

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 para PHP versión 3
<a name="guide_commands"></a>

 AWS SDK para PHP Utiliza el [patrón de comandos](http://en.wikipedia.org/wiki/Command_pattern) para encapsular los parámetros y el controlador que se utilizarán para transferir una solicitud HTTP en un momento posterior.

## Uso implícito de comandos
<a name="implicit-use-of-commands"></a>

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' => 'amzn-s3-demo-bucket',
    '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
<a name="command-parameters"></a>

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`
<a name="http"></a>

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"](guide_configuration.md#config-http).

```
// Configures the command to be delayed by 500 milliseconds
$command['@http'] = [
    'delay' => 500,
];
```

### `@retries`
<a name="retries"></a>

Al igual que la [opción del cliente "retries"](guide_configuration.md#config-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
<a name="creating-command-objects"></a>

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`
<a name="command-handlerlist"></a>

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`
<a name="command-pool"></a>

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 = 'amzn-s3-demo-bucket';
$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 = '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 la `CommandPool`
<a name="commandpool-configuration"></a>

El constructor `Aws\CommandPool` acepta distintas opciones de configuración.

**concurrency (invocable\$1entero)**  
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 la `before` 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
<a name="manual-garbage-collection-between-commands"></a>

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 PHP](https://www.php.net/manual/en/features.gc.php) todavía no había recopilado cuando se alcanzó el límite de memoria. Si se invoca manualmente el algoritmo de recopilación entre los comandos, es posible que los ciclos se recopilen antes de alcanzar dicho límite. En el siguiente ejemplo, se crea un `CommandPool` 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();
    }
]);
```