

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

# AWS SDK for PHP バージョン 3 でのハンドラーとミドルウェア
<a name="guide_handlers-and-middleware"></a>

AWS SDK for PHP を拡張するには、主なメカニズムとして**ハンドラー**と**ミドルウェア**を使用します。各 SDK クライアントクラスには、クライアントの `Aws\HandlerList` メソッドでアクセスできる独自の `getHandlerList()` インスタンスがあります。クライアントの `HandlerList` を取得して変更することによって、クライアントの動作を追加または削除できます。

## ハンドラー
<a name="handlers"></a>

ハンドラーは、コマンドおよびリクエストから結果への実際の変換を実行する関数です。ハンドラーは、通常、HTTP リクエストを送信します。ハンドラーをミドルウェアで構成して動作を補強できます。ハンドラー関数は、`Aws\CommandInterface` と `Psr\Http\Message\RequestInterface` を受け入れて、`Aws\ResultInterface` で満たすかまたは `Aws\Exception\AwsException` 理由で拒否する promise を返します。

次に示しているハンドラーは、呼び出しごとに同じ Mock 結果を返します。

```
use Aws\CommandInterface;
use Aws\Result;
use Psr\Http\Message\RequestInterface;
use GuzzleHttp\Promise;

$myHandler = function (CommandInterface $cmd, RequestInterface $request) {
    $result = new Result(['foo' => 'bar']);
    return Promise\promise_for($result);
};
```

クライアントのコンストラクタの `handler` オプションにこのハンドラーを指定することによって、SDK クライアントで使用できます。

```
// Set the handler of the client in the constructor
$s3 = new Aws\S3\S3Client([
    'region'  => 'us-east-1',
    'version' => '2006-03-01',
    'handler' => $myHandler
]);
```

クライアントを作成した後に、`setHandler` の `Aws\ClientInterface` メソッドを使用して、そのクライアントのハンドラーを変更することもできます。

```
// Set the handler of the client after it is constructed
$s3->getHandlerList()->setHandler($myHandler);
```

**注記**  
コンストラクトした後、マルチリージョンクライアントのハンドラーを変更するには、`Aws\MultiRegionClient` の `useCustomHandler` メソッドを使用します。  

```
$multiRegionClient->useCustomHandler($myHandler);
```

### Mock ハンドラー
<a name="mock-handler"></a>

SDK を使用するテストを記述する場合は `MockHandler` を使用することをお勧めします。`Aws\MockHandler` を使用して、模擬結果を返すか、または Mock 例外をスローできます。結果または例外をキューに追加すると、MockHandler は FIFO ルールに従ってそれをキューから削除します。

```
use Aws\Result;
use Aws\MockHandler;
use Aws\DynamoDb\DynamoDbClient;
use Aws\CommandInterface;
use Psr\Http\Message\RequestInterface;
use Aws\Exception\AwsException;

$mock = new MockHandler();

// Return a mocked result
$mock->append(new Result(['foo' => 'bar']));

// You can provide a function to invoke; here we throw a mock exception
$mock->append(function (CommandInterface $cmd, RequestInterface $req) {
    return new AwsException('Mock exception', $cmd);
});

// Create a client with the mock handler
$client = new DynamoDbClient([
    'region'  => 'us-west-2',
    'version' => 'latest',
    'handler' => $mock
]);

// Result object response will contain ['foo' => 'bar']
$result = $client->listTables();

// This will throw the exception that was enqueued
$client->listTables();
```

## ミドルウェア
<a name="middleware"></a>

ミドルウェアは、コマンドの転送動作を補強して「next」ハンドラーに委任する、特殊なタイプの高レベル関数です。ミドルウェア関数は `Aws\CommandInterface` と `Psr\Http\Message\RequestInterface` を受け入れて、`Aws\ResultInterface` で満たすかまたは `Aws\Exception\AwsException` 理由で拒否する promise を返します。

ミドルウェアは高次関数であり、ミドルウェアを通過したコマンド、リクエスト、または結果が変更されます。ミドルウェアは次のような形式です。

```
use Aws\CommandInterface;
use Psr\Http\Message\RequestInterface;

$middleware = function () {
    return function (callable $handler) use ($fn) {
        return function (
            CommandInterface $command,
            RequestInterface $request = null
        ) use ($handler, $fn) {
            // Do something before calling the next handler
            // ...
            $promise = $fn($command, $request);
            // Do something in the promise after calling the next handler
            // ...
            return $promise;
        };
    };
};
```

