# The Autoloader

`Zend_Loader_Autoloader` introduces a comprehensive autoloading solution for Zend Framework. It has been designed with several goals in mind:

- Provide a true namespace autoloader. (Previous incarnations intercepted all userland namespaces.)

- Allow registering arbitrary callbacks as autoloaders, and manage them as a stack. (At the time of this writing, this overcomes some issues with `spl_autoload`, which does not allow re-registering a callback that utilizes an instance method.)

- Allow optimistic matching of namespaces to provide faster class resolution.

`Zend_Loader_Autoloader` implements a singleton, making it unversally accessible. This provides the ability to register additional autoloaders from anywhere in your code as necessary.

## Using the Autoloader

The first time an instance of the autoloader is retrieved, it registers itself with `spl_autoload`. You retrieve an instance using the `getInstance()` method:

    $autoloader = Zend_Loader_Autoloader::getInstance();

By default, the autoloader is configured to match the "Zend_" and "ZendX_" namespaces. If you have your own library code that uses your own namespace, you may register it with the autoloader using the `registerNamespace()` method. For instance, if your library code is prefixed with "My_", you could do so as follows:

    $autoloader->registerNamespace('My_');

### Namespace Prefixes

You'll note that the previous example uses "My_" and not "My". This is because `Zend_Loader_Autoloader` is intended as a general purpose autoloader, and does not make the assumption that a given class prefix namespace includes an underscore. If your class namespace does include one, you should include it when registering your namespace.

You can also register arbitrary autoloader callbacks, optionally with a specific namespace (or group of namespaces). `Zend_Loader_Autoloader` will attempt to match these first before using its internal autoloading mechanism.

As an example, you may want to utilize one or more eZcomponents components with your Zend Framework application. To use its autoloading capabilities, push it onto the autoloader stack using `pushAutoloader()`:

    $autoloader->pushAutoloader(array('ezcBase', 'autoload'), 'ezc');

This tells the autoloader to use the eZcomponents autoloader for classes beginning with "ezc".

You can use the `unshiftAutoloader()` method to add the autoloader to the beginning of the autoloader chain.

By default, `Zend_Loader_Autoloader` does no error suppression when using its internal autoloader, which utilizes `Zend_Loader::loadClass()`. Most of the time, this is exactly what you want. However, there may be cases where you want to suppress them. You can do this using `suppressNotFoundWarnings()`:

    $autoloader->suppressNotFoundWarnings(true);

Finally, there may be times when you want the autoloader to load any namespace. For instance, PEAR libraries do not share a common namespace, making specifying individual namespaces difficult when many PEAR components are in use. You can use the `setFallbackAutoloader()` method to have the autoloader act as a catch-all:

    $autoloader->setFallbackAutoloader(true);

### Loading Classes from PHP Namespaces

Starting in version 1.10.0, Zend Framework now allows loading classes from PHP namespaces. This support follows the same guidelines and implementation as that found in the PHP Framework Interop Group PSR-0 reference implementation.

Under this guideline, the following rules apply:

- Each namespace separator is converted to a `DIRECTORY_SEPARATOR` when loading from the file system.

- Each "_" character in the CLASS NAME is converted to a `DIRECTORY_SEPARATOR`. The "_" character has no special meaning in the namespace.

- The fully-qualified namespace and class is suffixed with ".php" when loading from the file system.

As examples:

- `\Doctrine\Common\IsolatedClassLoader` => `/path/to/project/lib/vendor/Doctrine/Common/IsolatedClassLoader.php`

- `\namespace\package\Class_Name` => `/path/to/project/lib/vendor/namespace/package/Class/Name.php`

- `\namespace\package_name\Class_Name` => `/path/to/project/lib/vendor/namespace/package_name/Class/Name.php`

## Selecting a Zend Framework version

Typically, you will use the version of Zend Framework that the autoloader you instantiate came with. However, when developing a project, it's often useful to track specific versions, major or minor branches, or just the latest version. `Zend_Loader_Autoloader`, as of version 1.10, offers some features to help manage this task.

