[Solar-talk] Proposal: Remove namespace to Solar::loadClass()/factory()
Travis Swicegood
development at domain51.com
Tue Nov 7 07:35:45 PST 2006
Howdy all,
One thing in Solar that's been bugging me is the concrete class
dependencies that it has. Code like this makes me cringe:
$sql = Solar::factory('Solar_Sql');
My whole problem with it is that it creates a dependency on Solar_Sql
and keeps me to inserting my own Domain51_Sql code. My solution, as
Paul has heard many (he would add "many, many" I believe) times is some
sort of Dependency Injection model where you don't request the class,
but it's interface. Paul's not a fan of this model, and it is
definitely more esoteric and probably not the easiest to grok. I have,
however, come up with a model that I think will work quite well and is a
step in that direction: namespaces.
$sql = Solar::factory('Sql');
Currently, the Solar_Controller_Front allows you to specify via a config
value the "classes" that it will search. What I'm proposing is that
Solar::loadClass() start using its config['namespaces'] to load classes
in a similar manner. loadClass() would also need to start returning the
name of the class that it found.
The reasoning for this is my work on the Domain51_Service_* classes the
last few weeks. Those are classes I would definitely like to see in
Solar, however anything I do with them right now requests the objects as:
$s3 = Solar::factory('Domain51_Service_Amazon_S3');
This is fine, until they make it to Solar. If they do, all of my apps
are going to be obsoleted unless I maintain dual versions of the Service
code or change all of my factory() calls. If the code were as follows
instead, I wouldn't have anything to change:
$s3 = Solar::factory('Service_Amazon_S3');
This is a step toward a DI-type system, without a change to
__construct() for full on Constructor Injection (a la PicoContainer).
This keeps Solar::loadClass() working as a Service Locator, but
introduces real namespaces by removing them from the the requests.
Obviously, I would like to see Interfaces introduced so you can always
verify that the methods you need will always be available regardless of
what object comes back, but that's not an immediate need for this
particular change.
== Required code changes ==
To make this change happen - three things need to be done. The first,
and obvious is the change to loadClass(). It has to be able to know
about its namespaces, apply them, and catch exceptions when the file
isn't found instead of throwing them again. It also needs to return the
name of the real file that it expects. That leads to a change I didn't
foresee - throwing an exception in Solar::run() would cause an issue
with namespacing because Solar::exception() relies on the loadClass()
functionality. You quickly hit an infinite loop that way on the first
namespace. I've changed it to allow you to throw a regular exception,
but it could easily throw Solar_Exception since Solar should always know
exactly where it is. The last change that needs to be made is the
factory() method. It needs to know which class to instantiate, so that
changes to instantiate the class based on what loadClass() returns.
There's another change in there that I found out (and is recorded in
issue 30 on Trac). Asking for a config value via Solar::config() that
was false would return null even if a default value was provided. This
is used with a check against 'bc_compat:namespaces' to allow this code
to work with the old style names by stripping the Vendor_ portion off of
the requested class.
The attached patch works without issue with all of the Solar demo code.
If you specify the following config values, it will work with any
Solar-based code without modification thanks to the bc_compat:namespaces
setting.
$config['Solar']['namespaces'] = array(
'Solar',
'VendorOne',
'VendorTwo',
'Domain51' // cause everyone uses my code, right? ;-)
);
Anyhow, this email has become long enough. Thoughts, comments,
suggestions? Am I the only one that sees value in removing the
namespace from the requested code?
-Travis
P.S. I wrote the majority of this email yesterday, but let it sit
through the night to see if I thought of anything else. One additional
change I think might be useful is to change the signature of loadClass() to:
public function loadClass($class, $concrete = false)
By specifying "true" as the second parameter, you could override the
namespace code. This would be necessary for sub-classes that need to
insure the specific super-class they expect is loaded.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: namespaces.patch
Type: text/x-patch
Size: 4043 bytes
Desc: not available
Url : http://mail.killersoft.com/pipermail/solar-talk/attachments/20061107/3a5c2a7b/attachment.bin
More information about the solar-talk
mailing list