Why use a PSR-0 or PSR-4 autoload in composer if classmap is actually faster?

Solution 1:

The problem is that the classmap is NOT actually faster in every case!

The speed of the classmap comes from not having to check the filesystem if a file exists before doing the always necessary work of loading it, parsing it (opcode caches will help here) and then executing it.

But the downside of the classmap is that you possibly generate a huge amount of data for every single class, interface and trait included in the libraries you use, without you actually using it in your production code. Loading huge arrays does not come for free - while the code need not be parsed again and again (opcode cache), it still has to be executed, the array data structure has to be put into memory, filled with lots of strings, and then eats up some amount of memory that might have been usable for something else.

I found two resources discussing this topic: First of all there is github issue #1529 suggesting further improvements for the composer autoloader using a bunch of symlinks to avoid having to scan multiple directories.

The discussion there also reveals that you should actually try to use the best possible namespace- or classname-prefix in the PSR-0 autoload declaration, i.e. the longest one possible. You can also use more than one prefix in the declaration.

Then there is a blog post linked in that issue that documents some xhprof benchmarks using a stock EZPublish 5 and fiddling with the settings, including APC Caching and classmap dumping.

Money quote:

This command created a 662KiB vendor/composer/autoload_classmap.php file containing an array that is a hash composed of the class name as index and the path to the file containing the class definition as value. At the time I am writing this post, this array is composed of 4168 entries. [...] Although it should give us the most efficiant autoloading mechanism, it actually slows things down (from 254.53 reqs/second to 197.95). The reason being that even if the file is cached by APC, the PHP array containing the map with more than 4100 entries needs to be re-created at every single request.

Will a classmap be fast? Certainly. Fastest in every case? Of course not - it depends on the ratio used vs. unused classes per request. So even if on average your application actually uses ALL classes in the map, a classmap might still be slower if you only use about 10% of the classes per request, and you'd be better off optimizing the autoload declarations of the libraries you use. In fact, every classname prefix should only ever point to exactly one directory.

Note that the performance gain you'd achieve only is in the area of about low single digit milliseconds per request. Your application surely is awesome if that figure is a significant performance boost in the range of 5 to 10%. But if you really are in that performance range, blindly believing that a classmap is ALWAYS faster probably wastes a lot of unnecessary CPU cycles.

If you optimize something: Measure it! How would you know if it actually becomes better if you cannot measure it?

Solution 2:

Why use a PSR-0 or PSR-4 autoload in composer if classmap is actually faster?

Because it's more practical.

In production, you can use a classmap (with composer dumpautoload -o) because you won't add any new class, but in dev environment it's interesting to have the flexibility provided by PSR-0 or PSR-4 (i.e. nothing to do when adding new classes).

Update: you can also use composer install -o, it's simpler.

Solution 3:

here's what you'd need to do, if you added/changed classes:

  • classmap: composer dumpautoload (perhaps also update composer.json with a new classmap entry)
  • psr-0: nothing
  • psr-4: nothing

so basically you can go wild with psr-4 and psr-0 without having to worry, whether your newly created class is correctly in the autoloader. plus with it you get a free proper directory structure of your library, that represents your namespace.

autoloader files:

  • classmap: vendor/composer/autoload_classmap.php
  • psr-0: vendor/composer/autoload_namespaces.php
  • psr-4: vendor/composer/autoload_psr4.php

Solution 4:

An important argument here is that using psr-4 or psr-0 in the composer.json forces you to organize your class files following a strict standard. This allows others (or yourself 2 years from now) who look at the composer.json to immediately know where your classes are.

If you do this wrong, e.g. if you misspell a namespace, then you will likely find out during development or in your unit tests due to a "class not found". This is good, because it forces you to fix this.

The classmap is much more forgiving, and will allow any arbitrary organization of class files, leaving the reader in the dark.

So, as others already said: Use psr-4 or psr-0 in the composer.json, work with that during development, and then consider the -o option for production. But measure if this really brings a performance benefit!