Page 1 of 1

MORE class interaction

Posted: Mon Jun 19, 2006 4:29 pm
by Luke
Alright, this is the third thread I have started about this, but I was reading the original thread I posted about class interaction and the idea of a registry caught my attention. I sort of understand the concept, but would like maybe a further explanation. Here is the piece of code that caught my attention. I am horrible at asking questions, so feel free to let me know that.
Maugrim wrote:

Code: Select all

class DBConnect
{
    function DBConnect()
    {
        // connect to database and a whole host of other functions
    }
}

class SimpleRegistry
{

        var $instances;

        function register($name, &$object) {
                $this->instances[$name] = $object;
        }

        function get($name) {
                return $this->instances[$name];
        }

}

class MyClass
{
    var $db;
    function MyClass(&$registry)
    {
        $this->db = $registry->get('dbconn');
    }
}

$registry = new SimpleRegistry();
$dbconn = new DBConnect();
$registry->register('dbconn', $dbconn);
$myclass = new MyClass($registry);

Posted: Mon Jun 19, 2006 5:19 pm
by Christopher
I mention it occasionally, a lot of what you want to do is available in the Skeleton codebase I maintain. It is all PHP4 code and is centered around a Registry/Service Locator like the simple one you just posted. It is not a framework so there is no particular conventions for its use and it allows just about any kind naming or directory layout. Feel free to use as little or as much (or any ideas) as you like, as it is meant to be a example of using controllers in PHP.

The codebase is very controller-centric and provides Front, Form and Application Controllers. There are examples included with the code.

The code is here: http://ap3.sourceforge.net/

Specifically to your question, the registry is injected into every controller's constructor and the dispatched execute()/run() method so whatever objects you want to make available can be put there. This is Service Locator style Constructor Injection.

To do Access Control, you can register a method name with the Front Controller that will be called if it exists. This is PHP trick to do simple Interface Injection. It can be used for Access Control by registering a denyAccess() security method with the Front Controller. If a dispatched controller implements that method it will be run before the dispatched method and can short-circuit what is dispatched with a new action or an action registered with the injected method.

Posted: Mon Jun 19, 2006 5:21 pm
by Luke
I will need a little while to digest everything you just said, but thank you. This is all very interesting.

Posted: Mon Jun 19, 2006 5:37 pm
by Christopher
If you need specific examples, let me know. If you are new to controller architectures it can be hard to keep track of all the balls in the air. ;)

Posted: Mon Jun 19, 2006 5:41 pm
by Maugrim_The_Reaper
I suppose explaining the problem it (may) provides a solution for.

Let's say you have a class which interacts at some level with several others. Now the number of classes that are required could be an arbitrary number. Typical approach is to require the classes, and instantiate them as needed. This could be by instantiating them outside the class, and them "injecting" them somehow (maybe the constructor or a init() method) or instantiating inside the class. In either case you have a small problem.

The class has developed a dependency on these classes, since it knows both their class names, requires them as paramaters, or suddenly has responsibility for instantiating them. On the face of it, the class works fine. Problem is dependencies will need to be carried forward for re-use or else the class will need future editing to enable changed dependencies. This is fine when talking about one class - now apply it across a few dozen. See the molehill turning into a mountain? There's also a testing dilemma - how to test a class which insists on instantiating external objects in defiance of our need to manipulate those same classes via stubs, mocks or some other alternative. The problem list grows, that mole is mutating.

The first solution, is to remove the instantiation from the class. Do it elsewhere and pass the dependencies into the object via the constructor. This solves the instantiation issue, but adds another. Who's going to remember our growing parameter list, it's order, etc. Will we need to do this for every instantiation? When we change the paramater list, will we have to edit all those instantiation lines across the application?

Remove one potential problem, and we find another.

This eventually leads us the quartet of possible solutions - we need to avoid:

a) instantiating objects inside the class (it can still be done, but our unit testing will become a nightmare)
b) passing a potentially changing list of parameters to all instantiation events