ミドルウェアは、実行する 1 つのコマンドと 1 つのリクエストオブジェクト (省略可能) を受け取ります。ミドルウェアは、リクエストおよびコマンドを補強するかそのままにするかを選択できます。ミドルウェアは、チェーン内の次のハンドラーを呼び出すか、または次のハンドラーを省略して promise を返すことを選択できます。次のハンドラーを呼び出すことによって作成された promise を、その promise の `then` メソッドを使用して、promise をミドルウェアのスタックに戻す前に最終結果またはエラーを変更するように補強できます。

### HandlerList
<a name="handlerlist"></a>

SDK では、コマンドの実行時に使用されるミドルウェアとハンドラーを管理するために `Aws\HandlerList` が使用されます。各 SDK クライアントには独自の `HandlerList` があり、その `HandlerList` のクローンが作成され、クライアントで作成された各コマンドに追加されます。ミドルウェアをクライアントの `HandlerList` に追加することによって、ミドルウェアとデフォルトハンドラーをアタッチして、クライアントで作成された各コマンドで使用されるようにできます。特定のコマンドで所有されている `HandlerList` を変更することによって、そのコマンドに対してミドルウェアを追加および削除できます。

`HandlerList` は、**ハンドラー**をラップするために使用されるミドルウェアのスタックを表します。ミドルウェアのリストとミドルウェアがハンドラーをラップする順序を管理しやすいように、`HandlerList` では、ミドルウェアスタックは次のように、コマンドの転送のライフサイクルの各部分を表す名前付きのステップに分かれています。

1.  `init` - デフォルトパラメーターを追加します

1.  `validate` - 必須パラメーターを検証します

1.  `build` - HTTP リクエストを送信用にシリアル化します

1.  `sign` - シリアル化した HTTP リクエストに署名します

1. <handler> (ステップではありませんが、実際の転送を実行します)

**初期化**  
このライフサイクルステップは、コマンドの初期化を表し、リクエストはまだシリアル化されていません。このステップは通常、コマンドにデフォルトパラメーターを追加するために使用されます。  
`init` および `appendInit` メソッドを使用して、`prependInit` ステップにミドルウェアを追加できます。ミドルウェアは、`appendInit` では `prepend` リストの末尾に追加され、`prependInit` では `prepend` リストの先頭に追加されます。  

```
use Aws\Middleware;

$middleware = Middleware::tap(function ($cmd, $req) {
    // Observe the step
});

// Append to the end of the step with a custom name
$client->getHandlerList()->appendInit($middleware, 'custom-name');
// Prepend to the beginning of the step
$client->getHandlerList()->prependInit($middleware, 'custom-name');
```

**validate**  
このライフサイクルステップは、コマンドの入力パラメーターを検証するために使用されます。  
`validate` および `appendValidate` メソッドを使用して、`prependValidate` ステップにミドルウェアを追加できます。ミドルウェアは、`appendValidate` では `validate` リストの末尾に追加され、`prependValidate` では `validate` リストの先頭に追加されます。  

```
use Aws\Middleware;

$middleware = Middleware::tap(function ($cmd, $req) {
    // Observe the step
});

// Append to the end of the step with a custom name
$client->getHandlerList()->appendValidate($middleware, 'custom-name');
// Prepend to the beginning of the step
$client->getHandlerList()->prependValidate($middleware, 'custom-name');
```

**ビルド**  
このライフサイクルステップは、実行するコマンドの HTTP リクエストをシリアル化するために使用されます。下流のライフサイクルイベントは、コマンドと PSR-7 HTTP リクエストを受け取ります。  
`build` および `appendBuild` メソッドを使用して、`prependBuild` ステップにミドルウェアを追加できます。ミドルウェアは、`appendBuild` では `build` リストの末尾に追加され、`prependBuild` では `build` リストの先頭に追加されます。  

```
use Aws\Middleware;

$middleware = Middleware::tap(function ($cmd, $req) {
    // Observe the step
});

// Append to the end of the step with a custom name
$client->getHandlerList()->appendBuild($middleware, 'custom-name');
// Prepend to the beginning of the step
$client->getHandlerList()->prependBuild($middleware, 'custom-name');
```

**sign**  
このライフサイクルステップは通常、送信前に HTTP リクエストに署名するために使用されます。通常は、署名エラーを避けるために、署名した後に HTTP リクエストを変更しないでください。  
このステップは、HTTP リクエストがハンドラーによって転送される前の、`HandlerList` での最後のステップです。  
`sign` および `appendSign` メソッドを使用して、`prependSign` ステップにミドルウェアを追加できます。ミドルウェアは、`appendSign` では `sign` リストの末尾に追加され、`prependSign` では `sign` リストの先頭に追加されます。  

