Some legacy applications may already have a custom autoloader in place. If this is our situation, we have some options:
Other legacy codebases may have a third-party autoloader in place, such as Composer. If Composer is present, we can obtain its autoloader instance and add our central class directory location for autoloading like so:
1 <?php 2 // get the registered Composer autoloader instance from the vendor/ 3 // subdirectory 4 $loader = require '/path/to/app/vendor/autoload.php'; 5 6 // add our central class directory location; do not use a class prefix as 7 // we may have more than one top-level namespace in the central location 8 $loader->add('', '/path/to/app/classes'); 9 ?>
With that, we can co-opt Composer for our own purposes, making our own autoloader code unnecessary.
There is some reason to think that using autoloaders may cause a slight performance drag compared to using include
, but the evidence is mixed and situation-dependent. If it is true that autoloading is comparatively slower, how big of a performance hit can be expected?
I assert that, when modernizing a legacy application, it is probably not an important consideration. Any performance drag incurred from autoloading is minuscule compared to the other possible performance issues in your legacy application, such as the database interactions.
In most legacy applications, or even in most modern ones, attempting to optimize performance on autoloading is a case of attempting to optimize on the wrong resource. There are other resources that are likely to be worse offenders, just ones that we don't see or don't think of.
If autoloading is the single worst performance bottleneck in your legacy application, then you are in fantastic shape. (In that case, you should return this book for a refund, and then tell me if you are hiring, because I want to work for you.)
The PSR-0 rules can be confusing. Here are some class-to-file mapping examples to illustrate its expectations:
Foo => Foo.php Foo_Bar => Foo/Bar.php Foo => Foo/Bar.php Foo_Bar\Bar => Foo_Bar/Baz.php Foo\Bar\Baz => Foo/Bar/Baz.php # ??? Foo\Baz_Bar => Foo/Bar/Baz.php # ??? Foo_Bar_Baz => Foo/Bar/Baz.php # ???
We can see that there is some unexpected behavior in the last three examples. This is born of the transitional nature of PSR-0: Foo\Bar\Baz, Foo\Bar_Baz
, and Foo_Bar_Baz
all map to the same file. Why is this?
Recall that pre-PHP-5.3 codebases did not have namespaces, and so used underscores as a pseudo-namespace separator. PHP 5.3 introduced a real namespace separator. The PSR-0 standard had to accommodate both cases simultaneously, so it honors underscores in the relative class name (i.e., the final part of the fully-qualified name) as directory separators, but underscores in the namespace part are left alone.
The lesson here is that if you are on PHP 5.3, you should never use underscores in your relative class names (although underscores in the namespace are fine). If you are on a version before PHP 5.3, you have no choice but to use only underscores, as there is only the class name and no actual namespace portion; interpret underscores as namespace separators in that case.