Las traducciones son generadas a través de traducción automática. En caso de conflicto entre la traducción y la version original de inglés, prevalecerá la version en inglés.
Objetos de mando de la versión 3 AWS SDK for PHP
AWS SDK for PHP usa el patrón de comandos
Uso implícito de comandos
Si examina cualquier clase de cliente, verá que los métodos que corresponden a las operaciones de la API no existen en realidad. Se implementan mediante el método mágico __call()
. Estos pseudométodos son en realidad accesos directos que encapsulan el uso de objetos comando por parte del SDK.
Normalmente no tendrá que interactuar con objetos comando directamente. Cuando llama a métodos como Aws\S3\S3Client::putObject()
, el SDK en realidad crea un objeto Aws\CommandInterface
utilizando los parámetros proporcionados, ejecuta el comando y devuelve un objeto Aws\ResultInterface
con la información devuelta (o genera una excepción en caso de error). El flujo es similar cuando se llama a cualquiera de los métodos Async
de un cliente (por ejemplo, Aws\S3\S3Client::putObjectAsync()
): el cliente crea un comando basado en los parámetros proporcionados, serializa una solicitud HTTP, inicia la solicitud y devuelve una promesa.
Los siguientes ejemplos son funcionalmente equivalentes.
$s3Client = new Aws\S3\S3Client([ 'version' => '2006-03-01', 'region' => 'us-standard' ]); $params = [ 'Bucket' => 'foo', 'Key' => 'baz', 'Body' => 'bar' ]; // Using operation methods creates a command implicitly $result = $s3Client->putObject($params); // Using commands explicitly $command = $s3Client->getCommand('PutObject', $params); $result = $s3Client->execute($command);
Parámetros de comando
Todos los comandos admiten algunos parámetros especiales que no forman parte de una API del servicio, sino que controlan el comportamiento del SDK.
@http
Con este parámetro se puede ajustar la forma en que el controlador HTTP subyacente ejecuta la solicitud. Las opciones que puede incluir en el parámetro @http
son las mismas que puede establecer al crear instancias para el cliente con la opción de cliente "http".
// Configures the command to be delayed by 500 milliseconds $command['@http'] = [ 'delay' => 500, ];
@retries
Al igual que la opción del cliente "retries", @retries
controla cuántas veces un comando se pueden reintentar antes de que se considere que se ha producido un error. Si establece el valor 0
, se deshabilitan los reintentos.
// Disable retries $command['@retries'] = 0;
nota
Cuando se deshabilitan los reintentos en un cliente, no es posible habilitarlos de manera selectiva en los comandos individuales que se pasan a ese cliente.
Crear objetos comando
Puede crear un comando con el método getCommand()
de un cliente. No ejecuta ni transfiere inmediatamente una solicitud HTTP, solo se ejecuta cuando se especifica en el método execute()
del cliente. Esto le da la oportunidad de modificar el objeto comando antes de ejecutarlo.
$command = $s3Client->getCommand('ListObjects'); $command['MaxKeys'] = 50; $command['Prefix'] = 'foo/baz/'; $result = $s3Client->execute($command); // You can also modify parameters $command = $s3Client->getCommand('ListObjects', [ 'MaxKeys' => 50, 'Prefix' => 'foo/baz/', ]); $command['MaxKeys'] = 100; $result = $s3Client->execute($command);
Comando de HandlerList
Cuando se crea un comando desde un cliente, se le asigna un clon del objeto Aws\HandlerList
del cliente. Se asigna al comando un clon de la lista de controladores del cliente para permitirle usar middleware y controladores personalizados sin afectar a los demás comandos que ejecuta el cliente.
Esto significa que puede utilizar un cliente HTTP diferente para cada comando (por ejemplo, Aws\MockHandler
) y añadir un comportamiento personalizado para cada comando mediante middleware. En el ejemplo siguiente se usa MockHandler
para crear resultados simulados en lugar de enviar solicitudes HTTP reales.
use Aws\Result; use Aws\MockHandler; // Create a mock handler $mock = new MockHandler(); // Enqueue a mock result to the handler $mock->append(new Result(['foo' => 'bar'])); // Create a "ListObjects" command $command = $s3Client->getCommand('ListObjects'); // Associate the mock handler with the command $command->getHandlerList()->setHandler($mock); // Executing the command will use the mock handler, which returns the // mocked result object $result = $client->execute($command); echo $result['foo']; // Outputs 'bar'
Además de cambiar el controlador que usa el comando, también puede inyectarle middleware personalizado. En el ejemplo siguiente se usa el middleware tap
, que actúa como observador en la lista de controladores.
use Aws\CommandInterface; use Aws\Middleware; use Psr\Http\Message\RequestInterface; $command = $s3Client->getCommand('ListObjects'); $list = $command->getHandlerList(); // Create a middleware that just dumps the command and request that is // about to be sent $middleware = Middleware::tap( function (CommandInterface $command, RequestInterface $request) { var_dump($command->toArray()); var_dump($request); } ); // Append the middleware to the "sign" step of the handler list. The sign // step is the last step before transferring an HTTP request. $list->append('sign', $middleware); // Now transfer the command and see the var_dump data $s3Client->execute($command);
CommandPool
El objeto Aws\CommandPool
permite ejecutar comandos de forma simultánea mediante un iterador que proporciona objetos Aws\CommandInterface
. CommandPool
garantiza la ejecución simultánea de un número constante de comandos mientras se itera por los comandos del grupo (cuando se completen comandos, se ejecutan otros para asegurar el número constante).
El siguiente es un ejemplo muy sencillo de cómo enviar algunos comandos con CommandPool
.
use Aws\S3\S3Client; use Aws\CommandPool; // Create the client $client = new S3Client([ 'region' => 'us-standard', 'version' => '2006-03-01' ]); $bucket = 'example'; $commands = [ $client->getCommand('HeadObject', ['Bucket' => $bucket, 'Key' => 'a']), $client->getCommand('HeadObject', ['Bucket' => $bucket, 'Key' => 'b']), $client->getCommand('HeadObject', ['Bucket' => $bucket, 'Key' => 'c']) ]; $pool = new CommandPool($client, $commands); // Initiate the pool transfers $promise = $pool->promise(); // Force the pool to complete synchronously $promise->wait();
Este ejemplo no aprovecha bien CommandPool
. Probemos con uno algo más complejo. Supongamos que desea cargar archivos del disco en un bucket de Amazon S3. Para obtener una lista de archivos del disco, podemos usar DirectoryIterator
de PHP. Este iterador devuelve objetos SplFileInfo
. CommandPool
acepta un iterador que devuelve objetos Aws\CommandInterface
, por lo que asignamos los objetos SplFileInfo
para conseguir objetos Aws\CommandInterface
.
<?php require 'vendor/autoload.php'; use Aws\Exception\AwsException; use Aws\S3\S3Client; use Aws\CommandPool; use Aws\CommandInterface; use Aws\ResultInterface; use GuzzleHttp\Promise\PromiseInterface; // Create the client $client = new S3Client([ 'region' => 'us-standard', 'version' => '2006-03-01' ]); $fromDir = '/path/to/dir'; $toBucket = 'my-bucket'; // Create an iterator that yields files from a directory $files = new DirectoryIterator($fromDir); // Create a generator that converts the SplFileInfo objects into // Aws\CommandInterface objects. This generator accepts the iterator that // yields files and the name of the bucket to upload the files to. $commandGenerator = function (\Iterator $files, $bucket) use ($client) { foreach ($files as $file) { // Skip "." and ".." files if ($file->isDot()) { continue; } $filename = $file->getPath() . '/' . $file->getFilename(); // Yield a command that is executed by the pool yield $client->getCommand('PutObject', [ 'Bucket' => $bucket, 'Key' => $file->getBaseName(), 'Body' => fopen($filename, 'r') ]); } }; // Now create the generator using the files iterator $commands = $commandGenerator($files, $toBucket); // Create a pool and provide an optional array of configuration $pool = new CommandPool($client, $commands, [ // Only send 5 files at a time (this is set to 25 by default) 'concurrency' => 5, // Invoke this function before executing each command 'before' => function (CommandInterface $cmd, $iterKey) { echo "About to send {$iterKey}: " . print_r($cmd->toArray(), true) . "\n"; }, // Invoke this function for each successful transfer 'fulfilled' => function ( ResultInterface $result, $iterKey, PromiseInterface $aggregatePromise ) { echo "Completed {$iterKey}: {$result}\n"; }, // Invoke this function for each failed transfer 'rejected' => function ( AwsException $reason, $iterKey, PromiseInterface $aggregatePromise ) { echo "Failed {$iterKey}: {$reason}\n"; }, ]); // Initiate the pool transfers $promise = $pool->promise(); // Force the pool to complete synchronously $promise->wait(); // Or you can chain the calls off of the pool $promise->then(function() { echo "Done\n"; });
Configuración de CommandPool
El constructor Aws\CommandPool
acepta distintas opciones de configuración.
- concurrency (invocable|entero)
-
Número máximo de comandos que se ejecutan de forma simultánea. Especifique una función para cambiar el tamaño del grupo de forma dinámica. La función recibe el número actual de solicitudes pendientes y se espera que devuelva un número entero que representa el nuevo límite de tamaño del grupo.
- before (invocable)
-
Function que se invoca antes de enviar cada comando. La función
before
acepta el comando y la clave del iterador del comando. Puede cambiar el comando de labefore
como sea necesario antes de enviar el comando. - fulfilled (invocable)
-
Función que se invoca invocar cuando una promesa se ha cumplido. La función recibe el objeto resultado, el ID del iterador del que proviene el resultado y la promesa agregada que se puede resolver o rechazar si es necesario cerrar el grupo.
- rejected (invocable)
-
Función que se invoca invocar cuando una promesa se ha rechazado. La función recibe un objeto
Aws\Exception
, el ID del iterador del que proviene la excepción y la promesa agregada que se puede resolver o rechazar si es necesario cerrar el grupo.
Recopilación de elementos no utilizados manualmente entre comandos
Si se alcanza el límite de memoria al utilizar grupos de comandos de gran tamaño, puede deberse a las referencias cíclicas generadas por el SDK que el recolector de elementos no utilizados de PHPCommandPool
que invoca el algoritmo de recopilación mediante una devolución de llamada antes del envío de cada de parte. Tenga en cuenta que invocar el recolector de elementos no utilizados conlleva un costo de rendimiento y su uso óptimo dependerá de su caso de uso y su entorno.
$pool = new CommandPool($client, $commands, [ 'concurrency' => 25, 'before' => function (CommandInterface $cmd, $iterKey) { gc_collect_cycles(); } ]);