Preload your sweet sweet code to opcache with a composer command, making your code faster to run.

Overview

Composer Preload

Preload your sweet sweet code to opcache with a composer command, making your code run faster.

Composer Preload is a composer plugin aiming to provide and complement PHP opcache warming. This plugin introduces a new composer preload command that can generate a vendor/preload.php file (following vendor/autoload.php pattern) that contains calls to warm up the opcache cache.

Please note that this plugin is currently in a very rudimentary state, and it is highly recommend to not use this in any production system. Any contributions are warmly welcome!

How it works

At the moment, this plugin scans for .php files in the given paths recursively, and create a file that calls opcache_compile_file function.

When you want to warm up the cache, you can either call php vendor/preload.php in command line, or when PHP 7.4 hits the shelves, configure PHP to automatically load this file.

Installation

Just the way you'd install a normal composer package, you can install this plugin aswell:

composer require ayesh/composer-preload

If you would rather install this globally:

composer g require ayesh/composer-preload

Configuration

1: Modify your composer.json file, and create a section called extra if it's not there already. Following is an example:

{
    "extra": {
        "preload": {
            "paths": [
                "web"
            ],
            "exclude": [
                "web/core/tests",
                "web/core/lib/Drupal/Component/Assertion",
                "web/core/modules/simpletest",
                "web/core/modules/editor/src/Tests"
            ],
            "extensions": ["php", "module", "inc", "install"],
            "exclude-regex": "/[A-Za-z0-9_]test\\.php$/i",
            "no-status-check": false,
            "files": [
                "somefile.php"
            ]
        }
    }
}

The extra.preload directive contains all the configuration options for this plugin. The paths directive must be an array of directories relative to the composer.json file. These directories will be scanned recursively for .php files, converted to absolute paths, and appended to the vendor/preload.php file.

2: Run the composer preload command.

3: Execute the generated vendor/preload.php file. You can either run php vendor/preload.php or use your web server to execute it. See the Preloading section below for more information.

Configuration options

  • extra.preload.paths : Required

An array of directory paths to look for .php files in. This setting is required as of now. The directories must exist at the time composer preload command is run.

  • extra.preload.exclude : Optional

An array of directory paths to exclude from the preload.php. This list must be relative to the composer.json file, similar to the paths directive. The ideal use case limiting the scope of the paths directive.

  • extra.preload.extensions : Optional, Default: ["php"]

An array of file extensions to search for. If not entered, it will search for all .php files. Do not enter the proceeding period (.) character. The example above is suitable for Drupal. For Symfony/Laravel projects, you can leave the default option ["php"] or just not use this option so it defaults to just .php.

  • extra.preload.exclude-regex : Optional

Set a PCRE compatible full regular expression (with delimiters and modifiers included) that will be matched against the full path, and if matched, will be excluded from the preload list. This can help you exclude tests from the preload list.

For example, to exclude all PHPUnit-akin tests, you can use the regular expression /[A-Za-z0-9_]test\\.php$/i. This will make sure the file name ends with "test.php", but also has an alphanumeric or underscore prefix. This is a common pattern of PHPUnit tests. The /i modifier makes the match case insensitive.

For directory separators, always use Unix-style forward slashes (/) even if you are on a Windows system that uses backwards slashes (\). Don't forget to properly escape the regex pattern to work within JSON syntax; e.g escape slashes (\ and /) with a backwards slash (\ -> \\ and / -> \/). This will make the regular expression hard to read, but ¯\(ツ)/¯.

  • extra.preload.no-status-check: Optional, Default: false

If this setting is set to true (you can also pass command line option --no-status-check), make the generated preload.php file not contain additional checks to make sure the opcache is enabled. This setting is disabled by default, and the generated preload.php file will contain a small snippet on the top that makes it quit if opcache is not enabled.

  • extra.preload.files : Optional

An array of single files to be included. This setting is optional. The files must exist at the time composer preload command is run.

Preloading

To do the actual preloading, execute vendor/preload.php.

If you have enabled opcache for CLI applications, you can directly call php vendor/preload.php to execute the generated PHP file and warm up the cache right away.

Future versions of this plugin will have a feature to generate the file and immediately run it.

In a webserver context, or when you cannot run the PHP file with the CLI php binary. this probably means you'll want to link vendor/preload.php into your docroot somwhere and curl it. For example, ln -s vendor/preload.php path/to/docroot/preload.php and then curl localhost/preload.php on webserver startup.

FAQ

What does this plugin even do?

