SitePoint Sponsor

User Tag List

Page 1 of 2 12 LastLast
Results 1 to 25 of 39
  1. #1
    ********* Victim lastcraft's Avatar
    Join Date
    Apr 2003
    Location
    London
    Posts
    2,423
    Mentioned
    2 Post(s)
    Tagged
    0 Thread(s)

    The smallest dependency injector?

    Hi.

    As a result of an article for PHP|Architect I have finally gotten a chance to play with dependency injection and the result is called "Phemto". It's the bare minimum of a dependency injector as I understand it. I am sure that I have missed some vital feature that Jason, et al. will tell me about. It only works with PHP5.

    Here is a sample piece of usage...
    PHP Code:
    class Datacash implements PaymentGateway { ... }

    class 
    PayementInAdvance implements SignUpProcess {
        function 
    __construct(PaymentGateway $gateway) { ... }
        ...
    }

    $injector = new Injector();
    $injector->register('Datacash');
    $injector->register('PaymentInAdvance');

    $sign_up $injector->create('SignUpProcess'); 
    That is the wiring can be done purely by interfaces and is handled by typed constructors. As usual when I post code on the forum, it's a plaything that anyone is welcome to carry forward. Idon't advise using it in the real world though .

    yours, Marcus
    Attached Files Attached Files
    Marcus Baker
    Testing: SimpleTest, Cgreen, Fakemail
    Other: Phemto dependency injector
    Books: PHP in Action, 97 things

  2. #2
    SitePoint Guru
    Join Date
    Nov 2002
    Posts
    841
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    So what is the killer app for a dependency injection container in PHP. (versus manual dependency injection.)

    I can't give you any more rep, Marcus.

  3. #3
    ********* Victim lastcraft's Avatar
    Join Date
    Apr 2003
    Location
    London
    Posts
    2,423
    Mentioned
    2 Post(s)
    Tagged
    0 Thread(s)
    Hi...

    Quote Originally Posted by Selkirk
    So what is the killer app for a dependency injection container in PHP.
    I have absolutely no idea .

    Given that a PHP "program" is just a small slice of the application, the construction needs shouldn't be that great, right? No need for complicated wiring and all that? Well, I now have a kind of half idea that I may have been missing out on something.

    The injector seems to be of most use for wiring up large chunks of application when the authors of these chunks are constantly changing their dependencies on each other. By giving each other interfaces (or writing adapters) you can gather together say a catalog, a store backend and a shopping cart without having to see the actual code at all. You don't have to see the constructors of these objects either and thus you know nothing of their dependencies as long as you can satisfy each one on demand.

    Because of the constructor passing, the components don't know anything about the injector either, they just have to follow the rules for that injector. In the case of Phemto, everything in the constructor with a type hint.

    Is this any use? I have no idea. I have never tried it or yet needed to.

    It's currently just a curiosity to me. To make it useful in a real program anyway, you would have to add Injector::registerAsSingleton() and, especially for PHP, Injector::registerAsSession(). I would also want to allow superclass specifications, rather than just interfaces, for completeness. It's currently only 50 lines of code after all.

    I do have a vague feeling it could be useful...

    yours, Marcus
    Marcus Baker
    Testing: SimpleTest, Cgreen, Fakemail
    Other: Phemto dependency injector
    Books: PHP in Action, 97 things

  4. #4
    Non-Member
    Join Date
    Jan 2003
    Posts
    5,748
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Off Topic:

    I can't give you any more rep, Marcus.


    But I can

  5. #5
    SitePoint Wizard silver trophy kyberfabrikken's Avatar
    Join Date
    Jun 2004
    Location
    Copenhagen, Denmark
    Posts
    6,157
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    the code looks impressively clean. i still haven't completely understood what the use for dependency injections is, but well ... seems to be a common problem though ?

  6. #6
    SitePoint Guru dbevfat's Avatar
    Join Date
    Dec 2004
    Location
    ljubljana, slovenia
    Posts
    684
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Nice work, although it's not very clear to me, why if you register two classes (that implement the same interface) and then create the interface, you get the latter one. I mean, I see why it works like that, since in the register method, a class is saved in the hash with the interface name, so the latter class 'overrides' the former. What I don't understand is, why is it so? Does it have to be like that? Is constructing a class by passing the interface name to the injector usable at all?

    Regards,
    f

  7. #7
    SitePoint Wizard Ren's Avatar
    Join Date
    Aug 2003
    Location
    UK
    Posts
    1,060
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by dbevfat
    Nice work, although it's not very clear to me, why if you register two classes (that implement the same interface) and then create the interface, you get the latter one. I mean, I see why it works like that, since in the register method, a class is saved in the hash with the interface name, so the latter class 'overrides' the former. What I don't understand is, why is it so? Does it have to be like that? Is constructing a class by passing the interface name to the injector usable at all?

    Regards,
    f
    I think your only meant to register only one implementation of any given interface.

    Think I'd remove the dynamic code building/eval(), using ReflectionClass::newInstance()

    $reflection = new ReflectionClass($class);
    $object = call_user_func_array(array($relection, 'newInstance'), $objects);

    Wouldn't this also need recursion protection, if a class deeper the construction depended on something higher? Probably shouldn't happen in a well designed application, but it'd be good to make sure.

  8. #8
    Non-Member
    Join Date
    Jan 2003
    Posts
    5,748
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Yer, I have a hard time following this as well, but maybe someone can gleam something more from this image I've attached?

    I've proberly had the need for this but not realised it myself, what I could do with is more examples... Hint, hint

  9. #9
    ********* Victim lastcraft's Avatar
    Join Date
    Apr 2003
    Location
    London
    Posts
    2,423
    Mentioned
    2 Post(s)
    Tagged
    0 Thread(s)
    Hi...

    Quote Originally Posted by kyberfabrikken
    the code looks impressively clean. i still haven't completely understood what the use for dependency injections is, but well ... seems to be a common problem though ?
    Funnily, the more I am aware of it, the more (potentially) useful it seems to become. Take this hypothetical example. I have a class, that I'll call Gateway, that is created in a complicated web page that I want to test. I am using a web tester for this test, so mocking it out is not an option. I would like to use a server stub though to emulate behaviour for the rest of the script. Trouble is this runs in a separate process than the test, so how to get the stub in?

    Suppose the test script does this...
    PHP Code:
    // At top...
    $injector = new Injector();
    $injector->register('Gateway');

    // Later on...
    $injector = new Injector();
    $gateway $injector->create('Gateway'); 
    That's the hook in place. Now suppose that in the web test we make this call...
    PHP Code:
    class TestOfGatewayPage extends WebTestCase {
        function 
    testStubbedOutGateway() {
            
    $this->get('stub_gateway_registration.php');
            
    $this->get('gateway_page.php');
            ...
        }

    In the stub registration page we have...
    PHP Code:
    $injector = new Injector();
    $injector->registerInSession('StubGateway''gateway_stub.php');
    $injector->create('Gateway'); 
    And in gateway_stub.php we have...
    PHP Code:
    class StubGateway implements Gateway {
        ...

    If the search order is to look for session objects first, then the StubGateway will fill the dependency first in the live script.

    Probably not a good example, but I do get the feeling that there is something to the DI stuff after all. I'm still groping. Other lifecycle options might be shared memory, or even automatic stubbing for the trick above. It's the way the lifecycle is defines outside of the client code which is the other half of the DI puzzle I think.

    yours, Marcus

    p.s. that is "Dependency Injection", not "Dependency Inversion" .
    Marcus Baker
    Testing: SimpleTest, Cgreen, Fakemail
    Other: Phemto dependency injector
    Books: PHP in Action, 97 things

  10. #10
    Non-Member
    Join Date
    Jan 2003
    Posts
    5,748
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    What? They're not the same then?

  11. #11
    SitePoint Addict
    Join Date
    May 2003
    Location
    Calgary, Alberta, Canada
    Posts
    275
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by lastcraft
    Funnily, the more I am aware of it, the more (potentially) useful it seems to become.
    Im pretty skeptical about dependency injection containers (Would that or things like Pico be called a container?). I can see where it could be very usefull for the reasons already mentioned however it seems to me there are some big hurdles to using one.

    Object creation isnt as simple as laid out in most DI examples. Usually creation of objects is hidden behind some sort of creational method. This means as already mentioned that the Injector would need to be a singleton (Kind of goes against the entire DI priciple ) or passed into the object (Dont really like this idea either as it dirties the interface).

    On top of being hidden behind factories objects are rarely constructed like this:
    PHP Code:
    $object = new Object(new ObjectB(), new ObjectC(new Object D())); 
    They are constructed using objects that have been built during the process of the script. They use request variables, configuration file variables, etc in their construction parameters.

    For some reason the idea seems to break down and become more trouble than its worth. I could be and hope Im wrong though, because the theory behind it should enable you to make dependency changes much easier, and thats always good.

  12. #12
    ********* Victim lastcraft's Avatar
    Join Date
    Apr 2003
    Location
    London
    Posts
    2,423
    Mentioned
    2 Post(s)
    Tagged
    0 Thread(s)
    Hi...

    Quote Originally Posted by Brenden Vickery
    They are constructed using objects that have been built during the process of the script. They use request variables, configuration file variables, etc in their construction parameters.
    This stuff is for top level components only. You would not create the low level objects this way. You still need all of those AbstractFactories, Registries and Builders, etc for most of the code.

    Does anyone have any experience using DI tools? Everyone (me included) seems to be judging something that we have no personal experience of .

    yours, Marcus
    Marcus Baker
    Testing: SimpleTest, Cgreen, Fakemail
    Other: Phemto dependency injector
    Books: PHP in Action, 97 things

  13. #13
    SitePoint Addict
    Join Date
    May 2003
    Location
    Calgary, Alberta, Canada
    Posts
    275
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by lastcraft
    Does anyone have any experience using DI tools? Everyone (me included) seems to be judging something that we have no personal experience of .
    Im guilty . I have no experience using one. Hopefully we will all get a chance to use Pawel's port of pico soon though.

  14. #14
    SitePoint Enthusiast
    Join Date
    Jan 2005
    Location
    Sydney
    Posts
    43
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    I think it would be good in a system, where there may be a range of objects that focus on one task, run pretty much the same, but are different in their naming.

    So instead of going through all of your code, you could just write two or three lines in the beginning that would create a register for say a class to communicate with the database.

    This would also make it easier if someone had set up a pgsql and mysql class, but didn't write them in a way that they we're easily swapped with a configuration setting. Although the example isn't that good it does show when it can be a good thing to use something like DI.

    I don't really see it in a situation where you change the dependency and this also breaks the code. But that's just my take on it.

  15. #15
    SitePoint Guru
    Join Date
    Nov 2002
    Posts
    841
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by dylanegan
    So instead of going through all of your code, you could just write two or three lines in the beginning that would create a register for say a class to communicate with the database.
    This is an interesting "dependency injection" like pattern that keeps cropping up in various MVC frameworks, where one will stuff a database connection into the request object in an intercepting filter. See this thread:

    Global filters are good for setting up database objects, for example. You perform all the code to connect to the database and instantiate a db connection object. The way you get this to your Actions is by putting it in the $request object in the filter and retrieving it in your actions (see $request->setAttributeByRef(), $request->setAttribute() and $request->getAttribute()).
    This seems like a type of dependency injection to me.

  16. #16
    eschew sesquipedalians silver trophy sweatje's Avatar
    Join Date
    Jun 2003
    Location
    Iowa, USA
    Posts
    3,749
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by Selkirk
    This is an interesting "dependency injection" like pattern that keeps cropping up in various MVC frameworks, where one will stuff a database connection into the request object in an intercepting filter.
    Ewwww! And "keeps cropping up" implies you have seen this more than once?!?

    Quote Originally Posted by Brenden Vickery
    On top of being hidden behind factories objects are rarely constructed like this:
    PHP Code:
    $object = new Object(new ObjectB(), new ObjectC(new Object D())); 
    No...but it could be I think the DI pattern may make you want to put your thinking cap on a little askew. Whereas when you are coding up things by hand, passing in to many different objects in the constructor is a bit of a pain, but when you ask for an object, which as another object which was constructed with two other objects from the DI container, and it just hands it to you, it puts things in a slightly different perspective.

    You can see some of my efforts at combining WACT and Pico here. All I have used it for is to "auto-wire" the application to run, and allow for injection of MockObjects during testing.
    Jason Sweat ZCE - jsweat_php@yahoo.com
    Book: PHP Patterns
    Good Stuff: SimpleTest PHPUnit FireFox ADOdb YUI
    Detestable (adjective): software that isn't testable.

  17. #17
    SitePoint Addict
    Join Date
    May 2003
    Location
    Calgary, Alberta, Canada
    Posts
    275
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by sweatje
    No...but it could be I think the DI pattern may make you want to put your thinking cap on a little askew.
    I like putting my thinking cap on askew. Maybe you guys can help me here.

    The example from Fowlers article is, as he admits, a naive example. "Super simple, small enough to be unreal". But Ill use it anyway. Here is his test case converted to php/simpletest using pico contatiner.
    PHP Code:
    class TestOfMovieLister extends UnitTestCase {
        private function 
    configureContainer() {
            
    $pico = new DefaultPicoContainer();
            
    $finderParams = array(new ConstantParameter("movies1.txt"));
            
    $pico->registerComponentImplementation('MovieFinder''ColonMovieFinder'$finderParams);
            
    $pico->registerComponentImplementation('MovieList');
            return 
    $pico;
        } 
        public function 
    testWithPico() {
            
    $pico $this->configureContainer();
            
    $lister $pico->getComponentInstance('MovieLister');
            
    $movies $lister->moviesDirectedBy("Sergio Leone");
            
    $this->assertEquals("Once Upon a Time in the West"$movies[0]->getTitle());
        } 

    Now this is the same test without pico:
    PHP Code:
    class TestOfMovieLister extends UnitTestCase {
        public function 
    testWithoutPico() {
            
    $lister = new MovieLister(new ColonMovieFinder('movies.txt'));
            
    $movies $lister->moviesDirectedBy("Sergio Leone");
            
    $this->assertEquals("Once Upon a Time in the West"$movies[0]->getTitle());
        } 

    So.. what do we gain with all those extra lines for pico?

    If I had a pico expert beside me here is what I would ask:
    - Am I supposed to be passing pico to all my objects like it is a huge factory?
    - Am I supposed to be making multiple instances of pico all over my code?
    - Am I only supposed to be using pico in my tests?
    - How do I deal with objects that need to be created using objects that have already been constructed (eg. Not just class names but real objects that need to be passed into the constuctor).

  18. #18
    SitePoint Guru
    Join Date
    Nov 2002
    Posts
    841
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by sweatje
    Ewwww! And "keeps cropping up" implies you have seen this more than once?!?
    Well, the thing is that passing the database connection to the action instead of a singleton may be a good thing. Crufty java inspired implementation aside, perhaps this is part of the "killer application" for dependency injection.

    Ever since that picoContainer thread, I've had a hunch that there was a dependency injection container hidden somewhere in the WACT Handle class. I just don't know where yet.

  19. #19
    SitePoint Wizard
    Join Date
    Aug 2004
    Location
    California
    Posts
    1,672
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    // At top...
    $injector = new Injector();
    $injector->register('Gateway');

    // Later on...
    $injector = new Injector();
    $gateway = $injector->create('Gateway');
    It is interesting that some of the examples look as much like a Service Locator as Dependency Injection. Both provide a path to Inversion of Control. Fowler seems positive on both Service Locator and Dependency Injection, and definitely likes Service Locator's simplicity. I wonder if Service Locator might be a better path in PHP given the lack of plumbing (short of a C extension) to support Dependency Injection as done in Java.
    Christopher

  20. #20
    SitePoint Guru
    Join Date
    Nov 2002
    Posts
    841
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Possibly related: Singleton registry

  21. #21
    eschew sesquipedalians silver trophy sweatje's Avatar
    Join Date
    Jun 2003
    Location
    Iowa, USA
    Posts
    3,749
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Unfortunatly, the need for the project I was working on with WACT and Pico evaporated before I completed the project, and a new project of similar complexity has not come along yet.

    Here is where I got to (remember this is basically initial experimentation, not a well factored design ).

    a bootstrap file:
    PHP Code:
    require_once 'setup.php'//constants
    session_start();

    $pico = new DefaultPicoContainer;
    ApplicationController::registerComponents($pico);
    ApplicationController::processActions($pico);

    $page_ctrlr = new ParameterDispatchController;
    $page_ctrlr->setParameterName(VIEW);
    ApplicationController::addPages($pico$page_ctrlr);
    $page_ctrlr->start(); 
    I was also playing with WACT controllers at this point (fall 04, IIRC). I think I would use more of the hierarchical controllers in post WACT-0.2 now.

    Here was the ApplicationController. Static calls, so more of just a namespace thing:
    PHP Code:
    class ApplicationController {
        static function 
    registerComponents($pico) {
            
    $pico->registerComponentImplementation('AmpAdodbConn''AmpAdodbConn',
                 array(
    'db' => new ConstantParameter(DBC))); 
            foreach(array(
                
    // util
                
    'Post',
                
    // models
                
    'CDPlan''FilterState',
                
    // actions
                
    'SetFilterState''UpdPlan'
                
    ) as $item) {
                
    $pico->registerComponentImplementation($item$item);
            }
        }
        protected static function 
    actionMap() {
            return array(
                 
    'filter'    => 'SetFilterState'
                
    ,'updplan'    => 'UpdPlan'
                
    ,'splitplan'    => 'SplitPlan'
                
    ); 
        }
        static function 
    processActions($pico) {
            
    $post $pico->getComponentInstance('Post');
            if (
    $post->hasKey(ACTION)
                && 
    array_key_exists($request $post->get(ACTION)
                    ,
    $map ApplicationController::actionMap())
                ) {
                
    $class $map[$request];
                if (!
    class_exists($class)) {
                    require_once 
    'actions/'.$class.'.php';
                }
                
    $action $pico->getComponentInstance($class);
                if (
    method_exists($action'process'))
                    
    $action->process();
            }
        }
        static function 
    addPages($pico$page_ctrlr) {
            
    $view_map = array(
                
    'plan'    => 'PlanView'
                
    ); 
            foreach(
    $view_map as $view => $class) {
                
    $pico->registerComponentImplementation($class$class);
                
    $page_ctrlr->addView($view, new PicoLazyProxy($pico$class'views/'));
            }
            
    $page_ctrlr->setDefaultView(new PicoLazyProxy($pico'PlanView''views/'));
        }
        static function 
    addGlobalTemplateVars($ds) {
            
    $ds->set('action'ACTION);
            
    $ds->set('appl_link'BASE_URL);
            
    $ds->set('view_link'VIEW_URL);
            
    $ds->set('action_link'ACTION_URL);
            
    $ds->set('jsstart''<script type="text/javascript">');
            
    $ds->set('jsend''</script>');
        }
    }


    class 
    PicoLazyProxy {
        protected 
    $pico;
        protected 
    $class;
        protected 
    $path;
        protected 
    $subject;
        public function 
    __construct($pico$class$path='') {
            
    $this->pico $pico;
            
    $this->class $class;
            
    $this->path $path;
        }
        protected function 
    subject() {
            if (!(
    $this->subject instanceof View)) {
                if (!
    class_exists($this->class)) {
                    require_once 
    $this->path.$this->class.'.php';
                }
                
    $this->subject $this->pico->getComponentInstance($this->class);
            }
            return 
    $this->subject;
        }
        public function 
    __call($method$args) {
                return 
    call_user_func_array(array($this->subject(), $method), $args);
        }

    So there was my big secret use a LazyLoading Proxy which remembers the PicoContainer.

    So an action might need a model and the request:
    PHP Code:
    interface iUpdPlan {
        public function 
    process();
    }

    class 
    UpdPlan extends BaseCdplanAction implements iUpdPlan {
        protected 
    $cdp;
        protected 
    $post;
        function 
    __construct(iCDPlan $cdpiRequestHash $post) {
            
    $this->cdp $cdp;
            
    $this->post $post;
        }
        
        public function 
    process() {
      
    //...
            
    }

    and a model might need a database connection:
    PHP Code:
    interface iCDPlan {
        public function 
    getPlants($requery=false);
        public function 
    getRfps($requery=false);
        public function 
    getPlan($filter=false);
        public function 
    update($plant$rfp$month$wgt);
        public function 
    getAreSplits();
    }

    class 
    CDPlan extends BaseCdplanModel implements iCDPlan {
    //...
    }

    class 
    BaseCdplanModel {
        protected 
    $conn;

        function 
    __construct(AmpAdodbConn $db) {
            
    $this->conn $db;
        }

    I ended up using interfaces for all of the type hinting, so that I could use MockObjects in testing.

    PHP Code:
    if (!class_exists('MockCDPlan')) {
        
    Mock::Generate('CDPlan''IntermediateCDPlan');
        class 
    MockCDPlan extends IntermediateCDPlan implements iCDPlan {
            public function 
    getPlants($requery=false) {
                
    parent::getPlants($requery);
            }        
            public function 
    getRfps($requery=false) {
                
    parent::getRfps($requery);
            }        
            public function 
    getPlan($filter=false) {
                
    parent::getPlan($filter);
            }        
            public function 
    update($plant$rfp$month$wgt) {
                
    parent::update($plant$rfp$month$wgt);
            }        
            public function 
    getAreSplits() {
                
    parent::getAreSplits();
            }
        }
    }

    class 
    TestUpdPlan extends CdplanActionUnitTestCase 
    {
        function 
    TestProcess() {
            
    $key 'DPWA|-9999';
            
    $post $this->getPost(array(
                
    'process' => array($key)
                ,
    $key.'|1' => '10,000'
                
    ,$key.'|2' => '12,000'
                
    ), true);
            
    $post->expectCallCount('hasKey',14);
            
            
    $cdp = new MockCDPlan($this);
            
    $cdp->expectArgumentsAt(0'update', array(
                
    'DPWA''-9999''200501''10000'));
            
    $cdp->expectArgumentsAt(1'update', array(
                
    'DPWA''-9999''200502''12000'));
            
    $cdp->expectArgumentsAt(2'update', array(
                
    'DPWA''-9999''200503'null));
            
    $cdp->expectCallCount('update'2);
            
            
    $pico $this->getPico($post$cdp);
            
    ApplicationController::processActions($pico);
            
            
    $this->assertRedirect('cdplan.php');
            
            
    $post->tally();
            
    $cdp->tally();
        }
        protected function 
    getPico($post=false$cdp=false) {
            
    $pico = new DefaultPicoContainer;
            
    ApplicationController::registerComponents($pico);
            if (
    $post instanceof iRequestHash) {
                
    $pico->unregisterComponent('Post');
                
    $pico->registerComponent(new InstanceComponentAdapter($post'Post'));
                
    $this->assertIdentical($post$pico->getComponentInstance('Post'));
            }
            if (
    $cdp instanceof iCDPlan) {
                
    $pico->unregisterComponent('CDPlan');
                
    $pico->registerComponent(new InstanceComponentAdapter($cdp'CDPlan'));
                
    $this->assertIdentical($cdp$pico->getComponentInstance('CDPlan'));
            }
            return 
    $pico;
        }
        
    //...


  22. #22
    eschew sesquipedalians silver trophy sweatje's Avatar
    Join Date
    Jun 2003
    Location
    Iowa, USA
    Posts
    3,749
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by Selkirk
    Well, the thing is that passing the database connection to the action instead of a singleton may be a good thing.
    I don't mind passing around the connection, but stuffing it into the request smells of MagicContainer to me

  23. #23
    Non-Member
    Join Date
    Jan 2003
    Posts
    5,748
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    SweatJe, interesting concepts you have, indeed

    I don't like the idea either of putting objects into the request, this I feel is a bit suspect in my mind.

    Crufty java inspired implementation aside, perhaps this is part of the "killer application" for dependency injection.
    I'm all for learning more from our Java cousins, in that we can learn something but that's not to say we've to jump of the cliff like lemmings in putting the Java implementation into practice

  24. #24
    ********* Victim lastcraft's Avatar
    Join Date
    Apr 2003
    Location
    London
    Posts
    2,423
    Mentioned
    2 Post(s)
    Tagged
    0 Thread(s)
    Hi...

    Quote Originally Posted by arborint
    It is interesting that some of the examples look as much like a Service Locator as Dependency Injection.
    They are closely related. Needle supplies both for example.

    yours, Marcus
    Marcus Baker
    Testing: SimpleTest, Cgreen, Fakemail
    Other: Phemto dependency injector
    Books: PHP in Action, 97 things

  25. #25
    SitePoint Wizard
    Join Date
    Aug 2004
    Location
    California
    Posts
    1,672
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    They are closely related. Needle supplies both for example.
    Thanks for the link to Needle. Now I have a lot more reading to do.

    Given that Service Locator is described as both a subset of Dependency Injection and easier to implement, when are they applicable in PHP?

    It seems that with the PHP Request/Response cycle only executing a small slice of the whole application that the disadvantages of Service Locator in that you need to pass the object around are minimal. Current PHP frameworks already pass a Request object about as many places. Why not just replace the Request object with a Service Locator object and at a minimum register the Request object with the Service Locator. Quick example:
    PHP Code:
    class Locator {
        var 
    $_cache;
        
        function 
    Locator() {
            
    $this->_cache = array();
        }
        function 
    setLib($name, &$lib) {
            
    $this->_cache[$name] = &$lib;
        }
        function &
    getLib($name) {
            return 
    $this->_cache[$name];
        }
        function 
    isLib($name) {
            return (
    $this->getLib($name) !== null);
        }

    PHP Code:
    class Request {
    var 
    $_request = array();
        
    function 
    Request() {
        if (!
    strcasecmp($_SERVER['REQUEST_METHOD'], 'POST')) {
            
    $this->_request =& $_POST;
        } else {
            
    $this->_request =& $_GET;
        }
        if (! 
    get_magic_quotes_gpc()) {
             
    $this->removeSlashes($this->_request);
        }
    }

    function 
    removeSlashes(&$str) {
        if (
    is_array($str)) {
            foreach (
    $str as $key => $val) {
                if (
    is_array($val)) {
                    
    $this->removeSlashes($val);
                } else {
                    
    $array[$key] = stripslashes($val);
                }
           }
        } else {
            
    $str stripslashes($str);
        }
    }

    function 
    get($name) {
        return 
    $this->_request[$name];
    }
        
    function 
    set($name$value) {
        if (
    $name) {
            
    $this->_request[$name] = $value;
        }
    }
        

    PHP Code:
    class Controller {
        function 
    execute(&$locator) {
            
    $request =& $locator->getLib('request');

    // code here
        
    }

    PHP Code:
    $locator =& new Locator();
    $locator->setLib('request', new Request());

    $controller =& new Controller();
    $controller->execute($locator); 
    But you could also do:
    PHP Code:
    $locator =& new Locator();
    $locator->setLib('request', new Request());
    $locator->setLib('db', new PostgressConnector('localhost''user'));
    $locator->setLib('template', new Template('./templates'));

    $controller =& new Controller();
    $controller->execute($locator); 
    Dependency Injection make possible more transparent injection, so I am definitely interested in delving more into Phemto to explore the possiblities.
    Christopher


Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •