Extending Zend_Controller_Router_Route: the singleton problem.
Today I ran into an issue while extending Zend_Controller_Router_Route. I wanted to add a little path pre/post processing in the match() and assemble() methods, so I just extended the Route class to add my tiny bits of code into the methods. Except it did not work at all. After a few debuging, it turned out that the Router uses Zend_Controller_Router_Route::getInstance() to retrieve a route object, which uses a new self(); statement to instantiate the route object. Problem is that self always refers to the current class definition we're in, if the method is called from a child class, without being overloaded, self will refer to the wrong class.
Example:
[php]
class Foo {
public static function getInstance() {
return new self;
}
}
class Bar extends Foo {}
var_dump(Bar::getClass());
echoes something like:
object(Foo)#1 (0) {
}
Which is fscking wrong IMHO. A quick workaround is to overload the getInstance method, which is what I call pretty annoying as it does not follow the DRY principle.
Comments
Rather than doing that, perhaps you should just define the route to use in the bootstrap with setRoute. That has worked pretty well for me.
Something along the lines of...
Zend_Controller_Front::getInstance()->getRouter()->setRoute('default', new Route_Win());
This will be possible in PHP 5.3 with the Late Static Binding (cf. http://ds-o.com/archives/53-Late-St...)
oh good news :-)
Can't we just change the getInstance() method with a factory() method instead ? We will place this factory() in the parent abstract class, so all "routes" should be generated from it. This factory method will keep one instance per class, so when asked twice or more times for an instance of a class previously loaded, it will return the one it has stored.
To do this, we got to have a common abstract class that all routes will extend. In this abstract class we will place this factory() method like this:
Zend_Controller_Router_Route_Abstract::factory('Xend_Controller_Router_Route_Modified');
What do you think ?
Kaloyan: well that would work for sure, but that is actually not the point of this article :-) This issue will (hopefuly) be solved with php 5.3 and late static binding, which will allow for such a behavior via the static keyword. (see JMF's comment)