Edited at

Guzzleでの非同期リクエスト

More than 1 year has passed since last update.


環境

PHP5.6

Guzzle6.3

公式ドキュメント:

http://docs.guzzlephp.org/en/stable/index.html


guzzle インストール

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

composer require guzzlehttp/guzzle


簡易版非同期リクエスト

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したい場合の例は下記です。(フォーム送信したいデータがある・ヘッダ指定したいケース)

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


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

<?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で順次実行される時)までリクエストが実行されずメモリを消費しない

  • レスポンスの$indexで、どのリクエストのレスポンスか把握できる

参考:

https://speakerdeck.com/suzuki/guzzle-promisewoshi-tuta-fei-tong-qi-chu-li-niyoruapikorufalsegao-su-hua

https://mike-neko.github.io/blog/guzzle/