Note: I'm migrating from gonzalo123.com to here. When I finish I'll swap the DNS to here. The "official" blog will be always gonzalo123.com

      How to run a Web Server from a PHP application

      Normally we deploy our PHP applications in a webserver (such as apache, nginx, …). I used to have one apache webserver in my personal computer to play with my applications, but from time to now I preffer to use PHP’s built-in webserver for my experiments. It’s really simple. Just run:

      php -S 0.0.0.0:8080 
      

      and we’ve got one PHP webserver at our current directory. With another languages (such as node.js, Python) we can start a Web Server from our application. For example with node.js:

      var http = require('http');
      http.createServer(function (req, res) {
        res.writeHead(200, {'Content-Type': 'text/plain'});
        res.end('Hello World\n');
      }).listen(8080, '0.0.0.0');
      console.log('Server running at http://0.0.0.0:8080');
      

      With PHP we cannot do it. Sure? That assertion isn’t really true. We can do it. I’ve just create one small library to do it in two different ways. First running the built-in web server and also running one React web server.

      I want to share the same interface to start the server. In this implementation we will register one callback to handle incomming requests. This callback will accept a Symfony\Component\HttpFoundation\Request and it will return a Symfony\Component\HttpFoundation\Response. Then we will start our server listening to one port and we will run our callback per Request (a simple implementeation of the reactor pattern)

      We will create a static factory to create the server

      namespace G\HttpServer;
      use React;
       
      class Builder
      {
          public static function createBuiltInServer($requestHandler)
          {
              $server = new BuiltInServer();
              $server->registerHandler($requestHandler);
       
              return $server;
          }
       
          public static function createReactServer($requestHandler)
          {
              $loop   = React\EventLoop\Factory::create();
              $socket = new React\Socket\Server($loop);
       
              $server = new ReactServer($loop, $socket);
              $server->registerHandler($requestHandler);
       
              return $server;
          }
      }
      

      Each server (BuiltIn, and React) has its own implementation.

      And basically that’s all. We can run a simple webserver with the built-in server

      use G\HttpServer\Builder;
      use Symfony\Component\HttpFoundation\Request;
       
      Builder::createBuiltInServer(function (Request $request) {
              return "Hello " . $request->get('name');
          })->listen(1337);
      

      Or the same thing but with React

      use G\HttpServer\Builder;
      use Symfony\Component\HttpFoundation\Request;
       
      Builder::createReactServer(function (Request $request) {
              return "Hello " . $request->get('name');
          })->listen(1337);
      

      As you can see our callback handles one Request and returns one Response (The typical HttpKernel), because of that we also can run one Silex application: With built-in:

      use G\HttpServer\Builder;
      use Symfony\Component\HttpFoundation\Request;
       
      $app = new Silex\Application();
       
      $app->get('/', function () {
              return 'Hello';
          });
       
      $app->get('/hello/{name}', function ($name) {
              return 'Hello ' . $name;
          });
       
      Builder::createBuiltInServer(function (Request $request) use ($app) {
              return $app->handle($request);
          })->listen(1337);
      

      And the same with React:

      use G\HttpServer\Builder;
      use Symfony\Component\HttpFoundation\Request;
       
      $app = new Silex\Application();
       
      $app->get('/', function () {
              return 'Hello';
          });
       
      $app->get('/hello/{name}', function ($name) {
              return 'Hello ' . $name;
          });
       
      Builder::createReactServer(function (Request $request) use ($app) {
              return $app->handle($request);
          })->listen(1337);
      

      As an exercise I also have created one small benchmark (with both implementations) with apache ab running 100 request with a 10 request at the same time. Here you can see the outcomes.

       builtinreact
      Simple response  
      ab -n 100 -c 10 http://localhost:1337/
      Time taken for tests0.878 seconds0.101 seconds
      Requests per second (mean)113.91 [#/sec]989.33 [#/sec]
      Time per request (mean)87.791 [ms]10.108 [ms]
      Time per request (mean across all concurrent requests)8.779 [ms]1.011 [ms]
      Transfer rate21.02 [Kbytes/sec]112.07 [Kbytes/sec]
      Silex application
      ab -n 100 -c 10 http://localhost:1337/
      Time taken for tests2.241 seconds0.247 seconds
      Requests per second (mean)44.62 [#/sec]405.29 [#/sec]
      Time per request224.119 [ms]24.674 [ms]
      Time per request (mean across all concurrent requests)22.412 [ms]2.467 [ms]
      Transfer rate10.89 [Kbytes/sec]75.60 [Kbytes/sec]
      ab -n 100 -c 10 http://localhost:1337/hello/gonzalo
      Time taken for tests2.183 seconds0.271 seconds
      Requests per second (mean)45.81 [#/sec] (mean)369.67 [#/sec]
      Time per request (mean)218.290 [ms] (mean)27.051 [ms]
      Time per request (mean across all concurrent requests)21.829 [ms]2.705 [ms]
      Transfer rate11.54 [Kbytes/sec]71.84 [Kbytes/sec]

      Built-in web server is not suitable for production environments, but React would be a useful tool in some cases (maybe not good for running Facebook but good enough for punctual situations).

      Library is available at github and also you can use it with composer

      comments powered by Disqus