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 comando en la AWS SDK for PHP versión 3
AWS SDK for PHP Utiliza el patrón de comandos
Uso implícito de comandos
Si examina cualquier clase de cliente, verá que los métodos correspondientes a API las operaciones no existen realmente. Se implementan mediante el método mágico __call()
. Estos pseudométodos son en realidad atajos que encapsulan el uso que se hace SDK de los objetos de comando.
Normalmente no tendrá que interactuar con objetos comando directamente. Cuando llamas a métodos comoAws\S3\S3Client::putObject()
, en SDK realidad crea un Aws\CommandInterface
objeto en función de los parámetros proporcionados, ejecuta el comando y devuelve un Aws\ResultInterface
objeto rellenado (o lanza una excepción en caso de error). Un flujo similar ocurre cuando se llama a cualquiera de los Async
métodos de un cliente (por ejemplo,Aws\S3\S3Client::putObjectAsync()
): el cliente crea un comando en función de los parámetros proporcionados, serializa una HTTP solicitud, 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 del servicioAPI, sino que controlan su comportamientoSDK.
@http
Con este parámetro, es posible ajustar la forma en que el HTTP controlador 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 una HTTP solicitud de forma inmediata, sino que solo se ejecuta cuando se pasa al execute()
método 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 usar un HTTP cliente diferente por comando (por ejemploAws\MockHandler
) y agregar un comportamiento personalizado por comando a través del middleware. En el siguiente ejemplo, se utiliza MockHandler
a para crear resultados simulados en lugar de enviar HTTP solicitudes 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 PHP DirectoryIterator
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 = 'amzn-s3-demo-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 estás alcanzando el límite de memoria con grupos de comandos grandes, puede que se deba a las referencias cíclicas generadas por el recolector de basura que aún SDK no había recogido el recolector de PHP basuraCommandPool
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(); } ]);