The quartet of possible solutions?

1. Singletons!
2. A Registry
3. ServiceLocator
4. Dependency Injection

Singletons can help avoid parameter lists - but it's merely replacing the in-class instantiation. We would need to add some extra wiring to facilitate testing, and well, singletons are a bit like Globals.

A Registry does away with a long parameter list, and it can jump the Singleton issue a little. Just register the dependencies to the Registry, and pass it into the class as a parameter (no more long hard to remember parameter list), or we can make the Registry a Singleton itself and call it from the class constructor with the parameter option left open to facilitate testing. This is the commonly used option...

A ServiceLocator does a similar job to the Registry, but in addition it takes control of finding, including, and finally instantiating classes. It can help reduce all those include calls littered everywhere in the code (and we all know they can wind up anywhere :)).

Dependency Injection is another step up the ladder - and I have never seen a real PHP example outside a theoretical discussion.

To sum up the ramble (hoping it makes sense because I'm speed typing) - Registry/ServiceLocator try to solve the problem of getting dependencies into a class in such a way that it makes testing simple, avoids long parameter lists (hard to remember, easy to make mistakes with), narrows the dependencies by concealing (not always possible - but often) the class name so classes of varying types with the same interface are acceptable, lets developers worry about more important things and cuts down on maintenance due to dependency changes (edit one class, not every occurance of the "new" keyword!).

Someone else's turn to cut in now...

Posted: Mon Jun 19, 2006 5:49 pm
by Christopher
That is a really excellent description of both the problems and solutions that are important here.

Posted: Mon Jun 19, 2006 6:25 pm
by Ambush Commander
Agreed. However, dependency injection does exist: http://www.lastcraft.com/partial_mocks_ ... tation.php

Posted: Mon Jun 19, 2006 6:47 pm
by Luke
arborint wrote:The code is here: http://ap3.sourceforge.net/
Very cool! Thank you... this is a great start for me. I am finally wrapping my head around all this stuff.

Posted: Mon Jun 19, 2006 6:49 pm
by Maugrim_The_Reaper
I'm not arguing it doesn't exist. There's a PHP port of Pico, and another effort called Garden. It's just that dep injection doesn't seem quite as needed as badly in PHP compared to say, Java. That's a personal perspective so don't take it as absolute truth - it's still a reasonably recent topic in PHP which I've only seen gathering momentum in the past year. Largely, a Registry or ServiceLocator serve most needs where a DI container would just feel overkill.

Even a ServiceLocator is still hard to pin down in PHP with a concrete example (though Sitepoint carries some great threads on the topic) - I've seen SL named classes which rarely get further than a Registry with some ad-hoc instantiation code attached. I had a stab at creating such a class for a small project which still needs work (need to get factory calls integrated, among other things) but works for simple cases...which is really all I need.

Class: http://svn.sourceforge.net/viewcvs.cgi/ ... iew=markup
Unit Tests: http://svn.sourceforge.net/viewcvs.cgi/ ... iew=markup

Posted: Mon Jun 19, 2006 7:17 pm
by Christopher
Though I would less call a real example -- and more a means lastcraft is using to achieve a end. It is however based on some of lastcraft's work on DI in his phemto library.
The Ninja Space Goat wrote:Very cool! Thank you... this is a great start for me. I am finally wrapping my head around all this stuff.
Feel free to ask me specific questions if you need clarification about the what's and why's of that code.

Posted: Mon Jun 19, 2006 8:42 pm
by Luke
arborint wrote:Though I would less call a real example -- and more a means lastcraft is using to achieve a end. It is however based on some of lastcraft's work on DI in his phemto library.
The Ninja Space Goat wrote:Very cool! Thank you... this is a great start for me. I am finally wrapping my head around all this stuff.
Feel free to ask me specific questions if you need clarification about the what's and why's of that code.
Alright thank you very much for all your help