```
use Aws\Middleware;

$middleware = Middleware::tap(function ($cmd, $req) {
    // Observe the step
});

// Append to the end of the step with a custom name
$client->getHandlerList()->appendSign($middleware, 'custom-name');
// Prepend to the beginning of the step
$client->getHandlerList()->prependSign($middleware, 'custom-name');
```

### 使用可能なミドルウェア
<a name="available-middleware"></a>

この SDK には、クライアントの動作を補強するため、またはクライアントまたはコマンドの実行を確認するために使用できるいくつかのミドルウェアが付属しています。

#### mapCommand
<a name="map-command"></a>

`Aws\Middleware::mapCommand` ミドルウェアは、コマンドが HTTP リクエストとしてシリアル化される前に、そのコマンドを変更する必要がある場合に便利です。たとえば、`mapCommand` を使用して、デフォルトパラメーターの検証または追加を実行できます。`mapCommand` 関数は、`Aws\CommandInterface` オブジェクトを受け入れて `Aws\CommandInterface` オブジェクトを返す呼び出し可能関数を受け入れます。

```
use Aws\Middleware;
use Aws\CommandInterface;

// Here we've omitted the require Bucket parameter. We'll add it in the
// custom middleware.
$command = $s3Client->getCommand('HeadObject', ['Key' => 'test']);

// Apply a custom middleware named "add-param" to the "init" lifecycle step
$command->getHandlerList()->appendInit(
    Middleware::mapCommand(function (CommandInterface $command) {
        $command['Bucket'] = 'amzn-s3-demo-bucket';
        // Be sure to return the command!
        return $command;
    }),
    'add-param'
);
```

#### mapRequest
<a name="map-request"></a>

`Aws\Middleware::mapRequest` ミドルウェアは、コマンドが HTTP リクエストとしてシリアル化された後、かつ送信される前に、リクエストを変更する必要がある場合に便利です。たとえば、このミドルウェアを使用して、リクエストにカスタム HTTP ヘッダーを追加できます。`mapRequest` 関数は、`Psr\Http\Message\RequestInterface` 引数を受け入れて `Psr\Http\Message\RequestInterface` オブジェクトを返す呼び出し可能関数を受け入れます。

```
use Aws\Middleware;
use Psr\Http\Message\RequestInterface;

// Create a command so that we can access the handler list
$command = $s3Client->getCommand('HeadObject', [
    'Key'    => 'test',
    'Bucket' => 'amzn-s3-demo-bucket'
]);

// Apply a custom middleware named "add-header" to the "build" lifecycle step
$command->getHandlerList()->appendBuild(
    Middleware::mapRequest(function (RequestInterface $request) {
        // Return a new request with the added header
        return $request->withHeader('X-Foo-Baz', 'Bar');
    }),
    'add-header'
);
```

これで、コマンドが実行されたときに、カスタムヘッダー付きで送信されるようになりました。

**重要**  
このミドルウェアは、`build` ステップの最後でハンドラーリストに追加されています。これは、リクエストが作成された後に、このミドルウェアが呼び出されるようにするためです。

#### mapResult
<a name="mapresult"></a>

`Aws\Middleware::mapResult` ミドルウェアは、コマンドの実行結果を変更する必要がある場合に便利です。`mapResult` 関数は、`Aws\ResultInterface` 引数を受け入れて `Aws\ResultInterface` オブジェクトを返す呼び出し可能関数を受け入れます。

```
use Aws\Middleware;
use Aws\ResultInterface;

$command = $s3Client->getCommand('HeadObject', [
    'Key'    => 'test',
    'Bucket' => 'amzn-s3-demo-bucket'
]);

$command->getHandlerList()->appendSign(
    Middleware::mapResult(function (ResultInterface $result) {
        // Add a custom value to the result
        $result['foo'] = 'bar';
        return $result;
    })
);
```

これで、コマンドが実行されたときに、返される結果に `foo` 属性が含まれるようになりました。

#### 履歴
<a name="history"></a>

`history` ミドルウェアは、SDK で、期待どおりのコマンドが実行され、期待どおりの HTTP リクエストが送信され、期待どおりの結果が受け取られたかどうかをテストする場合に便利です。これは、実質的には、ウェブブラウザの履歴と同じように動作するミドルウェアです。

