guzzle/guzzle — pull request #466 by naderman (2013-11-11 19:45:57+00:00)
Title: [WIP] Asynchronous sendAsync() immediately returns FutureResponse with blocking receive() method

Work in Progress: Not mergable yet, lots of cleanup todo, docs missing so far.

The basic idea of this PR is to make it possible to send of requests, then continue with some work in PHP while the remote server is responding and to then process the response later in the script. This is made possible with new sendAsync() methods which return FutureResponse objects which contain a blocking receive method that waits for a response and returns it. The following snippet demonstrates the basic workflow:

// create $request as usual
$futureResponse = $request->sendAsync();
// do some complicated work that takes a while, aka napping
sleep(1);
$response = $futureResponse->receive();
// do something with the response
echo $response->getBody();

The current send() method to continues to work as is, it internally calls sendAsync() and then immediately calls receive() on the future response and only returns the actual response.

Alternatively we could have FutureResponse implement the same Response interface and implement all calls to block until the response is received and then return the result of corresponding Response method. Either manually or via a magic __call method. I haven't looked at how this would interact with custom Response classes yet. If we did this, we would not have to explicitly call sendAsync() but this new behaviour would simply be the default as all code using guzzle could remain the same and would automatically benefit from this behaviour.

The underlying change that made this possible is the split of perform() into performWrite() and performRead(). Consequently the CurlMultiInterface now requires a call to send() to be followed by a call to receive() to block until a response is received.

Please let me know if the overall concept of how I'm implementing this is acceptable. I've been trying to keep the interface as backward compatible as possible for now. send() on both the client and Request continue to work as they always have.