I want to autoload php classes and functions. Ideally, I want a lazy loader (include class files only when they are needed, never including more files than necessary). I’d also like namespace protection (if running PHP 5.3 or later). And of course I want to do this easily without having to keep track of hierarchical dependency chains.
PHP provides a magic function called __autoload() which can be leveraged to this end. You can implement __autoload() directly, OR you can use the spl_autoload functions. There is a default spl_autload() that provides namespace support (mapping namespaces to lowercase directories, classname to lowercase filename, and extension to .inc or .php)
Given two namespaces ‘foobar’ and ‘snafoo’; and lowercase filenames representing the class name (e.g., foobar\Foo() class would be located in foobar/foo.php) you could simply use the default spl_autoload() function as follows:
<?php spl_autoload_register(); $foo1 = foobar\Foo(); $foo2 = snafoo\Foo(); ?>
However, I would like my files to match the class names directly, e.g., “class FooBar” should be in a file named “FooBar.php” rather than “foobar.php”.
Also, to support legacy code written in PHP 5.2 and before, I would like the autoloader to search for underscore-based long class names, e.g., “class legacy_snafoo_FooBar” would be located in “legacy/snafoo/FooBar.php”. Prefixing a classname with an underscored-namespace has been an unofficial solution to the lack of PHP namespaces for years.
Fortunately, spl_autoload_register allows you to chain multiple autoload functions, and you can keep the default spl_autoload() at the top of the chain to maintain much faster performance autoloading namespace-based code.
Here is a custom autoload implementation with namespace support, legacy long-classname suppport, as well as honoring multiple file extensions. Note the use of a closure requires PHP 5.3
<?php /* * Custom autoload callback * * maintains spl_autoload_extensions */ function delimiter_autoload ($delimiter) { return function($className) use ($delimiter) { $extensions = explode(',', spl_autoload_extensions()); foreach($extensions as $ext) { $classFile = str_replace($delimiter,DIRECTORY_SEPARATOR,$className) . $ext; if (is_file($classFile)) { include_once($classFile); break; } } }; } /* * register autload functions */ spl_autoload_extensions('.php,.inc,.class.php,.lib,.lib.php'); spl_autoload_register(); spl_autoload_register(delimiter_autoload('\\')); spl_autoload_register(delimiter_autoload('_')); ?>
The actual application code is now free to instantiate based on any namespace or legacy classname (using the underscore-approach), e.g.,
<?php $foo1 = foobar\Foo(); $foo2 = snafoo\Foo(); $oldfoo = legacy_foobar_Foo(); ?>