This library was created to experiment with zend expressive using React PHP and is based on React\Http. Mileage may vary.
A large portion of this code leverages existing libraries such as guzzlehttp's psr7 library, zend diactoros, zend expressive, zend stratigility and zend service manager.
- PHP 5.6+
$ composer install
This library alters the functionality of Zend\Expressive\Application slightly to allow for deferred processing from middleware. If a middleware application returns an instance of DeferredResponse the application will wait to emit until the promise has been resolved. DeferredResponse must be created with a React\Promise\Promise object.
Example:
function($request, $response) use ($eventLoop) {
// create a request, wait 1-5 seconds and then return a response.
$deferred = new Deferred();
$eventLoop->addTimer(rand(1, 5), function() use ($deferred){
echo 'Timer executed' . PHP_EOL;
$deferred->resolve(new Diactoros\Response\HtmlResponse('Deferred response.'));
});
return new \ExpressiveAsync\DeferredResponse($deferred->promise());
}
$serviceManager = new \Zend\ServiceManager\ServiceManager();
$eventLoop = Factory::create();
$socketServer = new SocketServer($eventLoop);
$httpServer = new Server($socketServer);
$serviceManager->setFactory('EventLoop',function() use ($eventLoop) { return $eventLoop; });
$serviceManager->setInvokableClass(
'Zend\Expressive\Router\RouterInterface',
'Zend\Expressive\Router\FastRouteRouter'
);
$router = new \Zend\Expressive\Router\FastRouteRouter();
// Example of a regular request
$router->addRoute(new \Zend\Expressive\Router\Route(
'/',
function($request, $response) use ($eventLoop) {
return new Diactoros\Response\HtmlResponse('Hello World.');
},
['GET'],
'home'
));
// Example of a deferred request
$router->addRoute(new \Zend\Expressive\Router\Route(
'/deferred',
function($request, $response) use ($eventLoop) {
// create a request, wait 1-5 seconds and then return a response.
$deferred = new Deferred();
$eventLoop->addTimer(rand(1, 5), function() use ($deferred){
echo 'Timer executed' . PHP_EOL;
$deferred->resolve(new Diactoros\Response\HtmlResponse('Deferred response.'));
});
return new \ExpressiveAsync\DeferredResponse($deferred->promise());
},
['GET'],
'deferred'
));
$application = new Application(
$router,
$serviceManager,
function($request, $response) {
echo 'final handler was called.' . PHP_EOL;
return new Diactoros\Response\HtmlResponse('Not Found.', 404);
}
);
$connectionHandler = new ExpressiveAsync\ExpressiveConnectionHandler($application);
$httpServer->on('request', $connectionHandler);
$socketServer->listen('10091');
$eventLoop->run();
The ExpressiveConnectionHandler emits several events during the lifecycle of a request.
Before the middleware application is executed this event will be emitted. The request and response objects are passed in by reference allowing for modification.
$connectionHandler = new ExpressiveAsync\ExpressiveConnectionHandler($application);
$connectionHandler->on(ExpressiveConnectionHandler::EVENT_REQUEST, function ($conn, &$request, $response) {
$request = $request->withAttribute('request-start', microtime(true))
});
Before the response is written to the connection but after the middleware has executed. The response object is passed by reference.
$connectionHandler->on('end', function($conn, $request, $response) use ($logger) {
$logger->timing('app.timing', (microtime(true) - $request->getAttribute('request-start')) * 1000);
});
Emitted once the connection has been ended.
Emitted once the connection close has been called.
An example server has been provided. To run simply execute the following in the terminal from the root directory.
$ php bin/server.php
Open your browser to http://127.0.0.1:10091
For additional information on how to get started see the zend-expressive github page.
Currently this example contains BufferedStream, which isn't using streams at all. The Response and Request objects created by zend and guzzle all use php://memory or php://temp, I am currently unsure as to the impacts this will have in an environment that we wish to stay non-blocking.