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: 9) |
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 |
|---|
22 Comments
comments.show.hideJul 18, 2008
Bryce Lohr
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.
Also, you state that this will not use spl_autoload_register, yet this line from the class skeleton seems to indicate otherwise:
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?
Dec 17, 2008
Matthew Weier O'Phinney
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).
Dec 17, 2008
Bryce Lohr
Yes, it's much clearer now; thank you!
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?
Dec 17, 2008
Matthew Weier O'Phinney
setFallbackLoader() is a flag to indicate that any 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.
Dec 17, 2008
Rob Allen
It's non-intuitive to use Zend_Loader_Autoloader::getInstance(); to register with spl_autoload. Better would be: Zend_Loader_Autoloader::registerAutoload();
Dec 17, 2008
Matthew Weier O'Phinney
Noted. Thanks!
Dec 17, 2008
Rob Allen
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?
I could equally imagine something like:
$myAutoloader = new My_Autoloader('/path/to/classes', 'My_Stuff');
Zend_Loader::pushAutoloader($myAutoloader);
Dec 17, 2008
Matthew Weier O'Phinney
The idea would be to deprecate Zend_Loader::registerAutoload() in favor of Zend_Loader_Autoloader. (We may even have it proxy to it.)
The benefits are several:
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.
I'd like to keep a clean separation of concerns, which is why we're suggesting a new class.
Dec 17, 2008
Rob Allen
Another question! Why are there namespace related functions here? Surely the instances of Zend_Loader_Autoloader_Interface worry about such things?
Also, if you are going to have a pushAutoloader(), surely you would have a popAutoloader()?
Dec 17, 2008
Matthew Weier O'Phinney
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).
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.
And yes, you're right, there should be popAutoloader and shiftAutoloader methods – I'll update the proposal to reflect that.
Dec 17, 2008
Matthew Weier O'Phinney
Please see my comment to Till below – pop and shift don't make much sense, as you typically need to selectively remove an autoloader, but when adding you need to indicate where in the stack to add it.
Dec 17, 2008
Till Klampaeckel
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.
Dec 17, 2008
Matthew Weier O'Phinney
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 which autoloader to remove, while unshift and push add to the stack, but tell you where to add them. (btw, removeAutoloader() is in the class skeleton)
Dec 17, 2008
Till Klampaeckel
I thought push just adds to the end. No idea how the order is maintained there. From my understanding addAutoloader() would do the same?
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.
But can you detail how Zend_Loader will play a role in this, or aim those proposals to eventually replace Zend_Loader?
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?
Last but not least, can you show code so we can have a look how exactly you're solving the loading part?
Dec 17, 2008
Matthew Weier O'Phinney
re: push: you obviously missed the unshiftAutoloader() method, which prepends to the stack. We could maybe make these "prepend" and "append" instead of "unshift" and "push".
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.
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.
Finally, the References section has a link to code I've developed in the pastebin demo.
Dec 17, 2008
Lars Strojny
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:
Zend_Loader_Autoload::getInstance()
>getStack()>push(new MyAutoLoader());What's the route to forward compatibility with 5.3th namespaces?
Dec 17, 2008
Matthew Weier O'Phinney
The collection object makes sense, though it adds more complexity. That said, I'll definitely consider it.
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.
Dec 17, 2008
Rob Allen
Given that Zend_Loader_Autoload's only point is to be a collection of autoloaders, surely a collection object is redundant?
Dec 18, 2008
Lars Strojny
As far as I understand it, it's the management interface to a collection of autoloaders, not a collection itself.
Jan 08, 2009
Matthew Weier O'Phinney
This proposal is accepted for immediate development in the standard incubator, with the following additions:
Apr 08, 2009
Rick
Sorry, double post.
Apr 08, 2009
Rick
I have 2 questions regarding the following lines of the "getClassAutoloaders" method:
1. Edited: A minor point, but couldn't it be changed to:
2. Having a break; after the first match would exclude other potential namespace matches. Remove the break; and my first point doesn't apply.