This plugin can create a new file at vendor/preload.php that follows the pattern of Composer's autoloader at vendor/autoload.php. This new preload.php file contains several function calls that compiles PHP files and cache them into PHP's opcache. PHP Opcache is a shared memory (with optional file storage option) feature in PHP that can hold compiled PHP files, so the same file doesn't need to be compiled again and again when its called. This is a persistent memory until PHP is restarted or the cache is eventually cleared.

Caching files in opcache has siginificant performance benefits for the cost of memory.

So all the files are loaded all the time?

All the files are loaded to the Opcache. This is not same as you include() or require() a class, which makes PHP actually execute the code. When you cache code to Opcache, those classes are not executed - just their compiled code is cached to the memory.

For example, if you declare a variable, this plugin's preload functionality will not make the variables available inside your PHP code. You still have to include the file to make them available.

I have the vendor/preload.php file. What now?

After generating the file, you might need to actaully run it effectively load the files to Opcache. Ideally, you should do this every time you restart your web server or PHP server, depending on how you serve PHP within your web server.

PHP 7.4 has a php.ini option opcache.preload that you can specify this generated file, or a separate file that calls all vendor/preload.php files you have across your server to actively warm up the cache.

I have multiple Composer projects running on same server.

You can generate the preload file for each project, and include all of them in a separate PHP file you create by yourself. Then, call all of the generated vendor/preload.php files.

By default, the preload file will contain a small snippet at the top that will quit the script immediately if Opcache is not available. If you plan to include this vendor/preload.php file from another script, you can use the special command line option composer preload --no-status-check that will make the vendor/preload.php file not contain these checks, so you can incude multiple vendor/preload.php files across all your projects without running the same snippet over and over. It is recommended that you make sure Opcache is enabled before doing so. Feel free to copypasta the snippet from one of your generated preload files.

Can I generate the preload file in one server and use it in another server?

Yes. Similar to the vendor/autoload.php file, vendor/preload.php file this plugin generates also uses relative paths. From version v0.1.0 and forward, you can generate the preload file at one server and reuse it in other servers (directory hierarchies).

You will still need to run the vendor/preload.php file in all servers that you want to preload opcache.

Roadmap

  • ☐ Extend extras.preload section to configure the packages that should be preloaded instead of setting the individual paths.
  • ✓ Feature to set an exclude pattern (v0.0.3)
  • ☐ Progress bar to show the file generation progress
  • ☐ Flag to generate the file and run it, so the cache is immediately warmed up.
  • ☐ Fancier progress bar.
  • Full test coverage.
  • ☐ Even more fancier progress bar with opcache memory usage display, etc.
  • Get many Github stars
