 All right. Good morning, everybody. I hope you all enjoyed the keynote very much or took the opportunity for a longer breakfast. But I hope you went to the keynote. Always good to get you started, fresh and bright and early. So this presentation on the schedule is called Something About the Future. And I decided that I didn't like that title. So I'm calling it your next web server will be written in PHP, which is, of course, a bold statement. So maybe we should turn down a bit and say, it might possibly be written in PHP, maybe not now, maybe in a few years, depending on whether or not you like what I'm telling you. And the important thing about this presentation, I think, is that it's a bit more about what could be than what is. It's more a glimpse into the future, like the original talk title says. And I'm hoping that I can inspire you a little bit to play around with the technologies that I'm about to show and start thinking about the world of web servers in that context and not in the old ways, which I'm going to be taking quite some time of exploring. My name is David. I work. I'm from Germany. I hope that's OK. I was allowed in the country still. It's going to change at some point. So and I work for Heroku, where our platform as a service, we're part of Salesforce, so about all the nonsense I talk about, please don't make investment decisions based on it. You can email me in private criticism if you don't like this talk. If you like this talk, you can praise me publicly on Twitter. Or not, I can't really, like, my phone's here, but I'm not going to take a look at it. What's happened? OK, that's still my Twitter nickname. And I want to talk about, I'll take this opportunity for some water, I want to talk about CGI first. Who's old enough? OK, that's a few people. OK, good. For the younger ones, the uninitiated here. CGI was invented by a few people at the NCSA, the National Center for Supercomputing Applications. And they mostly worked on supercomputers, but also on the worldwide web, right? Because that field, like academia and the military and government organizations, is where the worldwide web was born. And they had a requirement, because Tim Berners-Lee walked on stage and said, hey, not on a literal stage, and said, hey, I have invented this worldwide web thing with an HTML, and everybody thought that was great for sharing information, for publishing papers, et cetera. But at some point, people wanted to do something interactive. And maybe it was a lunch order form. Somebody said, we need a way to run a script. So they put a spec on. And then a few people tried to pour that into an RFC, which, considering how simple the protocol is, took an amazing seven years. And in the meantime, all of the early worldwide web flourished on the possibility of CGI, right? Because people said, man, finally, we have the ability to run code dynamically. And that could be a C program, it could be something really stable. It could be something maybe. And I think this is from 1998 or 2009, because it's Netscape communicator, right? So for those of you who have never used this, this was just internet explorer, but way before. So it was the earliest Firefox ever. And people said, man, all this amazing technology and all the visionaries who were to later build PayPal and Amazon, they were like, eh, I have other things to do. So people with too much time on their hands and a vision for what's possible with CGI at that moment took it and built counters. So when you had a website on Geocities, when you had a website on Geocities with a lot of under construction banners and they were animated GIFs, then you would have a Perl script. And you could choose, you could pay for a counter, right? It's a Perl script on somebody else's server. And that would show all the visitors to your meaningless website that can't be found because there's no Google yet, that for the last two years, there's been eight visitors, right? So that's what they look like. And they were super, super popular because what they did is they got the request in some sort of database and usually was just a flat file, incremented the number, and returned a graphic like this. And you could pick amazing fonts for it, even Comic Sans. Eventually, people were like, oh, this is not enterprise enough, so we need a Java applet. And then the page would take like literally two minutes to load and is like everything's gray and says applet started and then the Java logo. It used to be a bean that jumped around on screen. So that was really terrible, but the underlying technology was clever, right? Because you needed a way to submit a form and process the form submission on the server side and do something dynamic with that. So CGI works by the web server getting the request from the client. And then it takes all the information from the request headers. It takes the protocol. It takes the host name. It takes the port and everything else. And it puts that into environment variables and then it calls a script, right? So the environment variables are like path info and request method and stuff. And then the script is run and that could be bash. That could be PHP, was one of the earliest examples, because PHP started out as a bunch of convenient template functions for C, right? So you could write C programs, but with more convenient templates, that was version one. And then eventually, later, it turned into a full script engine where you could do PHP, hello world dot PHP. And then that script is responsible for echoing the status if it wants to, then a bunch of header lines, an empty blank line, and then that's the response body. And that's how that works. Now, obviously, the problem is that if you invoke an external process every time somebody clicks form submission and the server has to do all this overhead, right? Like imagine writing the form data maybe to a text file takes 10 milliseconds. But the overhead of invoking whatever scripting engine is there, et cetera, Perl and these things, that took much, much, much longer, orders of magnitude longer than the actual script. And the result was that the web in these early days was slow, right? The counters took forever to load. And that was just not just because you were in modems, which are like, when they connected, and you'd like the younger people. You just know DSL and cable. But it was frustrating and slow, right? But it was simple. It's so simple that you can actually write a web application in Bash if you want to, right? Because all you have to tell Apache or something is, you know, when somebody calls hello.sh in CGI bin with a prefix, then run the script. And obviously, you know, you could probably inject about a bunch of stuff in. It's not really that smart to just call programs on the server. But these mechanics are still the same that we use today, right? So all the variables from the early spec are still around today. It's like there's this overarching what server is even on the other side talking to me in the script. And then for each request, a lot of information is extracted. This is just a subset, such as what port it is, what the request method was, et cetera. And then, obviously, all the arbitrary headers that a request could send. And there is an interesting artifact here, or several interesting artifacts, in this list that still affects us today when we write PHP scripts. So one is, there is no request URI or anything like this. That's an invention, just a quasi-standard from Nginx and Apache, et cetera. Because back then, nobody imagined that you want a different URL for your script. It was great to have CGI bin slash cart.pl in your URL. That meant you were doing cutting edge stuff. Nowadays, we don't want that anymore. And the other thing is, this was before HTTP 1.1. So there's just a server name. My laser is, OK, you can't see my laser, server name. That's static, because why would you have more than one domain name? And another thing is that, for whatever reason, they defined content type and content length with both headers as not to have the HTTP underscore prefix. So user agent and accept and whatever you send, including host, because that came after the HTTP 1.0 and CGI standards, has the prefix of these two done. So PHP was built originally to run as a CGI script. And then the trick becomes, and that's what path translated, et cetera, for is, with PHP, what you're actually invoking is the PHP binary. And then that gets passed additional information on what script to run. That's why configuration of CGI is such a nightmare, even today, in Apache, for instance. But the principle was, the engine starts and does something. So that's called an SAPI, the server API that PHP has. And you can think of an offer called SAPI. Who knows what this is? Ah, cool, excellent. OK, so you're learning some PHP internals. So the SAPI is a module in the engine, and there can only be one active at the same time, but you can compile several. That is the gateway into the execution of the script from outside. The one you're all familiar with is the CLI SAPI, which comes up when you type PHP, right? PHPFPM is another one. PHPCGI is another one. Then there is ModPHP, which maybe some of you know. This is an older way of running inside Apache, and we're going to be looking at the pros and cons of that. But the function of that code sometimes is more complex. In the case of FPM, it manages processes. In the case of CGI, it's just responsible for, you know, taking a bunch of variables and populating underscore get, et cetera. So it marshals input and output from and to the interface it's interacting with. And on the command line, for instance, that means whatever arguments I give PHP, hello.php, space, foo, bar, baz, ends up in the arc VRA, et cetera. So in a very simple way, it populates serve at end. So end gets environment variables from the processes context, and server gets often additional information, such as from what Apache version, gateway interface, request URI, et cetera. Then it takes the query string CGI variable and parses that into dollar underscore get. So we don't all have to do it manually, right? And when a user submitted a form on a website with a post and that has fields, then the content type of the request body is gonna be x dub dub form URL encoded, and it also decodes that into dollar underscore post. And if it's multi-part form data, it puts the uploader files into dollar underscore files. And then when I echo content or when I call header, and that includes set cookie, because set cookie is just a wrap around, I'm setting an HTTP header, then it returns that and echoes everything out, right? So I can set a bunch of headers, PHP remembers those, and once I echo something, it flushes the headers line by line, sends a blank line, and then the hello world I echo gets sent back, Apache picks that up and sends it to the browser, and then back in 1999, I have an interactive PHP website. So PHP was built around this, right? So this dollar underscore gets the fact that you access the request context through dollar underscore server. That's all because it's the world of the dynamic web started with CGI. So all SARPs that come after it, FPM, et cetera, which don't necessarily have to do some of these things, still replicate this, otherwise your code is not portable, right? It would be ridiculous. I mean, you can do that. You can, if you have code that uses Apache specific functions from mod PHP, it's not gonna run on the FPM, but those are very few and very rare exceptions around buffering and output flushing, but mostly if you write code, it works both in engine X and Apache as a module and as a fast CGI server, right? So that's great. But the whole execution model is of PHP is A, as a consequence of what was possible with CGI and B, because it makes life simple, modeled around statelessness, right? You always start with a blank slate. When your script starts at the top, there is no variables that are still left hanging. You don't have to worry about open transactions in the database unless you use persistent connections and something's wrong. But in principle, you just do whatever. You allocate memory, which you don't directly do, but you just waste memory on generating stuff and creating arrays, et cetera. And when your script ends, all of that is gone and the engine takes care of removing all this, right? That means it's a very simple programming model. It's not like a Java enterprise edition application where you're constantly fighting memory leaks or something, right? And you have to worry about transactions that get taken across pages. That's what servlets are. So the principle is, and this is gonna be very small for most of you to read, so I'm just gonna read it out. So PHP, when it runs the CGI interface, first, the PHP core logic starts up. It loads this list of extensions. It loads its basic configuration. The next thing is, once it's loaded, the extension modules into memory, like the .so or .dll files, PHP goes into a stage called the mInit, the module init phase. That's where, for instance, something like the old MySQL extension would create maybe a new instance of LibMySQL bindings, et cetera, underneath, right? Extensions initialize themselves, and that includes a potential server interface. So the mod PHP at this stage makes the connection to the Apache APIs to handle requests. Then this SAPI is gonna be ready because it's a module, and then every time a request comes in, and for CGI, that means PHP starts, serves the request, and shuts down, right? So it happens only once. You have the so-called our init phase. So that's when an extension in the engine can do startup logic. And the best example is the session extension. If you have session auto start enabled, it will automatically use your session handler to fetch the session data based on the info from the request and populate dollar underscore session for you. So you don't have to call session start. And then your script runs, right? Then the zent engine takes your PHP code and compiles it to bytecode, maybe caches the bytecode if you have opcache enabled, and executes the code. And when that's done, there's a phase called our shutdown so extensions can free whatever things they have allocated, let's say a database connection, right? If you use PDO, it would close database handles for you at this stage. And then the engine cleans up after you. So any variables, any constants you have to find, any classes, everything gets wiped clean. And if this wasn't CGI, it would be ready at step three, ready to handle the next request. And then eventually M shutdown, you can unload the extensions, et cetera, and do some cleanup work on the extension level. So all we really care about is number five, right? Our script runs. But as you can probably see, that's a lot of steps. And in particular, like initializing all the modules, starting up the extensions, et cetera, that's heavy, right? This happens on each request, and that's too slow, that's not efficient, that my German, my inner German is revolting. So people said, oh, we can fix that, let's use more PHP. So what more PHP does is it loads PHP, it embeds PHP's runtime and interprets and everything into Apache, right? Because Apache needs to run anyway to handle your PHP connections, sorry, HTTP connections. So why not load PHP into that, because then it only has to start once, right? Then we don't have the overhead of Apache seeing, oh, that's a static file, oh, that's an image, oh, that's a CGI bin, so I need to start PHP now. That's useless extra legwork on each request, so fix it. So the fixing is you enable mod PHP in Apache, you have to compile PHP so that it links against the right Apache APIs, and then you can load PHP as a module into Apache. And boom, you get A, better performance, and B, a few useless functions around header handling, which you should never use because otherwise your code will break with Nginx. So here we start at phase three that we had earlier. The SAPI is ready for the request that's waiting, right? Then we call our init again, and then the script executes, and our shutdown, and the engine cleans up after us. And that's a lot faster. That already cuts down massive, massive amounts of time because PHP doesn't have the startup, it doesn't have to load its configuration files. Everything's already in memory, all the extensions are already in memory, all the extensions have already allocated the basic functionalities they need, and the operating system doesn't have to start a new process, right? Like, invoking a process on the operating system side is also expensive because everything that's going on an operating system, right? That's why they're complicated. But the problem is, if you use more PHP, now PHP is in each HTTP DE process, right? All you want to do is serve one sign-up form for a conference, and suddenly, even when people are accessing your funny catgifts or the robots.txt, PHP gets loaded, right? And that's not ideal. So maybe we could use a different way of running Apache. Remember, this is before engine X was even like somebody's dream or vision. Does anybody remember LightT, LightTTPT? That was a web server that's no longer relevant. That was basically the engine X before engine X was a thing. So, but let's focus on Apache. This is like years ago when only Apache was a thing, right? And Internet Information Server, which we're not going to mention here. So the process models that you could use back then in Apache were two possible ones. Because the thing is, you have a process that accepts an HTTP request, right? And then does something based on it and returns a response. But what if you have two people accessing your site at the same time? You need more than one process, right? You need some sort of concurrency on the web server level. Concurrency could mean threading or concurrency could mean you start a bunch of processes. And that's what MPM Prefork does in Apache, right? So Apache starts and creates, let's say, 500 worker processes and each of them can handle a connection from a browser, from a client, right? From a user. So Prefork is great because each process is isolated, which is great for PHP, because PHP doesn't really do that well with threading. Alternatively, you can also run Apache in a threaded mode. So instead of running processes that run threads, which is more efficient and gives you higher performance and more importantly, less memory consumption, the problem is that you then need a thread safe PHP. So that's the, when you look at your extension directory, no-debug-non-zts-20121212, right? That's the extension directory for PHP 5.5, no debug build and not with ZenThreadSafety enabled. And these different extension directories in PHP exist because an extension that's built against the PHP with ZenThreadSafety doesn't work with one without and vice versa, right? And an extension built against the PHP with debug doesn't work without. So if you want a threadable PHP with debug symbols because something is broken, then your extension directory would be called debug-zts- whatever API version. So the problem is that crashes a lot. A, all the PHP extensions, often many PHP extensions have problems with threading. The Zen engine used to have problems with threading but not much anymore. So the PHP engine itself is pretty solid also because on Windows, with internet information server, and the so-called IS API, threading was the only model you could run, right? So historically, PHP has been decent at threading but the problem is like if you're an MPM worker, it's probably not even PHP that crashes, it's Apache because Apache's own modules were not thread safe. So it was a huge mess, right? So a couple of years ago with Apache 2.4 and before that as an optional module, Apache introduced something called MPM event. So that's an event loop where it handles connections and it handles requests. And it still spawns some amount of sub-processes but it's essentially a hybrid model of work and events. You can think of that as the same as Nginx, right? So if you just serve static files with Apache and you have MPM event running, then you get almost the same performance as Nginx. Nginx is still a little bit faster but the problem is Nginx is not as configurable and modular and extensible as Apache at runtime, right? So it's a trade-off, what do you want? Do you care about performance or do you care about a working.htx for your code? The problem with that is that it's an event loop, it's just doing stuff in a loop and with non-blocking IO keeping a lot of connections open and multiplexing requests. So embedding PHP in that even if it were thread safe is absolutely not an option at all. So what do we do now? I don't know. Let's just use Nginx, right? That's the solution to everything or was for a while. But the problem is so with Nginx you need fast CGI, right? So fast CGI is like CGI but it works over a socket. So either a TCP connection or a UNIX domain socket and the server process, so that could be PHP but that could also be a C program you write remains running, right? And it accepts a connection from the fast CGI client which is the web server. And then it says, all right, you want slash foobar and I give you a bunch of headers and here's my response and then next request and next request and next request. And that's great because that means PHP or whatever is a separate process from the web server so you can scale them independently, right? Which is nice because now Apache doesn't have PHP in memory anymore. And on the PHP or something application side all you care about is handling requests and you don't have to worry about being enabled being embedded in some sort of threaded environment. So the first solution for that was the FCGI SAPI, the old one. That's not, people still use that with a system called suexec et cetera in mass hosting because you can really basically jail each PHP process to a specific user and their permissions but since virtual hosting is rapidly falling out of popularity, most custom or, you know, for non-off-the-shelf software setups use FPM. So who has heard of PHP FPM? A lot of people, that's good. Okay, so a lot of you probably run PHP FPM without knowing it or somebody runs it for you without you knowing it, so go thank them. And what FPM does is instead of, so with FCGI, you run PHP FCGI and what that does is it runs a fast CGI server for one connection, right? And then it's the web server, so Apache or Engine X's responsibility to scale up and down the number of these processes. The problem with that is that Apache or Engine X know absolutely nothing about how many processes are reasonable to spawn. What's the current memory load? Is there any sort of corruption in your PHP? Do you maybe want to restart every 1000 requests because your doctrine version has a memory leak in combination with that Oracle PDO adapter you're using, right, this sort of stuff. So that's what PHP FPM solves. It runs a supervisor that spawns child processes and they run your code, right? And again, they launch once and then they just go through a loop of handling requests. So they always start at R in it. No overhead for extension loading, et cetera. And the great thing is that PHP FPM has a bunch of, so first of all is really, really, really rock solid. Second, it has a bunch of really cool features. For instance, what many of you maybe don't know, FPM has a feature called the slow log. So you can say any time a script that you wrote or the application that you wrote takes more than one second, for instance, right, automatically dump a backtrace. And suddenly your logs will be full of, oh, it's hanging on some sort of SQL query in that one piece of code so that query is probably wrong, right? It's kind of like a poor man's New Relic or a black file. So that's fast CGI. And the nice thing is PHP is still fast, but on the web server side, you have no overhead anymore for static content because if you're just serving a static GIF, you don't have the 20 megabytes per process times 100 or something for each mod PHP that's loaded in memory. Oh, it's just Apache, our Nginx, right? And Apache and Nginx with events, like they are so efficient now, that's basically some sort of underlying operating system function call that just takes blocks on disk or in a cached page in memory and shoves it without using the CPU straight to the TCP connection on the network interface. So that's why Nginx is so fast, right, when you want to serve static files. And the web server can use threading now without affecting PHP. But the problem is we still run this whole loop of requests, startup, cleaning everything, et cetera, et cetera, right, in PHP. But more importantly, and this is something that did not matter so much, five, six, seven, eight years ago, when PHP was a little bit stale, when we didn't have Composer with frameworks that were easily composable from a multitude of libraries, but now our frameworks are really, really complicated and powerful, but with that comes a certain overhead at startup time. So if you take the average Laravel or Symphony Hello World page, that probably spends 60, 70% of its time not showing the Hello World, but just starting Symphony or Laravel, loading all the configuration, even if it's cached, even if you use opcache. That's still a lot of code that runs, that initializes all your factories and your dependency injection containers and gives you all your service instances and configures them and sets parameters and loads files, megabytes and megabytes of serialized PHP arrays somewhere. So that's a problem. But that's not really something we can fix, right, because that's just how PHP works. PHP runs code and you don't have to worry about what comes after you. Well, what do other languages do? So Ruby and Python, let's say, to a bigger extent, Ruby and to a less extent, Python, are also really popular for web applications, right? People use them. And they kind of, both in popularity, grew after, for the web, grew after the web became big, right? PHP is off the web, by the web, for the web. Python and Ruby were more general-purpose languages that later figured out, hey, this is really cool, because CGI and scripting, so why don't we use that code because Python is really nice to write, I really like Python, so why wouldn't you write something in Python? Now, for Python and for Ruby, there is also mod underscore Ruby and mod underscore Python. The problem is, mod Python isn't that super stable, mod Ruby, from what I know, crashes all the time because the Ruby interpreter is built on shakier grounds than PHP, I would say, if to put it, you know, diplomatically. And so they had to come up years ago with solutions for this. And these solutions are called RAC and WSGI. Who's used Rails ever, looked at Rails and stuff? So you probably know what RAC is, right? RAC is a middleware standard so that servers and clients, sorry, servers and applications can interact. And the same is true for WSGI. It's basically a standard that says, this is what a request looks like and this is how you handle it in code and this is how you return a response, right? It's kind of like CGI, except it doesn't assume that the process that handles the HTTP connections is necessarily an external thing like Apache or Nginx. So you can write really, really simple applications without any built-in magic like PHP has for dollar underscore get and the automatic parsing of forms, et cetera. Ruby and Python don't have this, right? You can do it when you load special CGI libraries but if you don't do that, fast CGI is not really a thing with these. You use RAC or you use WSGI. So a standard RAC application looks something like this. You say, new process and all it does is return a 200, a content type header and a Hello World and that's an application. And now any RAC compatible web server can serve this application. And the same with Python, you say, there's my application, it has an environment that I can read from, right? Like that's where the request, et cetera, is. And then start responses are callable. This is actually a really clever design for two reasons. First of all, it gives you the callable that you used to say, now I'm ready to send a response, which is great for testing, mocking, et cetera. And the other thing is you may have noticed that the Hello World is not a return or an echo, it's a yield. So it's called a generator. Who knows what a generator is? Okay, a few people, good. For those of you who don't know, it's essentially you can write code that basically, let's say you want to read a file and encrypt every line, right? And you don't want to load the whole file into memory. So you want to read a line and then you run it through ROT 13 because it's really safe. And then you return that line, right? And then you do it with the next line. And let's say that file is two terabytes. So you can't load that into memory because you don't have two terabytes of memory. So what do you do? You write an iterator, right? And the iterator says open the file, read one line, encrypt, return, right? But now the calling code needs to know how does that work, et cetera, et cetera. And like writing an iterator is a lot of pain. So what you can do instead is, in PHP, this is a feature since 7.0. So you say, while you do the F open and you do the while line equals F read. And then instead of returning or echoing, you say yield ROT 13 line. And then calling code can call this function and basically exhaust all the lines and let's say write them to S3 or something that has infinite capacity because it's two terabytes. And then eventually there is no more stuff to read in your while loop and it gets called again the function and then it returns to outside of the while loop and closes. So you can serve content in constant memory, which is really nice. Rack actually has the same ability. So that means your application can stream a video, for instance, on the fly, right? You could build a video transcoder service that takes the request, takes each frame, flips it upside down and yields it. And then video, trans, whatever, coding is not that simple, obviously, but I hope you get the basic ideas. You can do really efficient things. The other thing that this allows you is in Environ, in WSGI, you have the headers, but the body is also a generator. So that means when I upload two gigabytes of a file to this Python application, the two gigabytes of the file don't have to be uploaded until the application can start handling the upload, right? So what it can do is the application can say start, okay, that looks okay, the content length is fine, two gigabytes, whatever. They're paying for it, hopefully. And then you just send the data onwards to S3 or something. That's not possible in PHP. If you upload a file in PHP, that's 80 megabytes, and your upload max file size is 16, then it takes 80 megabytes for Apache or Nginx to read and then it invokes your script and the script says that's too large, right? So that's one cool feature. There is other cool features, I will get back to those. But the cool thing about this is there is no reason why application has to call start response. It could call some code that authenticates a user and that calls some code that does some routing logic and modifies Environ and changes the request URL or whatever, right? And so forth and so forth. And the same for rack. And that's called a rack or WSGI stack, right? You have middlewares. So it starts with a web server that could be Unicorn. That's Ruby processes that get spawned and Ruby code acts as a web server. G Unicorn is the same in Python. Puma and Tornado are the same concept but they use threading in Python or Ruby. Obviously, not everybody uses Puma and Tornado because a lot of Ruby and Python developers use external libraries that are not thread safe, right? So they have to use the process-based ones. Fusion Passenger is a module that attaches to Nginx. It gets loaded into Nginx or it gets loaded into Apache and it acts as the first step in this middleware chain. So it fills Environ and the other variables up here and gives a start response. And the start response callback is then native Fusion Passenger or WSGI code that handles the response. So you can have really fast stable web servers as well if you want to still serve static files, for instance. And then you can basically do a stack. Think of it like an onion, right? You have the router calling the authentication, calling the variable filtering, calling the post processor, calling your Django or Rails application. And then that returns and eventually the post processor says, oh, that looks like XML. I need to tidy that up or oh, that looks like image. I will compress that or something like that, right? And then the code returns and all that code is native Ruby, native Python. And then at the end, the code that you call is a heavy framework like Rails or Django or like a micro framework like Sinatra or Flask. And the magic is, there's exceptions, there's always incompatibilities. But in principle, you can use any Ruby server with any Ruby middleware and any Ruby framework, right? And the same for Python. So somebody from the Laravel community could write some authentication thing not as a bundle in Symphony, but as like a middleware that just intercepts the request very early if there's no, I don't know, SSL client certificate, right? And that works with a Symphony, Sylex, then framework application if we were to all adhere to some standard, right? But for that, we need native PHP web servers. So PHP and Python and Ruby went through kind of different paths to get to the same destination. Ruby and Python started as general purpose languages and they slowly converged onto the web. PHP started on the website and then eventually figured out we should grow up, right? And like have a more stable engine and faster, et cetera. PHP is doing extremely well in this race and in this competition because it's way faster than Ruby and Python. It's really, really stable now. And it now has the necessary tools and engine changes in place to finally allow an architecture like this. So an obvious one is that PHP 7 is leaps and bounds faster than PHP 5, roughly twice as fast. So it now becomes suddenly a lot more feasible to write a PHP server, an HTTP server in PHP, right? Because you need to open a socket and listen on it and parse the request, like read the data and this is usually stuff you write in C code. So if you want to write that in native code, it would be great if the scripting engine for that code is fast, which is the case now. The second much, much, much bigger thing is that almost all engine errors with very, very, very few exceptions in PHP are now catchable. So this is something that Python has had for years, right? You can do a try and then you include a file in Python and if the file has a syntax error, that's catchable. In PHP 5, the process dies and there is nothing you can do about this, which is bad if you wanna run a web server that runs maybe other people's code that you don't know and has a typo when your web server is gone, right? You really don't want that. So the ability to catch engine level errors is really, really important for a system like this. So that's now done. Another nice thing is PHP 7.1 finally has native signal handling. So if you send a so-called SIG term or a Control C, a SIG int to running PHP code, there used to be no way to react to that, right? There's an extension called PCNTL, process control and it can pull for a signal. Did somebody send me a SIG term to tell me as a process I should shut down cleanly? Did somebody on the shell hit Control C, right? The reason why controlling C out of a PHP process works is because the engine takes care of it. But you really, in your code, when you have a development server locally and you hit Control C, what you want is that that server maybe kills other processes it has spawned and stuff like this. So you need the ability to react to that and that wasn't possible until PHP 7.1. It was possible, but you had to use so-called ticks. So at the top of your file, you say declare ticks equals one and then you'll register a special signal handler but the problem with ticks are really, they slow down your execution of your code, right? Because every time PHP runs an instruction, every time the PHP engine runs an instruction, it would execute any tick callback. So, and if that callback is expensive, such as let's check if there's a signal that was delivered to us from the shell or operating system, then your code only runs at half the speed or something. But most importantly, we now have really good concurrency frameworks. Because none of this stuff is possible if you don't have a really solid library that can run in a loop and handle a lot of connections at the same time that can asynchronously wait for IO, right? That's why Node.js is so strong at concurrency. That's why with Node.js, you can handle five, 10, 20,000 connections, not necessarily as high speed all the time, right? I mean, Node has other problems. Node is heavily, heavily single process. Node cluster is a bit of a pain. But the ability Node to just handle, like have a lot of connections open and whenever there's data from one and from the other, you do a little bit more code. That's why everything's heavily callback based in Node.js, right? And JavaScript lends itself well to that with its closures and variable binding. So we have that now in PHP. So React PHP is the oldest. It's a reactor. I'll show you in a moment what that means. Icicle is another one and then a relatively new one is called AMP PHP. They're all, they have slightly different areas of focus, but they are basically all a loop. And in the loop, you can do something. You can read a file, but non-blocking, right? Whenever the operating system delivers a few more bytes than whatever callback you have to find runs again. Whenever the network connection you're making outbound is ready, your callback is called. Whenever the DNS resolution that you made for a host name returns, your callback gets called, right? So you can do a lot of things with IO at the same time, really, really efficiently with all three of those. And all three also deliver an HTTP server. They have different features. Some don't, they do HTTP one perfectly. Some don't do Keep Alive. They're all in early-ish stages. This is probably not yet something you wanna run in production. But it's getting there, right? So these libraries use a so-called reactor pattern. Essentially, you run a loop and this so-called reactor has the ability to change itself all the time, right? So this actually never stops because the repeat function just calls tick, tick, tick all the time, this callback. But in this callback, I could start counting and say, oh, we're at iteration 1,000, I now wanna stop that function. And then the next callback would be called because there's nothing left to do and my code would quit. Or I could say, oh, tick number 1,000, it's time to open a file and I could open a file. And then in the next iteration of the event loop, it does that, right? Underneath it, it's either just a while loop that calls a function called stream select. That's a PHP function. And that uses an operating system function called select, which is for IO switching. But all these libraries can use libEvent or libEv or libUv, which are very good, very stable external concurrency libraries that are used by many, many operating systems, many, many web servers, many high-performance applications around the globe. So it's built on really strong foundations. And I could now hear, say, instead of just doing something every 1,000 milliseconds, I do something every time somebody connects to me. And then I check, oh, cool, that's port 80, obviously, because that's why I'm listening. And does it look like a valid HTTP request? If yes, then I register another callback that waits for the data to arrive. And once it has arrived, I send back some data, again, a synchronously that says, hello, world. And I've built an HTTP server. Luckily, they've done that for us, all of them. So in React PHP, for instance, you can write a massively concurrent, asynchronous, evented HTTP server like this. And that looks a lot like Node.js, right? You say, this is a callback. Every time a request comes in, call that callback. So now we have an evented HTTP server in PHP. And we don't need Apache, we don't need Nginx. We just type PHP, hello.php, and that listens on port 1337, and it works. So two clever people have taken the concept and said, well, you know, it's gonna be a few years until, or maybe, and I personally think this will never happen. PHP will never change to the point where we do evented heavily callback-based programming like Node.js. Because these different approaches have advantages and disadvantages. PHP's process model, the fact that you do write an imperative code, you don't have to worry a lot about like a spaghetti hell of callbacks and memory leaks, et cetera, that has advantages, right? But what if we could start Symphony and then start that loop? Is that possible? Maybe. So one thing you need first is this only handles, you know, one request at a time, like it's still all threading. It can still handle connections, et cetera, at a time, but it will only call one bit of code at a time. So we need more of these processes. So we need a supervisor process that says, well, I want 100 of these, and then some sort of load balance and front so that the traffic for my great new website is served properly. So there's one, the PHP process manager bundle, that's for Symphony, and then a bit more generic, PHP PM, which is this idea that you launch a process that only manages other processes and that serves the actual application code. And with them, you can run Symphony, you can run Laravel without having to launch Laravel for each request. So, sorry, we need to delete that slide. We were here, right? All right, that's better. So you can use PHP PM, et cetera, but you can also hack it together with just, let's say, React PHP server, because you already saw a simple Hello World example. So what we say is we create a new app kernel for Symphony and then, obviously, we initialize React PHP and tell it to listen, et cetera, right? And give it the callback for every time a request comes in. And that receives a request object and a response object that we write to and it needs the kernel for Symphony. So, and the kernel is obviously already initialized, right? Like, that's when you do new app kernel, it does all the services and dependency injection, et cetera. So that's the heavy lifting Symphony does for you. And now, we wanna feed Symphony a request, not from $underscore gets and $underscore session and $underscore post and $underscore server, right? The way it would normally do when you just run it in PHP because that's where all the information usually comes from. We wanna tell it because dollar request is our native PHP web server handling a request. So it has all the headers and it has all the information from the browser. So now, we need tell Symphony, run with that information and return us the results. So you say, give me all the headers and then we do a bunch of checks, is that even a legal request method? And if the content type is set, so this is for form handling, right? That's what I said earlier, because the thing is, when you submit a form to PHP, PHP sees that MIME type, x, dub, dub, form, you're unencoded and it takes the request body, you can use that, you can get that from PHP colon slash slash input, it's a stream in PHP, right? So if I upload, not with a web form, but just with an HTTP put an image to you, the headers are in dollar underscore server and PHP input is gonna be the binary data for the image I'm sending on the HTTP connection. And a web form submission with a post is the same thing, right? So a post is really, of a web form, is really just a long URL encoded string, like a query string, but in the post body. So that's what we're doing here is like we're saying, if it's a post, put, delete or patch and the content type is set and it's a form, then we call PHP's function for that, which is parse string. We feed it the body and it decodes that into post data and then we say, sure, let's make a new request for symphony and we give it our query string, we give it the post data if it exists and some empty arrays for stuff that doesn't matter, cookies, et cetera, we can ignore those for the moment. Files if there are any. Excuse me. And the request body and that's it. That's pretty good. Now we have a request. Now we say, we set the method based on the method that we get from the dollar request object from React PHP and we set all the headers that we parsed and we tell it what the request URI is that's also available to us in request got path. Again, that's something that React PHP got from parsing the HTTP request, right? Because the HTTP request starts with get slash foobar space HTTP slash 1.1. So slash foobar is in get path and if there is a host header, we set the host header as a server name and then we're pretty much good to go. Then we're saying kernel and we have the kernel made before only once, handle this code and write out the response headers and stream through the response contents. In this case, I think it would buffer, right? So if you render a page, that's 100 kilobytes, it's 100 kilobytes string that gets sent back but there is nothing stopping you theoretically from rewiring everything so it hooks into some sort of event-based loop again and or with a generator sends out the content of your application, of the request body that your application wants to send. And then you would have a really, really efficient web server and then eventually you want to terminate the request so the kernel knows it's done and can reset a few bits of internal state. And that is symphony running in a native web server and it works, it really does. So the interesting question is what becomes possible with that? So the first bit is performance. And I think that's a really good reason to do it because you cut out all the web's, the application initialization overhead. Also, you no longer have to rely on persistent connections from your database layer. You just make a connection once and it stays open. That also means you should need to be careful with transactions, et cetera. So the guy who wrote PHP PM, his name is Mark Schmidt, he's German, he benchmarked this a little bit. So he did two things. So first he compared native PHP with PHP FPM and HHVM, but he also tried two things. One is he has a PHP process that distributes all the requests across all the sub-processes he spawns that run the actual symphony code. And the other one was he launches 100 PHP processes that launch a little web server, but instead of doing the load balancing himself, he then configured an Nginx to say, hey Nginx, just proxy to these 100 processes, right? Because Nginx uses native C code heavily optimized for the exact thing. In a loop, select input and output streams and multiplex them, right? So that you can have 2,000 open connections waiting in your listen backlog and 100 connections and flight on the back ends and it's super efficient to send the data back and forth. And that's what Nginx really shines at. So it's good, it's really, really fast because if you look at React, so that's the green thing, right? It's already as fast as HHVM with a native web server that HHVM has or the Nginx implementation. But if you then start hooking up React to Nginx for load balancing, I mean not quite, but almost twice as fast as HHVM, right? And the baseline is just standard PHP FPM which initializes symphony in each request. So that performance gain is pretty massive. That's more than all of magnitude faster, right? 130 versus 1,900 requests. But we get other features. One thing we can do, I mentioned this already, is now that Apache or Nginx is no longer buffering the data for us, we can start doing something with the request data, for instance the video that somebody's uploading, while it's still in flight to us, right? So we could also write some logic that in a loop for a connection knows, oh, in the last 20 seconds, we only got 30 bytes. So it's either a really, really slow mobile client or it's an attack. There's an attack called the slow Loris attack that basically takes a website down by opening a connection, only sending a byte, and then another couple of seconds later, another byte, et cetera. So that ties up all the web server processes, right? We could, and I think this is a huge, huge, huge thing. Who's doing web sockets with PHP? Nobody. Nice. No, two people in the back raised their hands. And we're getting close to time, I know. I'm sorry, I'm almost done. So if you wanna do web sockets in Node.js, it's simple. You have some logic in place that says, if there's an upgrade header, and if the location is slash chat, then here's my web socket logic, right? In PHP, you can't do that. In PHP, you get an HTTP request from the web server and you just have to deal with that, right? So for PHP, when you wanna run web sockets, you have to have a separate web socket server, also written in PHP that listens on a different port, and then your JavaScript code needs to know that it needs to connect to the different port, so when you wanna run that in production, now you're running FPM and Apache and that stupid web socket code, not to mention the fact that you don't have one code base that can handle both the chat page and the chat message stream, right? And with this, you can do both because you're getting the request, you see the upgrade header in the HTTP request, you say, sure, the callback for this is my chat code, right? And that sends messages back and forth. So that's really, really great and it's also a matter of simplicity. Just to run the code, I mean, obviously, database is seeding, blah, everybody has horrible, vagrant boxes that break all the time and then people in the team point fingers who's to blame, but you clone a project, you compose or install, you do PHP server or PHP or something and it works. You don't have to configure Nginx or Apache, it just works, right? That's great and it works properly. It's not like the PHP built-in web server that can do one request at a time and then falls on its face, it's like a proper thing. But things also become impossible, right? So sessions don't work anymore, for instance, because the whole PHP's native session handling assumes that everything gets torn down. You have no influence over what happens on sessions start. In fact, if you flush the session, it will send a header. So if you do that twice, it'll say header's already sent. You've probably already ever, everybody of you has seen that error once in their lifetime, right? You can no longer ignore memleaks because right now, if you're doctrine underlying PDO thing, leaks a bit of memory, who cares, right? Because it all gets wiped away after your code is done. But if your code runs in a loop, five million times half a megabyte starts adding up, right? The solution that actually PHP PM, for instance, has is it will also serve 1,000 requests and then terminate that script and restart it just to prevent that from happening. But what's really nice is the potential for a really bright future that PHP has, similar to RAC and similar to WSGI, right? So PSR7 is a standard for a message interface that's already an accepted standard from the PHP FIG. But there is a separate one currently in the draft state that defines what a middleware interface looks like. And once we have that, everything's installable with Composer, suddenly you're pulling in 500 middlewares, right? And these middlewares can do transformation, authentication, security, et cetera. And suddenly we would have React, we would have AMPHP, we have Icicle, three web servers who are competing, who's the fastest, who's the most stable, which one works on Windows? Because Windows is like, you know, in many ways left out of this because of process handling concerns, et cetera. But it's possible, Ruby does it, for Unicorn, it works on Windows. So that would be great, right? And then you could have a legacy server that doesn't really accept HTTP connections, it just fetches data from Git and from the underscore server and from the underscore post and puts it in a message and says dispatch, right? So that new code that needs this new functionality for the middlewares, et cetera, can still run with an old CGI Apache or with an Nginx plus PHP FPM. Or you say, you have one of these new React servers that run in a loop and then you try to hook up WordPress to it, which doesn't even know that that's a thing, right? Because the last bit of code that runs before WordPress is invoked, you just do include index.php in your loop. But the last thing you do before that is extract the data into the long score gets. It's probably gonna break because WordPress uses sessions, et cetera, but it's worth a try, right? That'd be great. So if you wanna read up on this, there's a bunch of really good blog posts. I'll upload these slides and tweet about them. Because then you can just hopefully copy paste or at least type these URLs in. So you don't have to worry about this. This was an hour and five minutes, which means how many, I have negative five minutes for questions, right? Okay, yeah, I understand. So I'm really sorry that this is the first time I'm giving this talk, so pacing needs to be improved, obviously. But I thank you very, very much for listening and again, hit me up after the talk, later at lunch, email, Twitter for questions and enjoy the rest of the conference. Thank you.