[RFC] Opcache Preloading for Mezzio and MVC

Goal

Provide a mechanism for seeding the opcache preloading capabilities of PHP for:

  • MVC and API Tools applications
  • Mezzio applications

Background

PHP 7.4 introduces the opcache.preload setting and the opcache_compile_file() function. These can be used to preload files into the OpCache prior to starting the background PHP process (whether thats mod_php, php-fpm, or something like Swoole).

To use the functionality, you must define a file that performs include operations on the various files you want preloaded, or which calls opcache_compile_file() on each.

One thing to note: when compiling a file containing a class, you must also make certain you compile anything on which it depends: interfaces, parent classes, traits, etc. Failing to do so will result in a failure to preload its data.

Considerations

  • Since the functionality is compiling opcodes and storing them in memory, there’s obviously a trade-off in the amount of memory used. One thing to note is that if this goes beyond a certain threshold, you lose some efficiency; the common understanding is that the number of classes preloaded should likely not exceed around 100.

  • We currently compile configuration on first-request and then cache it. Additionally, it’s an array. We should likely provide some mechanism for compiling it to an ArrayObject implementation which can be autoloaded or included somehow.

    • Keep in mind that such configuration will likely need access to environment variables, and, as such, would need to be a deployment-time operation. When you consider Docker containers, this is a simple problem to solve, as env variables are passed as the container spins up, and the opcache.preload file is loaded when the PHP process starts. (This is how platform.sh works as well.)
  • It might be useful to be able to create a “compiled container”, based on the compiled configuration.

Suggested Approaches

One suggested approach is to generate a preload file that contains a class whereby you can specify directory paths with class files to include, and which uses the generated composer classmap autoloader to determine if a given file is relevant for purposes of providing PHP classes. Such a class can then also be used to provide a list of classes to ignore (e.g., if there are adapters you are not interested in).

If we went this route, we could even provide sane defaults for libraries you may want to preload: mezzio/mezzio, laminas/laminas-mvc, etc.

An example of such a class can be found on stitcher.io.

This would require:

  • Command line tooling
  • that would generate the preload file.
1 Like

Notes from the April 2020 TSC meeting:

  • This should use the new laminas-cli tooling to expose its commands.

  • We should name the preload script based on a consensus location seen in other frameworks; in particular, see where Symfony, Laravel, Yii, and Cake are doing.

  • Once the file is generated, the tooling should indicate the next steps (e.g., registering it with php.ini).

  • A command for spitting out the php.ini line to allow easily appending it would be useful (e.g. laminas preoload:ini >> path/to/php.ini).

1 Like
  • Symfony pushes it into var/cache/, and uses a name based on an HttpKernel class or interface.
  • Laravel does not have official support yet.
  • Yii does not either
  • I cannot find any information either way as to whether or not CakePHP supports it.

My feeling is, to keep it as framework agnostic as possible, we should have it be in the root directory of the application, and I would suggest a filename of preload.php.

READY FOR TESTING

I’ve got a work-in-progress proof-of-concept ready for people to test:

I’ve tried it with a few applications, and it appears to work fine. I’d love a bit more testing before I bring it back to the TSC to review, however.