In This Article

How it works

When you run an Expressive application using Swoole, you will execute PHP from the command line interface, without using a web server.

This sounds a bit strange in PHP, though it will be familiar to Node.js developers; the execution model under Swoole is similar to that technology.

The HTTP server of Swoole is a PHP class that offers callbacks on a number of events, using the on(string $name, callable $action) method.

The request handler implemented in zend-expressive-swoole is a runner that enables the execution of an Expressive application inside the on('request') event of Swoole\Http\Server. This runner is implemented in the Zend\Expressive\Swoole\SwooleRequestHandlerRunner class.

The basic implementation acts similar to the following:

public function run() : void
{
    $this->swooleHttpServer->on('start', function ($server) {
        printf("Swoole is running at %s:%s\n", $server->host, $server->port);
    });

    $this->swooleHttpServer->on('request', function ($request, $response) {
        printf(
            "%s - %s - %s %s\n",
            date('Y-m-d H:i:sO', time()),
            $request->server['remote_addr'],
            $request->server['request_method'],
            $request->server['request_uri']
        );
        $emitter = new SwooleEmitter($response);
        try {
            $psr7Request = ($this->serverRequestFactory)($request);
        } catch (Throwable $e) {
            // Error in generating the request
            $this->emitMarshalServerRequestException($emitter, $e);
            return;
        }
        $emitter->emit($this->handler->handle($psr7Request));
    });

    $this->swooleHttpServer->start();
}

This package provides a bridge between Swoole\Http\Request ($request) and PSR-7 requests ($psr7Request; specifically as implemented by zend-diactoros) via the class Zend\Expressive\Swoole\ServerRequestSwooleFactory.

It also provides a Swoole-specific emitter, Zend\Expressive\Swoole\SwooleEmitter, that converts a PSR-7 response to a Swoole\Http\Response instance.

When you run an Expressive application using zend-expressive-swoole, you will notice a bunch of PHP processes running. By default, Swoole executes 4 worker (or reactor) processes and 1 master process, for a total of 5 PHP processes.

Swoole processes

The advantages of this architecture are many: it's very light and simple (just PHP processes running); it offers a service layer that is able to restart a worker automatically if it's not responding; and it allows executing multiple HTTP requests in parallel. The architecture is built for scaling.

Performance

The ZF developers performed a benchmark running the default zend-expressive-skeleton application with Swoole 4.0.1, nginx 1.12.1, and Apache 2.4.27 (with mod_php) using PHP 7.2.7.

The results demonstrated that Expressive with Swoole runs 4 to 5 times faster than nginx or Apache.

This impressive result is primarily due to the shared memory approach of Swoole. Unlike traditional apache/php-fpm usage, the memory allocated in Swoole will not be freed after a request. This allows application configuration and artifacts (such as middleware and handlers) to persist between requests and processes.

Under Swoole 4.1+, for even better performance, you can enable the option zend-expressive-swoole.enable_coroutine. When this is enabled, Swoole will run most I/O processes in coroutines. Doing so provides approximately 10 times faster performance than without coroutines, meaning a Swoole-based application can be 40 to 50 times faster than running under nginx or Apache. Performance improves with the number of workers (which are restricted by the amount of memory); as such, performance can increase from these numbers.

Found a mistake or want to contribute to the documentation? Edit this page on GitHub!