Skip to end of metadata
Go to start of metadata

<ac:macro ac:name="unmigrated-inline-wiki-markup"><ac:plain-text-body><![CDATA[

<ac:macro ac:name="unmigrated-inline-wiki-markup"><ac:plain-text-body><![CDATA[

Zend Framework: Zend_Loader_Autoloader Component Proposal

Proposed Component Name Zend_Loader_Autoloader
Developer Notes http://framework.zend.com/wiki/display/ZFDEV/Zend_Loader_Autoloader
Proposers Ralph Schindler
Matthew Weier O'Phinney
Zend Liaison Matthew Weier O'Phinney
Revision 1.0 - 1 January 2008: Initial Draft.
1.1 - 17 December 2008: Initial Draft. (wiki revision: 10)

Table of Contents

1. Overview

Zend_Loader_Autoloader is a component for autoloading registered namespaces & managing arbitrary autoload callbacks.

2. References

3. Component Requirements, Constraints, and Acceptance Criteria

  • This component will register itself with spl_autoload
  • This component will autoload the Zend and ZendX namespaces by default
  • This component will allow registration of arbitrary namespaces that follow ZF/PEAR/Horde coding standards
  • This component will allow itself to optionally act as a fallback autoloader for arbitrary namespaces
  • This component will allow registering arbitrary autoload callbacks
    • This component will maintain an internal registry of these callbacks
    • This component will call these autoloaders itself
  • This component will provide a flag to toggle suppression of class loading errors
    • The class loading error suppression flag will default to off (i.e., no suppression)

4. Dependencies on Other Framework Components

  • Zend_Exception
  • Zend_Loader

5. Theory of Operation

The component is available for use by applications that might use multiple autoloaders (for example modules that might require the use of a custom autoloader).

Problems this autoloader attempts to solve:

  • Ability to autoload only specific namespaces
  • Ability to handle arbitrary autoload callbacks. spl_autoload is problematic to manipulate when using object instance methods
  • Ability to manage the ordering of the autoloader stack

6. Milestones / Tasks

  • Milestone 1: [DONE] Requirements written and published as a proposal
  • Milestone 2: [DONE] Working prototype checked into a public repository supporting the use cases
  • Milestone 3: Community review of proposal
  • Milestone 4: Acceptance of proposal
  • Milestone 5: Unit tests exist, work, and are checked into icubator
  • Milestone 6: Initial documentation exists
  • Milestone 7: Approval for trunk

7. Class Index

  • Zend_Loader_Autoloader
  • Zend_Loader_Autoloader_Interface

8. Use Cases

UC-01

Standard usage; no extra libraries:

UC-02

Register additional namespaces:

UC-03

Register an arbitrary autoloader callback:

UC-04

Use the autoloader interface to define an autoloader, and register an instance with the global autoloader.

UC-05

Suppress warnings.

UC-06

Use autoloader as a fallback autoloader (i.e., will load any namespace):

9. Class Skeletons

Zend_Loader_Autoloader
Zend_Loader_Autoloader_Interface

]]></ac:plain-text-body></ac:macro>

]]></ac:plain-text-body></ac:macro>

