Speeding up PHP application bootstrap with Class Dumper

One reasons for PHP still being considered slow is a consequence of how it works under web server environment: every time a client sends request, application is initialized from scratch - it runs all the bootstrap code. Bootstrapping is repeated over and over again, for every connecting client.

While this is an obvious waste of resources, it is also very difficult to avoid without rewriting an application under different architecture. Is there anything that could be done to at least reduce impact of application bootstrap, without making any changes to actual application? As it turns out, there is.

Merging class files

Even simple application written in modern, full-stack framework can use 100-200 classes just to show "Hello, World" in the browser. For each of this classes PHP needs to check if file exists, then open it and parse. This creates significant overhead even when opcache is enabled. There's an easy way to go around it though: you can put all classes that used on every request in a single file.

There are at least two frameworks that can merge this files for you: Symfony (via Bootstrap Files) and Zend Framework (via EdpSuperluminal module). Their solutions are difficult to reuse though, as they are tailored to work with given framework.

Class Dumper

Using ideas from this projects as a base, I crafted a general solution, that can be used everywhere: Class Dumper.
Idea is to let you choose any classes you want, and merge them together. Just as it is done in Symfony, you can automate this process with composer hooks - merged file will be refreshed whenever you update your dependencies.

Example

This is how your config could look like when building Zend Expressive app:

<?php

return [
    Zend\ServiceManager\Config::class,
    Zend\ServiceManager\ServiceManager::class,
    Zend\Expressive\Container\ApplicationFactory::class,
    Zend\Expressive\Router\Aura::class,
    Aura\Router\Router::class,
    Aura\Router\AbstractSpec::class,
    Aura\Router\RouteCollection::class,
    Aura\Router\RouteFactory::class,
    Aura\Router\Regex::class,
    Aura\Router\Generator::class,
    Zend\Expressive\Emitter\EmitterStack::class,
    Zend\Diactoros\Response\SapiEmitter::class,
    Zend\Stratigility\MiddlewarePipe::class,
    Zend\Expressive\Application::class,
    Zend\Stratigility\Route::class,
    Zend\Expressive\Router\Route::class,
    Aura\Router\Route::class,
    Zend\Diactoros\ServerRequestFactory::class,
    Zend\Diactoros\ServerRequest::class,
    Zend\Diactoros\Uri::class,
    Zend\Diactoros\Stream::class,
    Zend\Diactoros\PhpInputStream::class,
    Zend\Diactoros\HeaderSecurity::class,
    Zend\Diactoros\Response::class,
    Zend\Stratigility\FinalHandler::class,
    Zend\Stratigility\Http\Request::class,
    Zend\Stratigility\Http\Response::class,
    Zend\Stratigility\Next::class,
    Zend\Stratigility\Dispatch::class,
    Zend\Stratigility\Utils::class,
    Zend\Diactoros\Response\HtmlResponse::class,
];

You don't have to worry about order in which you place this classes, nor about their hard dependencies (parent classes, interfaces...) - Class Dumper will add them automatically to the merged file.

Let's assume you put this list in classes-to-cache.php file. Merging files together is as easy as running console command:

php ./vendor/bin/dump-classes.php classes-to-cache.php classes.php.cache --strip

--strip switch will ensure that generated file is as small as possible.
Finally, start using cached classes, by including generated file in your index.php:

<?php
include 'vendor/autoload.php';
include 'classes.php.cache';

Efficiency

Real performance gain can vary depending on number of files cached and your PHP configuration. I've tried it under different conditions, and I've seen improvements ranging from 2% to 10%. Of course if your App does some IO (database access), the end result will be even smaller. On the other hand, efficiency will increase with number of files merged together. Always ensure that OpCache enabled, and that merged file doesn't grow too big (try keeping it below 1MB).

Despite low efficiency in some cases, this optimization is worth considering, as it comes almost for free - create list of classes, update composer.json, and that's it!

More resources

Class Dumper can be found on Github, where you can also find detailed usage options, example composer hook, and limitations. Project is also available on Packagist.

Read more 

PSR-7: HTTP Messages Today

PSR-7 is here and is big. Now, more than one month after it was voted, a lot of work has been put into projects supporting this standard. Even though we’re still at the beginning of this great journey, it is exciting to see what is already available, thanks to great work of PHP community.

Watching related projects since the inception of that standard, I will present packages that can serve as foundation for actual applications: HTTP message implementations, dispatchers and micro frameworks.

Read more 

ZF-Console: PHP microframework for console applications

As you may know, folks from ZF2/Apigility projects keep bringing interesting utility modules, enriching ZF2 ecosystem. Today I discovered small framework/helper for writing console applications: ZF-Console. And, to my surprise, it was based on my own pull request from last year! I was really proud to see that I brought something useful to the community.

Read more 

Testing ZF2 module services

There's an important question often rising when working on Zend Framework 2 module: should I test service factories? After all, they are usually trivial, they create some object and inject it with dependencies from ServiceManager. Having one test per factory seems to be an overkill.

Better to go one step back, and ask yourself a question: what exactly do you want to test?

Read more 

MtMail: e-mail module for ZF2

I'm happy to present a ZF2 module that handles composing and sending e-mail messages.

Why another module? There are a few of them already available on ZF modules website. However, when I was looking for solution to use in my application, I quickly realized that most of them are either outdated, or they miss features I needed. That's why I decided to write my own.

My intention was to create something powerful, but still simple to use. You an customize e-mail headers, add layout, automatically generate plaintext version of HTML e-mail, and so on. But you can also start composing and sending e-emails from your controllers with just a few lines of code.

Read more 

Using standalone Zend\View

Zend\View is pretty advanced rendering engine, with multiple useful features. It is working nicely within ZF2's MVC stack, where it is automatically configured for you. But how to use it without full MVC?

This can be useful in some situations: when building Your Own Microframework™, when creating an application based on ZF2 components, or (in my case) when working on module that is supposed to render something outside MVC flow. All of this projects can benefit from nested templates, multiple rendering engines, or pluggable architecture of Zend\View.

So, how to do that?

Read more 

About me
Mateusz Tymek

After compiling my very first lines of code at the age of 12, I became passionate about computer science and technology. Now I'm a PHP developer, enjoying my work as a member of Cleeng team.
Doing some sports in my spare time.

Github activity