Asynchronous Method Call In PHP
You cannot execute a method asynchronously. But you could return the data to the client, close the connection, and execute your time consuming method once you disconnected.
This answer goes in details.
Another solution to execute php code asynchronously is forking a new process with pclose(popen()).
Or for a really advanced solution you could look into the threading module of PHP.
Running async function in php
Recent versions of pthreads support closures as members, making the code very simple:
<?php
class Background extends Thread {
public function __construct(callable $call, array $args = []) {
$this->call = $call;
$this->args = $args;
}
public function run() {
call_user_func_array($this->call, $this->args);
}
protected $call;
protected $args;
}
$background = new Background(function($greeting){
printf("%s\n", $greeting);
}, ["Hello World"]);
$background->start();
$background->join();
function named($greeting) {
printf("%s\n", $greeting);
}
$background = new Background("named", ["Goodbye World"]);
$background->start();
$background->join();
?>
However, this is horrible, it's hard to imagine any function that is so hungry that it requires a thread of it's own.
You have started down the right path with the thought that you should reuse the context and create a worker thread, pthreads has all of this built in.
More sensible code using built in classes looks more like:
<?php
class Background extends Threaded {
public function __construct(callable $call, array $args = []) {
$this->call = $call;
$this->args = $args;
}
public function run() {
call_user_func_array($this->call, $this->args);
}
protected $call;
protected $args;
}
$pool = new Pool(4);
$pool->submit(new Background(function($greeting){
printf("%s\n", $greeting);
}, ["Hello World"]));
$pool->shutdown();
?>
But this still doesn't deal with a return value. I'll assume that you want to retrieve the result of calls made using the Pool
, in that case the code looks more like:
<?php
class Background extends Threaded {
public function __construct(callable $call, array $args = []) {
$this->call = $call;
$this->args = $args;
}
public function run() {
$this->synchronized(function(){
$this->result = call_user_func_array
($this->call, $this->args);
$this->notify();
});
}
public function getResult() {
return $this->synchronized(function(){
while (!isset($this->result))
$this->wait();
return $this->result;
});
}
protected $call;
protected $args;
protected $result;
}
$pool = new Pool(4);
$call = new Background(function($greeting){
return sprintf("%s\n", $greeting);
}, ["Hello World"]);
$pool->submit($call);
echo $call->getResult();
$pool->shutdown();
?>
As you can see, a call to Background::getResult
will result in the calling context waiting until a result is available, this may or may not be desirable, but makes for a good example.
Multiple function calls asynchronously in PHP
First of all you can only have one loop running in an app.
Second you have to make the loop run: https://reactphp.org/event-loop/
You should create the app and then register all the services and events, start the loop and leave it running as a server.
$loop = React\EventLoop\Factory::create();
$server = stream_socket_server('tcp://127.0.0.1:8080');
stream_set_blocking($server, 0);
$loop->addReadStream($server, function ($server) use ($loop) {
[...]
});
$loop->addPeriodicTimer(5, function () {
[...]
});
$loop->run(); <---- you will not execute anything behind this point.
Why? https://github.com/reactphp/event-loop/blob/master/src/ExtLibeventLoop.php#L196
public function run()
{
$this->running = true;
while ($this->running) { <------------------------------
$this->futureTickQueue->tick();
$flags = EVLOOP_ONCE;
if (!$this->running || !$this->futureTickQueue->isEmpty()) {
$flags |= EVLOOP_NONBLOCK;
} elseif (!$this->streamEvents && !$this->timerEvents->count()) {
break;
}
event_base_loop($this->eventBase, $flags);
}
}
For the use you do of the loop I would recommend to use Guzzle Async: http://docs.guzzlephp.org/en/stable/faq.html
$finalResponse = [];
$promises = [];
$urls = ['www.google.es', 'www.github.com', 'www.bitbucket.org'];
foreach ($urls as $index => $url) {
$promise = $client->requestAsync('GET', $url);
$promise->then(function ($response) use ($index, &$finalResponse) {
$finalResponse[$index]=$response;
});
$promises[$index]=$promise;
}
foreach ($promises as $promise) {
$promise->wait();
}
return $finalResponse;
How to use php function asynchronously
You can't, php is not meant to work that way.
You can run a separate background process, which checks database for jobs to be done and does them. But that is not true async. It's just a background worker.
How to make asynchronous HTTP requests in PHP
The answer I'd previously accepted didn't work. It still waited for responses. This does work though, taken from How do I make an asynchronous GET request in PHP?
function post_without_wait($url, $params)
{
foreach ($params as $key => &$val) {
if (is_array($val)) $val = implode(',', $val);
$post_params[] = $key.'='.urlencode($val);
}
$post_string = implode('&', $post_params);
$parts=parse_url($url);
$fp = fsockopen($parts['host'],
isset($parts['port'])?$parts['port']:80,
$errno, $errstr, 30);
$out = "POST ".$parts['path']." HTTP/1.1\r\n";
$out.= "Host: ".$parts['host']."\r\n";
$out.= "Content-Type: application/x-www-form-urlencoded\r\n";
$out.= "Content-Length: ".strlen($post_string)."\r\n";
$out.= "Connection: Close\r\n\r\n";
if (isset($post_string)) $out.= $post_string;
fwrite($fp, $out);
fclose($fp);
}
Related Topics
Insert Current Date in Datetime Format MySQL
What Does Using a Single Pipe '|' in a Function Argument Do
How to Run a PHP Without a Web Server
How to Remove "Via" and Server Name When Sending Mails with PHP
Notice: Undefined Offset: 0 In
PHP Date() in Foreign Languages - E.G. Mar 25 Aoû 09
"PHP Fatal Error: Class 'Httprequest' Not Found"
How to Load CSS File in Codeigniter
How to Get All Class Names Inside a Particular Namespace
PHP Gd Use One Image to Mask Another Image, Including Transparency
Php: Settings Memory_Limits > 1024M Does Not Work
How to Insert an Array into a Single MySQL Prepared Statement W/ PHP and Pdo
PHP Return 500 Error But No Error Log