Comments
  • Incompatible with symfony 3?

    Incompatible with symfony 3?

    I was excited to try this out with Drupal 8, but it seems to require symfony 4, and Drupal 8 is symfony 3. That should probably go into the README.

    Thanks for the excellent thinking and work on this!

    Using version ^0.0.4 for ayesh/composer-preload
    ./composer.json has been updated
    > DrupalProject\composer\ScriptHandler::checkComposerVersion
    Loading composer repositories with package information
    Updating dependencies (including require-dev)
    Your requirements could not be resolved to an installable set of packages.
    
      Problem 1
        - Installation request for ayesh/composer-preload ^0.0.4 -> satisfiable by ayesh/composer-preload[v0.0.4].
        - Conclusion: remove symfony/finder v3.4.18
        - Conclusion: don't install symfony/finder v3.4.18
        - ayesh/composer-preload v0.0.4 requires symfony/finder ^4.1 -> satisfiable by symfony/finder[4.1.x-dev, 4.2.x-dev, v4.1.0, v4.1.0-BETA1, v4.1.0-BETA2, v4.1.0-BETA3, v4.1.1, v4.1.2, v4.1.3, v4.1.4, v4.1.5, v4.1.6, v4.1.7, v4.2.0-BETA1, v4.2.0-BETA2].
        - Can only install one of: symfony/finder[4.1.x-dev, v3.4.18].
        - Can only install one of: symfony/finder[4.2.x-dev, v3.4.18].
        - Can only install one of: symfony/finder[v4.1.0, v3.4.18].
        - Can only install one of: symfony/finder[v4.1.0-BETA1, v3.4.18].
        - Can only install one of: symfony/finder[v4.1.0-BETA2, v3.4.18].
        - Can only install one of: symfony/finder[v4.1.0-BETA3, v3.4.18].
        - Can only install one of: symfony/finder[v4.1.1, v3.4.18].
        - Can only install one of: symfony/finder[v4.1.2, v3.4.18].
        - Can only install one of: symfony/finder[v4.1.3, v3.4.18].
        - Can only install one of: symfony/finder[v4.1.4, v3.4.18].
        - Can only install one of: symfony/finder[v4.1.5, v3.4.18].
        - Can only install one of: symfony/finder[v4.1.6, v3.4.18].
        - Can only install one of: symfony/finder[v4.1.7, v3.4.18].
        - Can only install one of: symfony/finder[v4.2.0-BETA1, v3.4.18].
        - Can only install one of: symfony/finder[v4.2.0-BETA2, v3.4.18].
        - Installation request for symfony/finder (locked at v3.4.18) -> satisfiable by symfony/finder[v3.4.18].
    

    Drupal 8 really needs this :)

    I'm successful with it (at the composer require level) on TYPO3 v9.

    opened by rfay 4
  • 0.1.1 was broken `php vendor/preload.php` command

    0.1.1 was broken `php vendor/preload.php` command

    due to this line : https://github.com/Ayesh/Composer-Preload/blob/v0.1.1/src/PreloadWriter.php#L74

    should be

    if (!\function_exists('opcache_compile_file') || !\ini_get('opcache.enable')) {
    
    opened by chrisLeeTW 3
  • Fix generated paths

    Fix generated paths

    Preload file uses absolute paths. Unless both of your servers have same directory hierarchy, you cannot do this. It is recommend not to include the vendor/preload.php file in your version control system.

    But there is another case - you use build server, prepare package and upload code to server. Build server has different path. In my example I use Heroku

    opened by snapshotpl 2
  • An additional config preload.exclude-files and repair travis

    An additional config preload.exclude-files and repair travis

    Additional Config preload.exclude-files Sometimes you will face an issue that packages included within path (example vendor) has a default file. Executing vendor/preload.php can throw error as conflict of class name or function. So came out with a config to exclude this one file only.

    Repair Travis PHP Compatibility at composer.json was set to ^7.2 where else travis.yml was set nightly. Current nightly is 8.0.0-dev

    opened by ahmyi 2
  • The plugin should take dependencies into account

    The plugin should take dependencies into account

    Hi,

    I wanted to try your plugin out, but I got the following issues:

    Can't preload unlinked class AbcChild: Unknown parent
    Can't preload unlinked class BcdImplementation: Unknown interface 
    

    It means that in order for preloading to work, dependencies should be resolved first, and classes should be preloaded in the right order.

    opened by kocsismate 0
  • Improve compose.json preload section - comma errors

    Improve compose.json preload section - comma errors

    There were a couple of errors with trailing commas in the README's composer.json extra section, just a nit here. But a working example will help people not to have to debug it themselves. D*** json and it's problems with commas.

    opened by rfay 0
  • Deprecated PreloadList::getIterator() / PHP 8.1

    Deprecated PreloadList::getIterator() / PHP 8.1

    Deprecated: Return type of Ayesh\ComposerPreload\PreloadList::getIterator(): iterable should either be compatible with IteratorAggregate::getIterator(): Traversable, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice

    opened by lanfix 0
  • Fix getIterator must be compatible with interface

    Fix getIterator must be compatible with interface

    Deprecation notice in php 8.1:

    Deprecation Notice: Return type of Ayesh\ComposerPreload\PreloadList::getIterator(): iterable should either be compatible with IteratorAggregate::getIterator(): Traversable, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in /tmp/php/build/hbw/vendor/ayesh/composer-preload/src/PreloadList.php:19
    

    I saw no reason to use the attribute to suppress the notice than to fix it since this class is final.

    opened by hultberg 0
  • Compatibility issue with Symfony 5

    Compatibility issue with Symfony 5

    If you have symfony/console 5.x installed globally/for composer, then you get the following error:

    Fatal error: Uncaught TypeError: Return value of "Ayesh\ComposerPreload\Composer\Command\PreloadCommand::execute()" must be of the type int, "null" returned. vendor/symfony/console/Command/Command.php:259

    Needs to add a return 0;

    opened by Berdir 0
Owner
Ayesh Karunaratne
Software Architect, Security Researcher, Speaker, Full-time Traveler. Loves Cobblestone pavements, dark chocolate, Blueberry Pierogi, and Oxford Commas.
Ayesh Karunaratne
Make your PHP arrays sweet'n'safe

Mess We face a few problems in our PHP projects Illogical type casting (PHP's native implementation is way too "smart") Pointless casts like array =>

Artem Zakirullin 192 Nov 28, 2022
A composer plugin, to install differenty types of composer packages in custom directories outside the default composer default installation path which is in the vendor folder.

composer-custom-directory-installer A composer plugin, to install differenty types of composer packages in custom directories outside the default comp

Mina Nabil Sami 136 Dec 30, 2022
Run your WP site on github pages, php innovation award winner https://www.phpclasses.org/package/12091-PHP-Make-a-WordPress-site-run-on-GitHub-pages.html

Gitpress Run wordpress directly on github pages Gitpress won the innovation award for may 2021 Read more about this https://naveen17797.github.io/gitp

naveen 13 Nov 18, 2022
A collection of command line scripts for Magento 2 code generation, and a PHP module system for organizing command line scripts.

What is Pestle? Pestle is A PHP Framework for creating and organizing command line programs An experiment in implementing python style module imports

Alan Storm 526 Dec 5, 2022
Composer plugin that wraps all composer vendor packages inside your own namespace. Intended for WordPress plugins.

Imposter Plugin Composer plugin that wraps all composer vendor packages inside your own namespace. Intended for WordPress plugins. Built with ♥ by Typ

Typist Tech 127 Dec 17, 2022
Contains a few tools usefull for making your test-expectations agnostic to operating system specifics

PHPUnit Tools to ease cross operating system Testing make assertEquals* comparisons end-of-line (aka PHP_EOL) character agnostic Make use of EolAgnost

Markus Staab 1 Jan 3, 2022
Integrate reCAPTCHA using async HTTP/2, making your app fast with a few lines.

ReCaptcha Integrate reCAPTCHA using async HTTP/2, making your app fast with a few lines. use Illuminate\Support\Facades\Route; Route::post('login', f

Laragear 14 Dec 6, 2022
Makes indexing of your Magento store around x times faster! ‼️ Maintainers wanted!

FastIndexer This module has never been used in production. No more empty results in the frontend due to a long taking reindex process! Integrates seam

Cyrill Schumacher 79 Jul 10, 2022
A PHP Library To Make Your Work Work Easier/Faster

This Is A Php Library To Make Your Work Easier/Faster,

functionality 2 Dec 30, 2022
This module adds a command to easily generate "modules" in Laravel and install them using composer.

Laravel Module Create This module adds a command to easily generate "modules" in Laravel and install them using composer Installation Simply install t

null 2 Feb 18, 2022
Ied plugin composer - Inspired Plugin Composer: Create, publish and edit plugins from within Textpattern CMS.

ied_plugin_composer Create, publish and edit plugins from within Textpattern CMS. Creates a new page under the Extensions tab where you can edit and e

Stef Dawson 8 Oct 3, 2020
Magento-composer-installer - Composer installer for Magento modules

!!! support the maintainer of this project via Patreon: https://www.patreon.com/Flyingmana Magento Composer Installer The purpose of this project is t

null 213 Sep 24, 2022
Composer Repository Manager for selling Magento 2 extension and offering composer installation for ordered packages.

Magento 2 Composer Repository Credits We got inspired by https://github.com/Genmato. Composer Repository for Magento 2 This extension works as a Magen

EAdesign 18 Dec 16, 2021
Composer registry manager that help to easily switch to the composer repository you want

CRM - Composer Registry Manager Composer Registry Manager can help you easily and quickly switch between different composer repositories. 简体中文 Install

Tao 500 Dec 29, 2022
Dependency graph visualization for composer.json (PHP + Composer)

clue/graph-composer Graph visualization for your project's composer.json and its dependencies: Table of contents Usage graph-composer show graph-compo

Christian Lück 797 Jan 5, 2023
Composer Registrar Composer Plugin for Magento 2

This module add a global registration.php that replace the default glob search performed for each request to discover the components not installed from composer.

OpenGento 3 Mar 22, 2022
Drupal Composer Scaffold - A flexible Composer project scaffold builder

This project provides a composer plugin for placing scaffold files (like index.php, update.php, …) from the drupal/core project into their desired location inside the web root. Only individual files may be scaffolded with this plugin.

Drupal 44 Sep 22, 2022
Victor The Cleaner for Composer - This tool removes unnecessary files and directories from Composer vendor directory.

Victor The Cleaner for Composer This tool removes unnecessary files and directories from Composer vendor directory. The Cleaner leaves only directorie

David Grudl 133 Oct 26, 2022
Opinionated version of Wikimedia composer-merge-plugin to work in pair with Bamarni composer-bin-plugin.

Composer Inheritance Plugin Opinionated version of Wikimedia composer-merge-plugin to work in pair with bamarni/composer-bin-plugin. Usage If you are

Théo FIDRY 25 Dec 2, 2022