

翻訳は機械翻訳により提供されています。提供された翻訳内容と英語版の間で齟齬、不一致または矛盾がある場合、英語版が優先します。

# AWS SDK for PHP バージョン 3 のコマンドオブジェクト
<a name="guide_commands"></a>

は [コマンドパターン](http://en.wikipedia.org/wiki/Command_pattern) AWS SDK for PHP を使用して、後で HTTP リクエストを転送するために使用されるパラメータとハンドラーをカプセル化します。

## コマンドの暗黙的な使用
<a name="implicit-use-of-commands"></a>

任意のクライアントクラスをテストすると、API オペレーションに対応するメソッドが実際には存在しないことを確認できます。これらは `__call()` マジックメソッドを使用して実装されます。これらの疑似メソッドは、実際は SDK でのコマンドオブジェクトの使用をカプセル化するショートカットです。

通常、コマンドオブジェクトを直接操作する必要はありません。`Aws\S3\S3Client::putObject()` のようなメソッドを呼び出すと、SDK は実際には指定されたパラメーターに基づいて `Aws\CommandInterface` オブジェクトを作成し、コマンドを実行して、データが入力されている `Aws\ResultInterface` オブジェクトを返します (またはエラーで例外がスローされます)。クライアントのいずれかの `Async` メソッド (例 :`Aws\S3\S3Client::putObjectAsync()`) を呼び出すときにも、同様の流れになります。クライアントは、指定されたパラメーターに基づいてコマンドを作成し、HTTP リクエストをシリアル化して、リクエストを開始し、promise を返します。

以下の例も機能的に同様です。

```
$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);
```

## コマンドのパラメーター
<a name="command-parameters"></a>

すべてのコマンドは、サービスの API の一部ではなく、SDK の動作を制御する特別なパラメータをいくつかサポートしてします。

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

このパラメータを使用すると、基になる HTTP ハンドラーがリクエストを実行する方法を微調整できます。`@http` パラメータに含めることができるオプションは、[「http」クライアントオプション](guide_configuration.md#config-http)を使用してそのクライアントをインスタンス化するときに設定できるオプションと同じです。

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

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

[「retries」クライアントオプション](guide_configuration.md#config-retries)と同様に、`@retries` は、コマンドが失敗したと見なされるまでに再試行できる回数を制御します。再試行を無効にするには、`0` に設定します。

```
// Disable retries
$command['@retries'] = 0;
```

**注記**  
クライアントで再試行を無効にしている場合は、そのクライアントに渡される個別のコマンドで再試行を選択的に有効にすることはできません。

## コマンドオブジェクトの作成
<a name="creating-command-objects"></a>

クライアントの `getCommand()` メソッドを使用してコマンドを作成することができます。HTTP リクエストは、すぐに実行または転送されず、クライアントの `execute()` メソッドに渡さたときにのみ実行されます。これにより、コマンドを実行する前にコマンドオブジェクトを変更する機会が得られます。

```
$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);
```

## コマンド
<a name="command-handlerlist"></a>

コマンドがクライアントから作成された場合、クライアントの `Aws\HandlerList` オブジェクトのクローンが与えられます。コマンドは、クライアントのハンドラーリストの**クローン**として与えられ、クライアントが実行する他のコマンドに影響しない、カスタムミドルウェアとハンドラーを使用するためにコマンドが許可されます。

つまり、(例 :`Aws\MockHandler`) コマンドごとに別の HTTP クライアントを使用し、ミドルウェアからコマンドごとのカスタム動作を追加できます。次の例では、`MockHandler` を使用して、実際の HTTP リクエストを送信する代わりに疑似の結果を作成します。

```
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'
```

コマンドを使用するハンドラーの変更に加えて、カスタムミドルウェアをコマンドに挿入することもできます。次の例では、ハンドラーリストでオブザーバーとして機能する `tap` ミドルウェアを使用します。

```
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>

`Aws\CommandPool` オブジェクトを生成するイテレーターを使用して、`Aws\CommandInterface` により、コマンドを同時に実行できます。`CommandPool` は、プール内のコマンドを繰り返し実行する (コマンドが完了時に、固定プールサイズを確保するために複数実行される) 間に、一定数のコマンドが同時に実行されるようにします。

ここでは、`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();
```

この例では `CommandPool` のごく一部の機能しか利用していません。より複雑な例を試してみましょう。例えば、ディスク上のファイルを Amazon S3 バケットにアップロードするとします。ディスクからファイルのリストを取得するには、PHP の `DirectoryIterator` を使用できます。このイテレーターにより `SplFileInfo` オブジェクトが生成されます。`CommandPool` は `Aws\CommandInterface` オブジェクトを生成するイテレーターを受け入れます。そのため、`SplFileInfo` オブジェクトにマッピングして `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"; });
```

### `CommandPool` の設定
<a name="commandpool-configuration"></a>

`Aws\CommandPool` コンストラクタはさまざまな設定オプションを受け入れます。

**concurrency (callable\$1int)**  
同時に実行するコマンドの最大数。プールを動的にサイズ変更する関数を提供します。この関数は、現在保留中のリクエスト数を取得し、新しいプールのサイズ制限を表す整数を返します。

**before (callable)**  
各コマンドを送信する前に呼び出す関数。この `before` 関数では、コマンドとコマンドのイテレーターのキーを受け付けます。コマンドを送信する前に、`before` 関数で、必要に応じてコマンドを変更できます。

**fulfilled (callable)**  
promise が実行されたときに呼び出す関数。この関数は、プールを省略する必要がある場合、解決または拒否できる集計 promise と結果の基になるイテレーターの ID、結果オブジェクトが提供されます。

**rejected (callable)**  
promise が拒否されたときに呼び出す関数。この関数は、プールを省略する必要がある場合、解決または拒否できる集計 promise と例外の基になるイテレーターの ID、`Aws\Exception` オブジェクトが提供されます。

### コマンド間の手動のガベージコレクション
<a name="manual-garbage-collection-between-commands"></a>

大きなコマンドプールでメモリ制限に達している場合、メモリ制限に達したときに [PHP ガベージコレクター](https://www.php.net/manual/en/features.gc.php)でまだ収集されていない SDK によって生成された巡回参照が原因である可能性があります。コマンド間で収集アルゴリズムを手動で呼び出すと、制限に達する前にサイクルを収集できます。次の例では、各コマンドを送信する前にコールバックを使用して収集アルゴリズムを呼び出す `CommandPool` を作成します。ガベージコレクターを呼び出してもパフォーマンスに影響することはなく、最適な使用はお客様のユースケースと環境によって異なることに注意してください。

```
$pool = new CommandPool($client, $commands, [
    'concurrency' => 25,
    'before' => function (CommandInterface $cmd, $iterKey) {
        gc_collect_cycles();
    }
]);
```