Imagine the following scenario:

- During development, you want to track the latest version of Zend Framework you have installed, so that you can ensure the application works when you upgrade between versions.

  When pushing to Quality Assurance, however, you need to have slightly more stability, so you want to use the latest installed revision of a specific minor version.

  Finally, when you push to production, you want to pin to a specific installed version, to ensure no breakage occurs if or when you add new versions of Zend Framework to you server.

The autoloader allows you to do this with the method `setZfPath()`. This method takes two arguments, a path to a set of Zend Framework installations, and a version to use. Once invoked, it prepends a path to the `include_path` pointing to the appropriate Zend Framework installation library.

The directory you specify as your path should have a tree such as the following:

    ZendFramework/
    |-- 1.9.2/
    |   |-- library/
    |-- ZendFramework-1.9.1-minimal/
    |   |-- library/
    |-- 1.8.4PL1/
    |   |-- library/
    |-- 1.8.4/
    |   |-- library/
    |-- ZendFramework-1.8.3/
    |   |-- library/
    |-- 1.7.8/
    |   |-- library/
    |-- 1.7.7/
    |   |-- library/
    |-- 1.7.6/
    |   |-- library/

(where path points to the directory "ZendFramework" in the above example)

Note that each subdirectory should contain the directory `library`, which contains the actual Zend Framework library code. The individual subdirectory names may be version numbers, or simply be the untarred contents of a standard Zend Framework distribution tarball/zipfile.

Now, let's address the use cases. In the first use case, in development, we want to track the latest source install. We can do that by passing "latest" as the version:

    $autoloader->setZfPath($path, 'latest');

In the example from above, this will map to the directory `ZendFramework/1.9.2/library/`; you can verify this by checking the return value of `getZfPath()`.

In the second situation, for quality assurance, let's say we want to pin to the 1.8 minor release, using the latest install you have for that release. You can do so as follows:

    $autoloader->setZfPath($path, '1.8');

In this case, it will find the directory `ZendFramework/1.8.4PL1/library/`.

In the final case, for production, we'll pin to a specific version -- 1.7.7, since that was what was available when Quality Assurance tested prior to our release.

    $autoloader->setZfPath($path, '1.7.7');

Predictably, it finds the directory `ZendFramework/1.7.7/library/`.

You can also specify these values in the configuration file you use with `Zend_Application`. To do so, you'd specify the following information:

    [production]
    autoloaderZfPath = "path/to/ZendFramework"
    autoloaderZfVersion = "1.7.7"

    [qa]
    autoloaderZfVersion = "1.8"

    [development]
    autoloaderZfVersion = "latest"

Note the different environment sections, and the different version specified in each environment; these factors will allow `Zend_Application` to configure the autoloader appropriately.

### Performance implications

For best performance, either do not use this feature, or specify a specific Zend Framework version (i.e., not "latest", a major revision such as "1", or a minor revision such as "1.8"). Otherwise, the autoloader will need to scan the provided path for directories matching the criteria -- a somewhat expensive operation to perform on each request.

## The Autoloader Interface

Besides being able to specify arbitrary callbacks as autoloaders, Zend Framework also defines an interface autoloading classes may imlement, `Zend_Loader_Autoloader_Interface`:

    interface Zend_Loader_Autoloader_Interface
    {
        public function autoload($class);
    }

When using this interface, you can simply pass a class instance to `Zend_Loader_Autoloader`'s `pushAutoloader()` and `unshiftAutoloader()` methods:

    // Assume Foo_Autoloader implements Zend_Loader_Autoloader_Interface:
    $foo = new Foo_Autoloader();

    $autoloader->pushAutoloader($foo, 'Foo_');

## Autoloader Reference

Below, please find a guide to the methods available in `Zend_Loader_Autoloader`.

### Zend_Loader_Autoloader Methods

