PHP中是否有一种方法可以使HTTP调用不等待响应?我不关心响应,我只想做一些类似file_get_contents()的事情,但不等待请求完成后再执行其余的代码。这对于在我的应用程序中触发某种“事件”或触发长进程非常有用。
什么好主意吗?
PHP中是否有一种方法可以使HTTP调用不等待响应?我不关心响应,我只想做一些类似file_get_contents()的事情,但不等待请求完成后再执行其余的代码。这对于在我的应用程序中触发某种“事件”或触发长进程非常有用。
什么好主意吗?
当前回答
/**
* Asynchronously execute/include a PHP file. Does not record the output of the file anywhere.
*
* @param string $filename file to execute, relative to calling script
* @param string $options (optional) arguments to pass to file via the command line
*/
function asyncInclude($filename, $options = '') {
exec("/path/to/php -f {$filename} {$options} >> /dev/null &");
}
其他回答
Symfony HttpClient是异步的https://symfony.com/doc/current/components/http_client.html。
例如,你可以
use Symfony\Component\HttpClient\HttpClient;
$client = HttpClient::create();
$response1 = $client->request('GET', 'https://website1');
$response2 = $client->request('GET', 'https://website1');
$response3 = $client->request('GET', 'https://website1');
//these 3 calls with return immediately
//but the requests will fire to the website1 webserver
$response1->getContent(); //this will block until content is fetched
$response2->getContent(); //same
$response3->getContent(); //same
您可以使用exec()来调用一些可以执行HTTP请求的东西,如wget,但必须将程序的所有输出指向某个地方,如文件或/dev/null,否则PHP进程将等待该输出。
如果你想把进程和apache线程完全分开,可以尝试这样做(我不确定,但我希望你能明白):
exec('bash -c "wget -O (url goes here) > /dev/null 2>&1 &"');
这不是一项很好的业务,您可能需要类似cron作业的东西来调用heartbeat脚本,该脚本轮询实际的数据库事件队列来执行真正的异步事件。
/**
* Asynchronously execute/include a PHP file. Does not record the output of the file anywhere.
*
* @param string $filename file to execute, relative to calling script
* @param string $options (optional) arguments to pass to file via the command line
*/
function asyncInclude($filename, $options = '') {
exec("/path/to/php -f {$filename} {$options} >> /dev/null &");
}
您可以使用这个库:https://github.com/stil/curl-easy
这很简单:
<?php
$request = new cURL\Request('http://yahoo.com/');
$request->getOptions()->set(CURLOPT_RETURNTRANSFER, true);
// Specify function to be called when your request is complete
$request->addListener('complete', function (cURL\Event $event) {
$response = $event->response;
$httpCode = $response->getInfo(CURLINFO_HTTP_CODE);
$html = $response->getContent();
echo "\nDone.\n";
});
// Loop below will run as long as request is processed
$timeStart = microtime(true);
while ($request->socketPerform()) {
printf("Running time: %dms \r", (microtime(true) - $timeStart)*1000);
// Here you can do anything else, while your request is in progress
}
下面你可以看到上面例子的控制台输出。 它将显示简单的实时时钟,指示请求正在运行的时间:
我发现这个软件包非常有用,非常简单:https://github.com/amphp/parallel-functions
<?php
use function Amp\ParallelFunctions\parallelMap;
use function Amp\Promise\wait;
$responses = wait(parallelMap([
'https://google.com/',
'https://github.com/',
'https://stackoverflow.com/',
], function ($url) {
return file_get_contents($url);
}));
它将并行加载所有3个url。 您还可以在闭包中使用类实例方法。
例如,我使用Laravel扩展基于这个包https://github.com/spatie/laravel-collection-macros#parallelmap
这是我的代码:
/**
* Get domains with all needed data
*/
protected function getDomainsWithdata(): Collection
{
return $this->opensrs->getDomains()->parallelMap(function ($domain) {
$contact = $this->opensrs->getDomainContact($domain);
$contact['domain'] = $domain;
return $contact;
}, 10);
}
它在10个并行线程中加载所有需要的数据,而不是在没有异步的情况下50秒,它在8秒内完成。