Guzzleでの非同期リクエスト

# 環境

PHP5.6
Guzzle6.3

公式ドキュメント：
http://docs.guzzlephp.org/en/stable/index.html

# guzzle インストール
composerでインストールします。

```bash
composer require guzzlehttp/guzzle
```

# 簡易版非同期リクエスト

```php5
require_once(dirname(__FILE__) . '/vendor/autoload.php');
use GuzzleHttp\Client;

$client = new Client();
//$client = new \GuzzleHttp\Client(['cookies' => true]); //クッキーを利用したい場合
//$client = new \GuzzleHttp\Client(['debug' => true]); //通信内容をデバッグしたい場合

$promises[] = $client->requestAsync('GET', 'https://sample.com/1.html');
$promises[] = $client->requestAsync('GET', 'https://sample.com/2.html');
$promises[] = $client->requestAsync('GET', 'https://sample.com/3.html');
$promises[] = $client->requestAsync('GET', 'https://sample.com/4.html');
$promises[] = $client->requestAsync('GET', 'https://sample.com/5.html');

$responses = \GuzzleHttp\Promise\all($promises)->wait();

$result = [];
foreach ($responses as $response) {
    $result[] = [
      'html'             => $response->getBody()->getContents(),
      'status_code'      => $response->getStatusCode(), //ステータスコード
      'reason_phrase'    => $response->getReasonPhrase(), //
      'protocol_version' => $response->getProtocolVersion(),
      'response_header'  => $response->getHeaders()
    ];
}

var_dump($result);
```

- 5リクエストを非同期リクエストします
- 非同期なので、$resultに入ってくるレスポンスは順不同
- 非同期でPOSTしたい場合の例は下記です。（フォーム送信したいデータがある・ヘッダ指定したいケース）

```php5
$config = [
  //ヘッダ指定
  'headers' => [
      'Accept' => 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8',
      'Accept-Encoding' => 'gzip, deflate, br',
      'Accept-Language' => 'ja,en-US;q=0.9,en;q=0.8',
      'Cache-Control' => 'max-age=0',
      'Connection' => 'keep-alive',
      'Host' => 'sample.com',
      'Upgrade-Insecure-Requests' => 1,
      'User-Agent' => 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.186 Safari/537.36'
  ],
  //パラメータ指定
  'form_params' => [
    'email' => 'test@sample.com',
    'name'  => 'test'
  ]
];

$promises[] = $client->requestAsync('POST', 'https://sample.com/aaa.html', $config);
$response = \GuzzleHttp\Promise\all($promises)->wait();
```

# メモリ節約版非同期リクエスト

```php5
<?php
    require_once(dirname(__FILE__) . '/vendor/autoload.php');
    
    use GuzzleHttp\Pool;
    use GuzzleHttp\Client;
    use GuzzleHttp\Psr7\Request;
    
    $client = new Client();
    
    $urlList = [
      'https://sample.com/1.html',
      'https://sample.com/2.html',
      'https://sample.com/3.html',
      'https://sample.com/4.html',
      'https://sample.com/5.html',
      'https://sample.com/6.html',
      'https://sample.com/7.html',
      'https://sample.com/8.html',
      'https://sample.com/9.html',
      'https://sample.com/10.html'
    ];

    $requests = function ($urlList) use ($client) {
        foreach ($urlList as $url) {
            yield function() use ($client, $url) {
                return $client->requestAsync('GET', $url);
            };
        }
    };
    
    $contents = [];

    $pool = new Pool($client, $requests($urlList), [
        'concurrency' => 10,
        'fulfilled' => function ($response, $index) use ($urlList, &$contents) {
            $contents[$urlList[$index]] = [
              'html'             => $response->getBody()->getContents(),
              'status_code'      => $response->getStatusCode(),
              'response_header'  => $response->getHeaders()
            ];
        },
        'rejected' => function ($reason, $index) use ($urlList, &$contents) {
            // this is delivered each failed request
            $contents[$urlList[$index]] = [
              'html'   => '',
              'reason' => $reason
            ];
        },
    ]);
    
    $promise = $pool->promise();
    $promise->wait();
    
    var_dump($contents);
```


- 簡易版で大量に非同期リクエストした場合、promiseオブジェクトにリクエスト数分状態を保持してしまうのでメモリオーバーする事がある
- ジェネレータを使うと実際に必要になる（Poolで順次実行される時）までリクエストが実行されずメモリを消費しない

参考：
https://speakerdeck.com/suzuki/guzzle-promisewoshi-tuta-fei-tong-qi-chu-li-niyoruapikorufalsegao-su-hua
https://mike-neko.github.io/blog/guzzle/