From f1f064981b285d8c92fc29f958ac6ffd03dc1d14 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Tue, 7 Mar 2017 12:33:19 +0100 Subject: [PATCH] Add docs about autoloader optimizations, fixes #5947 --- doc/01-basic-usage.md | 2 + doc/04-schema.md | 20 +++-- doc/articles/autoloader-optimization.md | 109 ++++++++++++++++++++++++ 3 files changed, 125 insertions(+), 6 deletions(-) create mode 100644 doc/articles/autoloader-optimization.md diff --git a/doc/01-basic-usage.md b/doc/01-basic-usage.md index 06bfa83a4..0c48cba11 100644 --- a/doc/01-basic-usage.md +++ b/doc/01-basic-usage.md @@ -200,6 +200,8 @@ In addition to PSR-4 autoloading, Composer also supports PSR-0, classmap and files autoloading. See the [`autoload`](04-schema.md#autoload) reference for more information. +See also the docs on [`optimizing the autoloader`](articles/autoloader-optimization.md). + > **Note:** Composer provides its own autoloader. If you don't want to use that > one, you can just include `vendor/composer/autoload_*.php` files, which return > associative arrays allowing you to configure your own autoloader. diff --git a/doc/04-schema.md b/doc/04-schema.md index 0e96f131b..0843257fb 100644 --- a/doc/04-schema.md +++ b/doc/04-schema.md @@ -316,12 +316,12 @@ Example: } ``` -> **Note:** This feature has severe technical limitations, as the +> **Note:** This feature has severe technical limitations, as the > composer.json metadata will still be read from the branch name you specify > before the hash. You should therefore only use this as a temporary solution > during development to remediate transient issues, until you can switch to > tagged releases. The Composer team does not actively support this feature -> and will not accept bug reports related to it. +> and will not accept bug reports related to it. It is also possible to inline-alias a package constraint so that it matches a constraint that it otherwise would not. For more information [see the @@ -425,10 +425,11 @@ Example: Autoload mapping for a PHP autoloader. -Currently [`PSR-0`](http://www.php-fig.org/psr/psr-0/) autoloading, -[`PSR-4`](http://www.php-fig.org/psr/psr-4/) autoloading, `classmap` generation and -`files` includes are supported. PSR-4 is the recommended way though since it offers -greater ease of use (no need to regenerate the autoloader when you add classes). +[`PSR-4`](http://www.php-fig.org/psr/psr-4/) and [`PSR-0`](http://www.php-fig.org/psr/psr-0/) +autoloading, `classmap` generation and `files` includes are supported. + +PSR-4 is the recommended way since it offers greater ease of use (no need +to regenerate the autoloader when you add classes). #### PSR-4 @@ -599,6 +600,13 @@ Example: } ``` +#### Optimizing the autoloader + +The autoloader can have quite a substantial impact on your request time +(50-100ms per request in large frameworks using a lot of classes). See the +[`article about optimizing the autoloader`](articles/autoloader-optimization.md) +for more details on how to reduce this impact. + ### autoload-dev ([root-only](04-schema.md#root-package)) This section allows to define autoload rules for development purposes. diff --git a/doc/articles/autoloader-optimization.md b/doc/articles/autoloader-optimization.md new file mode 100644 index 000000000..4cf8fa2dd --- /dev/null +++ b/doc/articles/autoloader-optimization.md @@ -0,0 +1,109 @@ + + +# Autoloader Optimization + +By default, the Composer autoloader runs relatively fast. However, due to the way +PSR-4 and PSR-0 autoloading rules are set up, it needs to check the filesystem +before resolving a classname conclusively. This slows things down quite a bit, +but it is convenient in development environments because when you add a new class +it can immediately be discovered/used without having to rebuild the autoloader +configuration. + +The problem however is in production you generally want things to happen as fast +as possible, as you can simply rebuild the configuration every time you deploy and +new classes do not appear at random between deploys. + +For this reason, Composer offers a few strategies to optimize the autoloader. + +## Optimization Level 1: Class map generation + +### How to run it? + +There are a few options to enable this: + +- Set `"optimize-autoloader": true` inside the config key of composer.json +- Call `install` or `update` with `-o` / `--optimize-autoloader` +- Call `dump-autoload` with `-o` / `--optimize` + +### What does it do? + +Class map generation essentially converts PSR-4/PSR-0 rules into classmap rules. +This makes everything quite a bit faster as for known classes the class map +returns instantly the path, and Composer can guarantee the class is in there so +there is no filesystem check needed. + +On PHP 5.6+, the class map is also cached in opcache which improves the initialization +time greatly. If you make sure opcache is enabled, then the class map should load +almost instantly and then class loading is fast. + +### Trade-offs + +There are no real trade-offs with this method. It should always be enabled in +production. + +The only issue is it does not keep track of autoload misses (i.e. when +it can not find a given class), so those fallback to PSR-4 rules and can still +result in slow filesystem checks. To solve this issue two Level 2 optimization +options exist, and you can decide to enable either if you have a lot of +class_exists checks that are done for classes that do not exist in your project. + + +## Optimization Level 2/A: Authoritative class maps + +### How to run it? + +There are a few options to enable this: + +- Set `"classmap-authoritative": true` inside the config key of composer.json +- Call `install` or `update` with `-a` / `--classmap-authoritative` +- Call `dump-autoload` with `-a` / `--classmap-authoritative` + +### What does it do? + +Enabling this automatically enables Level 1 class map optimizations. + +This option is very simple, it says that if something is not found in the classmap, +then it does not exist and the autoloader should not attempt to look on the +filesystem according to PSR-4 rules. + +### Trade-offs + +This option makes the autoloader always returns very quickly. On the flipside it +also means that in case a class is generated at runtime for some reason, it will +not be allowed to be autoloaded. If your project or any of your dependencies does that +then you might experience "class not found" issues in production. Enable this with care. + +> Note: This can not be combined with Level 2/B optimizations. You have to choose one as +> they address the same issue in different ways. + + +## Optimization Level 2/B: APCu cache + +### How to run it? + +There are a few options to enable this: + +- Set `"apcu-autoloader": true` inside the config key of composer.json +- Call `install` or `update` with `--apcu-autoloader` +- Call `dump-autoload` with `--apcu` + +### What does it do? + +This option adds an APCu cache as a fallback for the class map. It will not +automatically generate the class map though, so you should still enable Level 1 +optimizations manually if you so desire. + +Whether a class is found or not, that fact is always cached in APCu so it can be +returned quickly on the next request. + +### Trade-offs + +This option requires APCu which may or may not be available to you. It also +uses APCu memory for autoloading purposes, but it is safe to use and can not +result in classes not being found like the authoritative class map +optimization above. + +> Note: This can not be combined with Level 2/A optimizations. You have to choose one as +> they address the same issue in different ways.