Method | Return Value | Parameters | Description
--- | --- | --- | ---
`getInstance()` | `Zend_Loader_Autoloader` | N/A | Retrieve the `Zend_Loader_Autoloader` singleton instance. On first retrieval, it registers itself with `spl_autoload`. This method is static.
`resetInstance()` | `void` | N/A | Resets the state of the `Zend_Loader_Autoloader` singleton instance to it's original state, unregistering all autoloader callbacks and all registered namespaces.

`autoload($class)`

`string|`FALSE``

- `$class`, required. A string class name to load.

Attempt to resolve a class name to a file and load it.

`setDefaultAutoloader($callback)`

`Zend_Loader_Autoloader`

- `$callback`, required.

Specify an alternate PHP callback to use for the default autoloader implementation.

`getDefaultAutoloader()` | `callback` | N/A | Retrieve the default autoloader implementation; by default, this is `Zend_Loader::loadClass()`.

`setAutoloaders(array $autoloaders)`

`Zend_Loader_Autoloader`

- `$autoloaders`, required.

Set a list of concrete autoloaders to use in the autoloader stack. Each item in the autoloaders array must be a PHP callback.

`getAutoloaders()` | Array | N/A | Retrieve the internal autoloader stack.

`getNamespaceAutoloaders($namespace)`

Array

- `$namespace`, required

Fetch all autoloaders that have registered to load a specific namespace.

`registerNamespace($namespace)`

`Zend_Loader_Autoloader`

- `$namespace`, required.

Register one or more namespaces with the default autoloader. If `$namespace` is a string, it registers that namespace; if it's an array of strings, registers each as a namespace.

`unregisterNamespace($namespace)`

`Zend_Loader_Autoloader`

- `$namespace`, required.

Unregister one or more namespaces from the default autoloader. If `$namespace` is a string, it unregisters that namespace; if it's an array of strings, unregisters each as a namespace.

`getRegisteredNamespaces()` | Array | N/A | Returns an array of all namespaces registered with the default autoloader.

`suppressNotFoundWarnings($flag = null)`

`boolean|Zend_Loader_Autoloader`

- `$flag`, optional.

Set or retrieve the value of the flag used to indicate whether the default autoloader implementation should suppress "file not found" warnings. If no arguments or a `NULL` value is passed, returns a boolean indicating the status of the flag; if a boolean is passed, the flag is set to that value and the autoloader instance is returned (to allow method chaining).

`setFallbackAutoloader($flag)`

`Zend_Loader_Autoloader`

- `$flag`, required.

Set the value of the flag used to indicate whether or not the default autoloader should be used as a fallback or catch-all autoloader for all namespaces.

`isFallbackAutoloader()` | Boolean | N/A | Retrieve the value of the flag used to indicate whether or not the default autoloader should be used as a fallback or catch-all autoloader for all namespaces. By default, this is `FALSE`.

`getClassAutoloaders($class)`

Array

- `$class`, required.

Get the list of namespaced autoloaders that could potentially match the provided class. If none match, all global (non-namespaced) autoloaders are returned.

`unshiftAutoloader($callback, $namespace = '')`

`Zend_Loader_Autoloader`

- `$callback`, required. A valid PHP callback

- `$namespace`, optional. A string representing a class prefix namespace.

Add a concrete autoloader implementation to the beginning of the internal autoloader stack. If a namespace is provided, that namespace will be used to match optimistically; otherwise, the autoloader will be considered a global autoloader.

`pushAutoloader($callback, $namespace = '')`

`Zend_Loader_Autoloader`

- `$callback`, required. A valid PHP callback

- `$namespace`, optional. A string representing a class prefix namespace.

Add a concrete autoloader implementation to the end of the internal autoloader stack. If a namespace is provided, that namespace will be used to match optimistically; otherwise, the autoloader will be considered a global autoloader.

`removeAutoloader($callback, $namespace = '')`

`Zend_Loader_Autoloader`

- `$callback`, required. A valid PHP callback

- `$namespace`, optional. A string representing a class prefix namespace, or an array of namespace strings.

Remove a concrete autoloader implementation from the internal autoloader stack. If a namespace or namespaces are provided, the callback will be removed from that namespace or namespaces only.