```
use Aws\History;
use Aws\Middleware;

$ddb = new Aws\DynamoDb\DynamoDbClient([
    'version' => 'latest',
    'region'  => 'us-west-2'
]);

// Create a history container to store the history data
$history = new History();

// Add the history middleware that uses the history container
$ddb->getHandlerList()->appendSign(Middleware::history($history));
```

`Aws\History` 履歴コンテナには、デフォルトでは 10 個のエントリが保存され、それを越えるエントリは消去されます。このエントリ数は、保持するエントリ数をコンストラクタに渡すことによってカスタマイズできます。

```
// Create a history container that stores 20 entries
$history = new History(20);
```

history ミドルウェアに渡すリクエストの実行後に、履歴コンテナを調べることができます。

```
// The object is countable, returning the number of entries in the container
count($history);

// The object is iterable, yielding each entry in the container
foreach ($history as $entry) {
    // You can access the command that was executed
    var_dump($entry['command']);
    // The request that was serialized and sent
    var_dump($entry['request']);
    // The result that was received (if successful)
    var_dump($entry['result']);
    // The exception that was received (if a failure occurred)
    var_dump($entry['exception']);
}

// You can get the last Aws\CommandInterface that was executed. This method
// will throw an exception if no commands have been executed.
$command = $history->getLastCommand();

// You can get the last request that was serialized. This method will throw an exception
// if no requests have been serialized.
$request = $history->getLastRequest();

// You can get the last return value (an Aws\ResultInterface or Exception).
// The method will throw an exception if no value has been returned for the last
// executed operation (e.g., an async request has not completed).
$result = $history->getLastReturn();

// You can clear out the entries using clear
$history->clear();
```

#### tap
<a name="tap"></a>

`tap` ミドルウェアはオブザーバーとして使用されます。このミドルウェアを使用して、ミドルウェアのチェーンを通じてコマンドを送信するときに関数を呼び出すことができます。この `tap` 関数は、実行される `Aws\CommandInterface` および `Psr\Http\Message\RequestInterface` (省略可能) を受け入れる呼び出し可能関数を受け入れます。

```
use Aws\Middleware;

$s3 = new Aws\S3\S3Client([
    'region'  => 'us-east-1',
    'version' => '2006-03-01'
]);

$handlerList = $s3->getHandlerList();

// Create a tap middleware that observes the command at a specific step
$handlerList->appendInit(
    Middleware::tap(function (CommandInterface $cmd, RequestInterface $req = null) {
        echo 'About to send: ' . $cmd->getName() . "\n";
        if ($req) {
            echo 'HTTP method: ' . $request->getMethod() . "\n";
        }
    }
);
```

## カスタムハンドラーの作成
<a name="creating-custom-handlers"></a>

ハンドラーは、`Aws\CommandInterface` と `Psr\Http\Message\RequestInterface` を受け入れて、`GuzzleHttp\Promise\PromiseInterface` で満たすかまたは `Aws\ResultInterface` 理由で拒否する `Aws\Exception\AwsException` を返すだけの関数です。

SDK にはいくつかの `@http` オプションがありますが、以下のオプションの使用法を知る必要があるのはハンドラーだけです。
+  [connect\_timeout](guide_configuration.md#http-connect-timeout) 
+  [デバッグ](guide_configuration.md#http-debug) 
+  [decode\_content](guide_configuration.md#http-decode-content) (省略可能)
+  [delay](guide_configuration.md#http-delay) 
+  [progress](guide_configuration.md#http-progress) (省略可能)
+  [proxy](guide_configuration.md#http-proxy) 
+  [sink](guide_configuration.md#http-sink) 
+  [synchronous](guide_configuration.md#http-sync) (省略可能)
+  [stream](guide_configuration.md#http-stream) (省略可能)
+  [ タイムアウト](guide_configuration.md#http-timeout) 
+  [認証](guide_configuration.md#http-verify) 
+ http\_stats\_receiver (省略可能) - [stats](guide_configuration.md#config-stats) 設定パラメーターを使用してリクエストされた場合に、HTTP 転送の統計情報の連想配列を付けて呼び出すための関数。

このオプションが省略可能として指定されている場合を除いて、ハンドラーはこのオプションを処理できる必要があり、そうでない場合は拒否された promise を返す必要があります。

特定の `@http` オプションを処理することに加えて、ハンドラーは次の形式の `User-Agent` ヘッダーを追加する必要があります。ここで、「3.X」は `Aws\Sdk::VERSION` に置き換えることができ、「HandlerSpecificData/version ...」はハンドラー固有の User-Agent 文字列に置き換える必要があります。

 `User-Agent: aws-sdk-php/3.X HandlerSpecificData/version ...` 