<?xml version="1.0" encoding="UTF-8"?>
<!-- Reviewed: no -->
<sect1 id="zend.loader.autoloader">
    <title>The Autoloader</title>

    <para>
        <classname>Zend_Loader_Autoloader</classname> introduces a comprehensive
        autoloading solution for Zend Framework. It has been designed with
        several goals in mind:
    </para>

    <itemizedlist>
        <listitem>
            <para>
                Provide a true namespace autoloader. (Previous incarnations
                intercepted all userland namespaces.)
            </para>
        </listitem>

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

        <listitem>
            <para>
                Allow optimistic matching of namespaces to provide faster class resolution.
            </para>
        </listitem>
    </itemizedlist>

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

    <sect2 id="zend.loader.autoloader.usage">
        <title>Using the Autoloader</title>

        <para>
            The first time an instance of the autoloader is retrieved, it
            registers itself with <code>spl_autoload</code>. You retrieve an
            instance using the <methodname>getInstance()</methodname> method:
        </para>

        <programlisting language="php"><![CDATA[
$autoloader = Zend_Loader_Autoloader::getInstance();
]]></programlisting>

        <para>
            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 <methodname>registerNamespace()</methodname> method. For instance, if your
            library code is prefixed with "My_", you could do so as follows:
        </para>

        <programlisting language="php"><![CDATA[
$autoloader->registerNamespace('My_');
]]></programlisting>

        <note>
            <title>Namespace Prefixes</title>

            <para>
                You'll note that the previous example uses "My_" and not "My".
                This is because <classname>Zend_Loader_Autoloader</classname> 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 <emphasis>does</emphasis>
                include one, you should include it when registering your
                namespace.
            </para>
        </note>

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

        <para>
            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
            <methodname>pushAutoloader()</methodname>:
        </para>

        <programlisting language="php"><![CDATA[
$autoloader->pushAutoloader(array('ezcBase', 'autoload'), 'ezc');
]]></programlisting>

        <para>
            This tells the autoloader to use the eZcomponents autoloader for
            classes beginning with "ezc".
        </para>

        <para>
            You can use the <methodname>unshiftAutoloader()</methodname> method to add the
            autoloader to the beginning of the autoloader chain.
        </para>

        <para>
            By default, <classname>Zend_Loader_Autoloader</classname> does no error
            suppression when using its internal autoloader, which utilizes
            <methodname>Zend_Loader::loadClass()</methodname>. 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
            <methodname>suppressNotFoundWarnings()</methodname>:
        </para>

        <programlisting language="php"><![CDATA[
$autoloader->suppressNotFoundWarnings(true);
]]></programlisting>

        <para>
            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
            <methodname>setFallbackAutoloader()</methodname> method to have the autoloader
            act as a catch-all:
        </para>

        <programlisting language="php"><![CDATA[
$autoloader->setFallbackAutoloader(true);
]]></programlisting>

        <note>
            <title>Loading Classes from PHP Namespaces</title>

            <para>
                Starting in version 1.10.0, Zend Framework now allows loading classes from
                <acronym>PHP</acronym> namespaces. This support follows the same guidelines and
                implementation as that found in the <ulink
                    url="http://groups.google.com/group/php-standards/web/psr-0-final-proposal">PHP
                Framework Interop Group PSR-0</ulink> reference implementation.
            </para>

            <para>
                Under this guideline, the following rules apply:
            </para>

            <itemizedlist>
                <listitem>
                    <para>
                        Each namespace separator is converted to a
                        <constant>DIRECTORY_SEPARATOR</constant> when loading from the file system.
                    </para>
                </listitem>

                <listitem>
                    <para>
                        Each "_" character in the <emphasis>CLASS NAME</emphasis> is converted to a
                        <constant>DIRECTORY_SEPARATOR</constant>. The "_" character has no special
                        meaning in the namespace.
                    </para>
                </listitem>

                <listitem>
                    <para>
                        The fully-qualified namespace and class is suffixed with ".php" when loading
                        from the file system.
                    </para>
                </listitem>
            </itemizedlist>

            <para>
                As examples:
            </para>

            <itemizedlist>
                <listitem>
                    <para>
                        <classname>\Doctrine\Common\IsolatedClassLoader</classname> =&gt;
                        <filename>/path/to/project/lib/vendor/Doctrine/Common/IsolatedClassLoader.php</filename>
                    </para>
                </listitem>

                <listitem>
                    <para>
                        <classname>\namespace\package\Class_Name</classname> =&gt;
                        <filename>/path/to/project/lib/vendor/namespace/package/Class/Name.php</filename>
                    </para>
                </listitem>

                <listitem>
                    <para>
                        <classname>\namespace\package_name\Class_Name</classname> =&gt;
                        <filename>/path/to/project/lib/vendor/namespace/package_name/Class/Name.php</filename>
                    </para>
                </listitem>
            </itemizedlist>
        </note>
    </sect2>

    <sect2 id="zend.loader.autoloader.zf-version">
        <title>Selecting a Zend Framework version</title>

        <para>
            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.
            <classname>Zend_Loader_Autoloader</classname>, as of version 1.10, offers some features
            to help manage this task.
        </para>

        <para>
            Imagine the following scenario:
        </para>

        <itemizedlist>
            <listitem>
                <para>
                    During <emphasis>development</emphasis>, 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.
                </para>

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

                <para>
                    Finally, when you push to <emphasis>production</emphasis>, 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.
                </para>
            </listitem>
        </itemizedlist>

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

        <para>
            The directory you specify as your <emphasis>path</emphasis> should have a tree such as
            the following:
        </para>

        <programlisting language="text"><![CDATA[
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/
]]></programlisting>

        <para>
            (where <emphasis>path</emphasis> points to the directory "ZendFramework" in the above
            example)
        </para>

        <para>
            Note that each subdirectory should contain the directory <filename>library</filename>,
            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.
        </para>

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

        <programlisting language="php"><![CDATA[
$autoloader->setZfPath($path, 'latest');
]]></programlisting>

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

        <para>
            In the second situation, for <emphasis>quality assurance</emphasis>, 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:
        </para>

        <programlisting language="php"><![CDATA[
$autoloader->setZfPath($path, '1.8');
]]></programlisting>

        <para>
            In this case, it will find the directory
            <filename>ZendFramework/1.8.4PL1/library/</filename>.
        </para>

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

        <programlisting language="php"><![CDATA[
$autoloader->setZfPath($path, '1.7.7');
]]></programlisting>

        <para>
            Predictably, it finds the directory <filename>ZendFramework/1.7.7/library/</filename>.
        </para>

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

        <programlisting language="ini"><![CDATA[
[production]
autoloaderZfPath = "path/to/ZendFramework"
autoloaderZfVersion = "1.7.7"

[qa]
autoloaderZfVersion = "1.8"

[development]
autoloaderZfVersion = "latest"
]]></programlisting>

        <para>
            Note the different environment sections, and the different version specified in each
            environment; these factors will allow <classname>Zend_Application</classname> to
            configure the autoloader appropriately.
        </para>

        <warning>
            <title>Performance implications</title>

            <para>
                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.
            </para>
        </warning>
    </sect2>

    <sect2 id="zend.loader.autoloader.interface">
        <title>The Autoloader Interface</title>

        <para>
            Besides being able to specify arbitrary callbacks as autoloaders,
            Zend Framework also defines an interface autoloading classes may
            imlement, <classname>Zend_Loader_Autoloader_Interface</classname>:
        </para>

        <programlisting language="php"><![CDATA[
interface Zend_Loader_Autoloader_Interface
{
    public function autoload($class);
}
]]></programlisting>

        <para>
            When using this interface, you can simply pass a class instance to
            <classname>Zend_Loader_Autoloader</classname>'s
            <methodname>pushAutoloader()</methodname>
            and <methodname>unshiftAutoloader()</methodname> methods:
        </para>

        <programlisting language="php"><![CDATA[
// Assume Foo_Autoloader implements Zend_Loader_Autoloader_Interface:
$foo = new Foo_Autoloader();

$autoloader->pushAutoloader($foo, 'Foo_');
]]></programlisting>
    </sect2>

    <sect2 id="zend.loader.autoloader.reference">
        <title>Autoloader Reference</title>

        <para>
            Below, please find a guide to the methods available in
            <classname>Zend_Loader_Autoloader</classname>.
        </para>

        <table id="zend.loader.autoloader.reference.api">
            <title>Zend_Loader_Autoloader Methods</title>

            <tgroup cols="4">
                <thead>
                    <row>
                        <entry>Method</entry>
                        <entry>Return Value</entry>
                        <entry>Parameters</entry>
                        <entry>Description</entry>
                    </row>
                </thead>

                <tbody>
                    <row>
                        <entry><methodname>getInstance()</methodname></entry>
                        <entry><classname>Zend_Loader_Autoloader</classname></entry>
                        <entry>N/A</entry>

                        <entry>
                            <para>
                                Retrieve the <classname>Zend_Loader_Autoloader</classname>
                                singleton instance. On first retrieval, it registers
                                itself with <code>spl_autoload</code>. This method is static.
                            </para>
                        </entry>
                    </row>

                    <row>
                        <entry><methodname>resetInstance()</methodname></entry>
                        <entry><code>void</code></entry>
                        <entry>N/A</entry>

                        <entry>
                            <para>
                                Resets the state of the
                                <classname>Zend_Loader_Autoloader</classname> singleton instance to
                                it's original state, unregistering all autoloader callbacks and all
                                registered namespaces.
                            </para>
                        </entry>
                    </row>

                    <row>
                        <entry><methodname>autoload($class)</methodname></entry>
                        <entry><code>string|<constant>FALSE</constant></code></entry>

                        <entry>
                            <itemizedlist>
                                <listitem>
                                    <para>
                                        <varname>$class</varname>, <emphasis>required</emphasis>.
                                        A string class name to load.
                                    </para>
                                </listitem>
                            </itemizedlist>
                        </entry>

                        <entry>
                            <para>Attempt to resolve a class name to a file and load it.</para>
                        </entry>
                    </row>

                    <row>
                        <entry><methodname>setDefaultAutoloader($callback)</methodname></entry>
                        <entry><classname>Zend_Loader_Autoloader</classname></entry>

                        <entry>
                            <itemizedlist>
                                <listitem>
                                    <para>
                                        <varname>$callback</varname>, <emphasis>required</emphasis>.
                                    </para>
                                </listitem>
                            </itemizedlist>
                        </entry>

                        <entry>
                            <para>
                                Specify an alternate <acronym>PHP</acronym> callback to use for the
                                default autoloader implementation.
                            </para>
                        </entry>
                    </row>

                    <row>
                        <entry><methodname>getDefaultAutoloader()</methodname></entry>
                        <entry><code>callback</code></entry>
                        <entry>N/A</entry>

                        <entry>
                            <para>
                                Retrieve the default autoloader implementation; by default, this is
                                <methodname>Zend_Loader::loadClass()</methodname>.
                            </para>
                        </entry>
                    </row>

                    <row>
                        <entry><methodname>setAutoloaders(array $autoloaders)</methodname></entry>
                        <entry><classname>Zend_Loader_Autoloader</classname></entry>

                        <entry>
                            <itemizedlist>
                                <listitem>
                                    <para>
                                        <varname>$autoloaders</varname>,
                                        <emphasis>required</emphasis>.
                                    </para>
                                </listitem>
                            </itemizedlist>
                        </entry>

                        <entry>
                            <para>
                                Set a list of concrete autoloaders to use in the
                                autoloader stack. Each item in the autoloaders array
                                must be a <acronym>PHP</acronym> callback.
                            </para>
                        </entry>
                    </row>

                    <row>
                        <entry><methodname>getAutoloaders()</methodname></entry>
                        <entry><type>Array</type></entry>
                        <entry>N/A</entry>
                        <entry><para>Retrieve the internal autoloader stack.</para></entry>
                    </row>

                    <row>
                        <entry><methodname>getNamespaceAutoloaders($namespace)</methodname></entry>
                        <entry><type>Array</type></entry>

                        <entry>
                            <itemizedlist>
                                <listitem>
                                    <para>
                                        <varname>$namespace</varname>, <emphasis>required</emphasis>
                                    </para>
                                </listitem>
                            </itemizedlist>
                        </entry>

                        <entry>
                            <para>
                                Fetch all autoloaders that have registered to load a
                                specific namespace.
                            </para>
                        </entry>
                    </row>

                    <row>
                        <entry><methodname>registerNamespace($namespace)</methodname></entry>
                        <entry><classname>Zend_Loader_Autoloader</classname></entry>

                        <entry>
                            <itemizedlist>
                                <listitem>
                                    <para>
                                        <varname>$namespace</varname>,
                                        <emphasis>required</emphasis>.
                                    </para>
                                </listitem>
                            </itemizedlist>
                        </entry>

                        <entry>
                            <para>
                                Register one or more namespaces with the default
                                autoloader. If <varname>$namespace</varname> is a string,
                                it registers that namespace; if it's an array of
                                strings, registers each as a namespace.
                            </para>
                        </entry>
                    </row>

                    <row>
                        <entry><methodname>unregisterNamespace($namespace)</methodname></entry>
                        <entry><classname>Zend_Loader_Autoloader</classname></entry>

                        <entry>
                            <itemizedlist>
                                <listitem>
                                    <para>
                                        <varname>$namespace</varname>,
                                        <emphasis>required</emphasis>.
                                    </para>
                                </listitem>
                            </itemizedlist>
                        </entry>

                        <entry>
                            <para>
                                Unregister one or more namespaces from the default
                                autoloader. If <varname>$namespace</varname> is a string,
                                it unregisters that namespace; if it's an array of
                                strings, unregisters each as a namespace.
                            </para>
                        </entry>
                    </row>

                    <row>
                        <entry><methodname>getRegisteredNamespaces()</methodname></entry>
                        <entry><type>Array</type></entry>
                        <entry>N/A</entry>

                        <entry>
                            <para>
                                Returns an array of all namespaces registered with the default
                                autoloader.
                            </para>
                        </entry>
                    </row>

                    <row>
                        <entry>
                            <methodname>suppressNotFoundWarnings($flag = null)</methodname>
                        </entry>

                        <entry><code>boolean|Zend_Loader_Autoloader</code></entry>

                        <entry>
                            <itemizedlist>
                                <listitem>
                                    <para>
                                        <varname>$flag</varname>, <emphasis>optional</emphasis>.
                                    </para>
                                </listitem>
                            </itemizedlist>
                        </entry>

                        <entry>
                            <para>
                                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 <constant>NULL</constant> 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).
                            </para>
                        </entry>
                    </row>

                    <row>
                        <entry><methodname>setFallbackAutoloader($flag)</methodname></entry>
                        <entry><classname>Zend_Loader_Autoloader</classname></entry>

                        <entry>
                            <itemizedlist>
                                <listitem>
                                    <para>
                                        <varname>$flag</varname>, <emphasis>required</emphasis>.
                                    </para>
                                </listitem>
                            </itemizedlist>
                        </entry>

                        <entry>
                            <para>
                                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.
                            </para>
                        </entry>
                    </row>

                    <row>
                        <entry><methodname>isFallbackAutoloader()</methodname></entry>
                        <entry><type>Boolean</type></entry>
                        <entry>N/A</entry>
                        <entry>
                            <para>
                                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 <constant>FALSE</constant>.
                            </para>
                        </entry>
                    </row>

                    <row>
                        <entry><methodname>getClassAutoloaders($class)</methodname></entry>
                        <entry><type>Array</type></entry>

                        <entry>
                            <itemizedlist>
                                <listitem>
                                    <para>
                                        <varname>$class</varname>, <emphasis>required</emphasis>.
                                    </para>
                                </listitem>
                            </itemizedlist>
                        </entry>

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

                    <row>
                        <entry>
                            <methodname>unshiftAutoloader($callback, $namespace = '')</methodname>
                        </entry>

                        <entry><classname>Zend_Loader_Autoloader</classname></entry>

                        <entry>
                            <itemizedlist>
                                <listitem>
                                    <para>
                                        <varname>$callback</varname>, <emphasis>required</emphasis>.
                                        A valid <acronym>PHP</acronym> callback
                                    </para>
                                </listitem>

                                <listitem>
                                    <para>
                                        <varname>$namespace</varname>,
                                        <emphasis>optional</emphasis>. A string representing a class
                                        prefix namespace.
                                    </para>
                                </listitem>
                            </itemizedlist>
                        </entry>

                        <entry>
                            <para>
                                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.
                            </para>
                        </entry>
                    </row>

                    <row>
                        <entry>
                            <methodname>pushAutoloader($callback, $namespace = '')</methodname>
                        </entry>
                        <entry><classname>Zend_Loader_Autoloader</classname></entry>

                        <entry>
                            <itemizedlist>
                                <listitem>
                                    <para>
                                        <varname>$callback</varname>, <emphasis>required</emphasis>.
                                        A valid <acronym>PHP</acronym> callback
                                    </para>
                                </listitem>

                                <listitem>
                                    <para>
                                        <varname>$namespace</varname>,
                                        <emphasis>optional</emphasis>. A string representing a class
                                        prefix namespace.
                                    </para>
                                </listitem>
                            </itemizedlist>
                        </entry>

                        <entry>
                            <para>
                                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.
                            </para>
                        </entry>
                    </row>

                    <row>
                        <entry>
                            <methodname>removeAutoloader($callback, $namespace = '')</methodname>
                        </entry>

                        <entry><classname>Zend_Loader_Autoloader</classname></entry>

                        <entry>
                            <itemizedlist>
                                <listitem>
                                    <para>
                                        <varname>$callback</varname>, <emphasis>required</emphasis>.
                                        A valid <acronym>PHP</acronym> callback
                                    </para>
                                </listitem>

                                <listitem>
                                    <para>
                                        <varname>$namespace</varname>,
                                        <emphasis>optional</emphasis>. A string representing a class
                                        prefix namespace, or an array of namespace strings.
                                    </para>
                                </listitem>
                            </itemizedlist>
                        </entry>

                        <entry>
                            <para>
                                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.
                            </para>
                        </entry>
                    </row>
                </tbody>
            </tgroup>
        </table>
    </sect2>
</sect1>
