Support for advanced autoloader optimizations for Composer
Currently, the buildpack always enable level-1 optimizations for the autoloader. This is good, and should not be configurable (there is no drawback to using the level 1, unless you delete files containing class definitions and then check them for class_exists, but this has no reason to happen in production as the source code should not get deleted without a build).
However, there is no way to enable level-2 optimizations: https://getcomposer.org/doc/articles/autoloader-optimization.md
Such optimizations need to be configurable, as both level-2 optimizations are mutually exclusive with different tradeoffs. But it would be great to be able to enable such level-2 optimizations in projects
Is it not enough that the level 2 optimizations can be enabled in the config section of composer.json?
No, because this would also enable them in your development environment, and this would totally break the development experience (having to run composer dump-autoload locally each time you add a new class is a no-go).
There are 2 good places to enable them:
- using the CLI option
- in the
configsection of the system-wide config of the build server (which we cannot control either on heroku).
@dzuelke any plan to allow this ?
What do you think a good flag would be? I am a little wary of a blanket COMPOSER_INSTALL_ARGS or something, as people will inevitably do wild stuff with it...
Well, if you expose an env variable allowing to specify arbitrary composer args, COMPOSER_INSTALL_ARGS looks like the best name :smile:
If you expose only an env variable telling the buildpack to pass specific args, a suggestion could be COMPOSER_ADVANCED_AUTOLOAD=classmap|apcu|none, where classmap would enable the classmap-authoritative flag, apcu would enable the --apcu-autoloader one (and force the installation of APCu ?) and none would not enable any level 2 autoloading optimization (the --optimize-autoloader flag should always be enabled as there is no reason to turn off the level 1 optimization in production)
a more explicit name would be COMPOSER_ADVANCED_AUTOLOAD_OPTIMIZATION, but that starts being long.
What if we made the Heroku global config default to true for both level 1 (https://getcomposer.org/doc/articles/autoloader-optimization.md#optimization-level-1-class-map-generation) and level 2A (https://getcomposer.org/doc/articles/autoloader-optimization.md#optimization-level-2-a-authoritative-class-maps), and if users have specific code that breaks with that, they can set "classmap-authoritative": false in their composer.json? That's something they should do anyway in there if the code is not compatible with that optimization level, right?
well, using the heroku global config might make sense indeed.
Can you help me understand levels 2/A and 2/B, @stof... the docs say they're mutually exclusive, but looking at the code, it appears you can enable both at the same time? There is even a test that checks for that (testClassMapAutoloadingAuthoritativeAndApcu).
And APCu is only used at runtime if the ext is enabled, so customers who do enable it would get that optimization as well.
We could enable all three by default, and customers with 2/A incompatibilities (unlikely on Heroku, but hey) can the disable it in their composer.json without negatively affecting their dev env.
Right?
Well, enabling both at the same time does not make much sense actually. If you enable the classMapAuthoritative mode (2/A), the code will stop executing before ever reaching the place where the APCu caching of not found classes is used: https://github.com/composer/composer/blob/4301c19ce3b2468ad841ca9f5f35ca5558fb005f/src/Composer/Autoload/ClassLoader.php#L341
Enabling the 2/A optimization through global config might indeed work, as project-level config would allow overwriting it. And then, enabling 2/B as a fallback for people disabling 2/A might indeed make sense. It would have no impact for most people.
@dzuelke any progress on that front ?
+1 would still be nice to have this