Labels:
None
Enter labels to add to this page:
Please wait 
Looking for a label? Just start typing.
  1. Jul 18, 2008

    <p>Could you provide a little more background on the problems this component solves? Even with the descriptions present, I still don't understand the benefit this is trying to bring.</p>

    <p>Also, you state that this will <strong>not</strong> use <code>spl_autoload_register</code>, yet this line from the class skeleton seems to indicate otherwise:</p>
    <ac:macro ac:name="code"><ac:plain-text-body><![CDATA[
    // autoload method to be registered with php's spl_autoload_register
    public function autoload($class);
    ]]></ac:plain-text-body></ac:macro>

    <p>Is this meant as a user-land tool, or for internal framework use? ZF itself doesn't currently use autoload; does this proposal indicate a change in direction on that?</p>

    1. Dec 17, 2008

      <p>Hopefully the changes to the proposal now answer your questions. We will be using spl_autoload_register to register Zend_Loader_Autoloader::autoload(), but then have Z_L_A maintain its own registry of autoloaders. The rationale behind it is to simplify the process of registering autoloaders, but also to work around deficiencies in spl_autoload (which often has trouble when re-registering instance methods as callbacks).</p>

      1. Dec 17, 2008

        <p>Yes, it's much clearer now; thank you!</p>

        <p>Also, shouldn't setFallbackLoader() be a setter for an arbitrary fallback loader, rather than a flag? Or am I just misunderstanding what it's about?</p>

        1. Dec 17, 2008

          <p>setFallbackLoader() is a flag to indicate that <em>any</em> namespace can be matched by the autoloader. For instance, if you're using PEAR, you may want to enable this as PEAR doesn't currently enforce a top-level namespace.</p>

  2. Dec 17, 2008

    <p>It's non-intuitive to use Zend_Loader_Autoloader::getInstance(); to register with spl_autoload. Better would be: Zend_Loader_Autoloader::registerAutoload();</p>

    1. Dec 17, 2008

      <p>Noted. Thanks!</p>

  3. Dec 17, 2008

    <p>How does this relate to Zend_Loader? Or more specifically, what is the benefit of having Zend_Loader::registerAutoload() and Zend_Loader_Autoloader? Can the registry of autoloaders be added to Zend_Loader? Will Zend_Loader's registerAutoload() be deprecated?</p>

    <p>I could equally imagine something like:<br />
    $myAutoloader = new My_Autoloader('/path/to/classes', 'My_Stuff');<br />
    Zend_Loader::pushAutoloader($myAutoloader);</p>

    1. Dec 17, 2008

      <p>The idea would be to deprecate Zend_Loader::registerAutoload() in favor of Zend_Loader_Autoloader. (We may even have it proxy to it.)</p>

      <p>The benefits are several:</p>

      <ul>
      <li>Better error handling capabilities. This has been a constant issue with using Zend_Loader::registerAutoload(), as some people want to have parse errors bubble up, and others don't want warnings when files aren't found (as they have other autoloaders that can map the class to a file). By having a central autoloader registry, we can make this <strong>much</strong> cleaner.</li>
      <li>Ability to restrict which namespaces are in use. (Leads to faster lookups, and also ensures that developers are explicit about selecting third party libraries for use with their application. That said, we allow it to act as a fallback handler, too.)</li>
      <li>Zend_Loader_Autoloader would use Zend_Loader::loadClass() internally. However, this keeps a separation of concerns: one has a mechanism for loading classes and files, the other performs autoloading and handles an autoloader registry.</li>
      </ul>

      <p>Finally, as noted in the proposal, this also works around issues we've noticed with spl_autoload_register when used with arbitrary instance method callbacks.</p>

      <ac:macro ac:name="code"><ac:plain-text-body><![CDATA[
      > I could equally imagine something like:
      > $myAutoloader = new My_Autoloader('/path/to/classes', 'My_Stuff');
      > Zend_Loader::pushAutoloader($myAutoloader);
      ]]></ac:plain-text-body></ac:macro>

      <p>I'd like to keep a clean separation of concerns, which is why we're suggesting a new class.</p>

  4. Dec 17, 2008

    <p>Another question! Why are there namespace related functions here? Surely the instances of Zend_Loader_Autoloader_Interface worry about such things?</p>

    <p>Also, if you are going to have a pushAutoloader(), surely you would have a popAutoloader()?</p>

    1. Dec 17, 2008

      <p>There's no reason to have a separate autoloader for each namespace when the implementation is the same. The motivation is to speed up lookups and prevent unnecessary lookups (if the namespace isn't in the list, just return false immediately instead of trying to load a file).</p>

      <p>Autoloaders implementing the interface will be used for custom autoloading – such as with the resource autoloader – where there is not a 1:1 class/filename relation.</p>

      <p>And yes, you're right, there should be popAutoloader and shiftAutoloader methods – I'll update the proposal to reflect that.</p>

      1. Dec 17, 2008

        <p>Please see my comment to Till below – pop and shift don't make much sense, as you typically need to <em>selectively</em> remove an autoloader, but when adding you need to indicate <em>where</em> in the stack to add it.</p>

  5. Dec 17, 2008

    <p>I don't like the push* method names. I know they come from array_push and array_pop, but most other components in the framework use addFoo() and removeFoo() style method names.</p>

    1. Dec 17, 2008

      <p>The problem with using add/remove is that with autoloading, we actually need to maintain a stack to ensure order – you need to be able to specify which autoloaders have precedence. I'm actually thinking unshift/push are all we need, as remove would allow you to choose <strong>which</strong> autoloader to remove, while unshift and push add to the stack, but tell you <strong>where</strong> to add them. (btw, removeAutoloader() <strong>is</strong> in the class skeleton)</p>

      1. Dec 17, 2008

        <p>I thought push just adds to the end. No idea how the order is maintained there. From my understanding addAutoloader() would do the same?</p>

        <p>I find it somewhat confusing with all the autoload goodness offered by the framework already. E.g. I think Zend_Loader has multiple methods that revolve around autoload'ing - point taken some parts are hard to fit into it so I see (and read) what you're trying to solve here.</p>

        <p>But can you detail how Zend_Loader will play a role in this, or aim those proposals to eventually replace Zend_Loader? </p>

        <p>Also how many autoloaders will I typically need for an app? E.g. for controllers, models, forms, library. An autoload for each one of them?</p>

        <p>Last but not least, can you show code so we can have a look how exactly you're solving the loading part?</p>

        1. Dec 17, 2008

          <p>re: push: you obviously missed the unshiftAutoloader() method, which <em>prepends</em> to the stack. We could maybe make these "prepend" and "append" instead of "unshift" and "push".</p>

          <p>Zend_Loader has two methods related to autoloading. autoload() is the actual callback used for autoloading, and registerAutoload() registers with spl_autoload(). The idea is to deprecate these and move autoloading into its own class. In the short term, registerAutoload() would actually register Zend_Loader_Autoloader, and Zend_Loader::autoload() would receive a deprecation notice.</p>

          <p>As for how many autoloaders would you need: one per module in most cases. Take a look at the Resource autoloader proposal, as it shows the proposed implementation. </p>

          <p>Finally, the References section has a link to code I've developed in the pastebin demo.</p>

  6. Dec 17, 2008

    <p>Two things: first, I'm not sure if the API should be cluttered with stuff dealing with the internal stack of autoloaders. Maybe having a separate collection object for autoloaders and using it in the following way fits better:</p>

    <p>Zend_Loader_Autoload::getInstance()<span style="text-decoration: line-through;">>getStack()</span>>push(new MyAutoLoader());</p>

    <p>What's the route to forward compatibility with 5.3th namespaces?</p>

    1. Dec 17, 2008

      <p>The collection object makes sense, though it adds more complexity. That said, I'll definitely consider it.</p>

      <p>As for 5.3 namespaces, we'll address that more in the coming months, but both Zend_Loader and this component will need some minor changes to facilitate usage with 5.3. We need a final API on namespaces before we even consider doing so – and even though namespaces are considered a "done deal" for 5.3, until there's a beta out, the API can change.</p>

      1. Dec 17, 2008

        <p>Given that Zend_Loader_Autoload's only point is to be a collection of autoloaders, surely a collection object is redundant?</p>

        1. Dec 18, 2008

          <p>As far as I understand it, it's the management interface to a collection of autoloaders, not a collection itself.</p>

  7. Jan 08, 2009

    <ac:macro ac:name="note"><ac:parameter ac:name="title">Zend Acceptance Criteria</ac:parameter><ac:rich-text-body>
    <p>This proposal is accepted for immediate development in the standard incubator, with the following additions:</p>
    <ul>
    <li>A Collection object (most likely an SplStack) should be used for handling the autoloaders</li>
    <li>Autoloaders should allow optionally specifying a namespace prefix. The implementation should then attempt to match namespace prefixes with specific autoloaders, and try only those autoloaders when attempting to find a match.</li>
    </ul>
    </ac:rich-text-body></ac:macro>

  8. Apr 08, 2009

    <p>Sorry, double post.</p>

  9. Apr 08, 2009

    <p>I have 2 questions regarding the following lines of the "getClassAutoloaders" method:</p>
    <ac:macro ac:name="code"><ac:plain-text-body><![CDATA[
    foreach (array_keys($this->_namespaceAutoloaders) as $ns) {
    if ('' == $ns)

    Unknown macro: { continue; }

    if (0 === strpos($class, $ns))

    Unknown macro: { $namespace = $ns; $autoloaders = $autoloaders + $this->getNamespaceAutoloaders($ns); break; }

    }
    ]]></ac:plain-text-body></ac:macro>

    <p>1. Edited: A minor point, but couldn't it be changed to:</p>
    <ac:macro ac:name="code"><ac:plain-text-body><![CDATA[
    $autoloaders = $this->getNamespaceAutoloaders($ns);
    ]]></ac:plain-text-body></ac:macro>

    <p>2. Having a break; after the first match would exclude other potential namespace matches. Remove the break; and my first point doesn't apply.</p>