SitePoint Sponsor

User Tag List

Page 1 of 5 12345 LastLast
Results 1 to 25 of 116
  1. #1
    SitePoint Member
    Join Date
    Jun 2004
    Location
    London
    Posts
    6
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    Dependency Injection in PHP4

    Hi,

    I've seen some real potential for using Dependency Injection, but all of the code I work with is PHP4 only. So, I thought I'd see if I could make something work in PHP4.

    The PHP5 features used by dependency injectors seem to be:
    • interfaces
    • type hints in constructor signature


    I replaced both of these with static methods on the class, e.g.

    Code:
    class Adder implements Number {
         function __construct(One one, Two two) {
         }
    }
    becomes

    Code:
    class Adder {
        function implements() {
            return array('Number');
        }
    
        function Adder($one, $two) {
        }
    
        function constructorSignature() {
             return array('One', 'Two');
        }
    }
    The DI container will call these methods when the class is registered to find out the class meta-information. Using this approach, I've ported Marcus's phemto code to php4. The tests run pretty much unmodified. Would be interested to hear what other people think of this approach.

    Dave
    Attached Files Attached Files

  2. #2
    SitePoint Wizard DougBTX's Avatar
    Join Date
    Nov 2001
    Location
    Bath, UK
    Posts
    2,498
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Off Topic:

    Quote Originally Posted by heathd
    The DI container will call these methods when the class is registered to find out the class meta-information.
    This is a problem I've been having: is there a good way to associate meta-data with classes and objects in PHP4 and/or 5?

    Douglas
    Hello World

  3. #3
    SitePoint Guru dbevfat's Avatar
    Join Date
    Dec 2004
    Location
    ljubljana, slovenia
    Posts
    684
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by DougBTX
    This is a problem I've been having: is there a good way to associate meta-data with classes and objects in PHP4 and/or 5?
    Some sort of lookup tables could do it, although that is additional work. And to work in both versions of php, the code should also be php4 compatible (obviosly).

  4. #4
    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)
    Quote Originally Posted by DougBTX
    This is a problem I've been having: is there a good way to associate meta-data with classes and objects in PHP4 and/or 5?
    This is probably the one thing that makes DI quite undesireable in zend1. The hassle of providing the meta-data kind of outweights the gains. Perhaps some ingenious code-generation could easy the pain a bit, but I remain sceptical.

  5. #5
    SitePoint Member
    Join Date
    Jun 2004
    Location
    London
    Posts
    6
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by kyberfabrikken
    This is probably the one thing that makes DI quite undesireable in zend1. The hassle of providing the meta-data kind of outweights the gains. Perhaps some ingenious code-generation could easy the pain a bit, but I remain sceptical.
    I thought the approach I'd used was quite neat :-). I don't think it would be a hassle, even for complex code. The description of the class is right there in the code where it should be. Of course it's not as elegant as having it built into the language, but good enough IMHO. I disagree that the hassle is bigger than the gains. Admittedly, I haven't tried this in a real application.

  6. #6
    SitePoint Wizard DougBTX's Avatar
    Join Date
    Nov 2001
    Location
    Bath, UK
    Posts
    2,498
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Hmm, how do you people feel about this sort of code:

    PHP Code:
    function Adder ($meta) {

        
    $metadata = array(
            
    'depends_on' => array('One''Two')
        );

        return 
    $metadata[$meta];
    }

    class 
    Adder {

        function 
    Adder($one$two) {
            
    // ...
        
    }

    }

    $dependencies Adder('depends_on');
    $adder =& new Adder(/* injected */); 
    Might be interesting if it could be extended so we could use it to add data too, class variable style.

    Douglas
    Hello World

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

    Why not add the extra information at the registration stage? One of the nice things about DI is the minimal impact it has on the components. Having to implant a reflection API could be a big deal, especially with PHP5 "around the corner".

    By adding meta to the registration, or directly to Phemto, the application writer and framework writer that registers the component has to take care of it. On the other hand, these are the same users thet have to manage the high level stuff anyway...er...such as PHP5 migration .

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

  8. #8
    SitePoint Wizard
    Join Date
    Aug 2004
    Location
    California
    Posts
    1,672
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    So more like?
    PHP Code:
    $meta = array(
        
    'depends_on' => array('One''Two'),
        
    'other_info => 'Three',
    );
    $adder = $Injector->register('
    Adder', $meta); 
    Specifying things explicitly would also be upward compatable with PHP5 and might even allow some sort of override capability in PHP5 where it would fill in suing introspection everything not provided explicitly.
    Christopher

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

    Exactly. Even...
    PHP Code:
    $injector->register(new Php4('Adder', array('One''Two'), 'Three')); 
    yours, Marcus
    Marcus Baker
    Testing: SimpleTest, Cgreen, Fakemail
    Other: Phemto dependency injector
    Books: PHP in Action, 97 things

  10. #10
    SitePoint Wizard
    Join Date
    Aug 2004
    Location
    California
    Posts
    1,672
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by lastcraft
    Hi.

    Exactly. Even...
    PHP Code:
    $injector->register(new Php4('Adder', array('One''Two'), 'Three')); 
    yours, Marcus
    Very interesting. I assume that for PHP5 you could just stub out the Php4() class so it would work as normal. Very cool.
    Christopher

  11. #11
    SitePoint Guru dbevfat's Avatar
    Join Date
    Dec 2004
    Location
    ljubljana, slovenia
    Posts
    684
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    maybe use a simple factory instead of creating a Php4 object directly? so, upon transition, all you'd have to change is the factory code.

  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 dbevfat
    maybe use a simple factory instead of creating a Php4 object directly? so, upon transition, all you'd have to change is the factory code.
    Er...yer what?

    No instantiation hasn't happened at this stage. It's just a class name that is declared to be available when needed.

    yours, Marcus
    Last edited by lastcraft; Sep 6, 2005 at 17:42. Reason: Changed "has" to "hasn't". Sorry about that - typo!
    Marcus Baker
    Testing: SimpleTest, Cgreen, Fakemail
    Other: Phemto dependency injector
    Books: PHP in Action, 97 things

  13. #13
    SitePoint Guru dbevfat's Avatar
    Join Date
    Dec 2004
    Location
    ljubljana, slovenia
    Posts
    684
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    oh, i've completely misunderstood it then. The constructor must've confused me, since at the time registering to a DI there is usually no object creation, i believe. What did you mean by passing 'new Php4()' then?

    still, makes me think. How about if the actual injection would be a class that would hold the injected classes' name along with additional meta info.

    then the instantiation would be defered to a factory that would create a proper Injection instance, depending on the version of php. For php5, it would override the passed meta-info with the actual dependencies.

    PHP Code:
    $injector->register(Injection::Create('Adder', array('One''Two'), 'Three'));

    class 
    Injection
    {
      function 
    Create($className$extends$implements)
      {
        ...
      }

    I am just thinking out loud, i guess there's at least too much overhead, if not something worse wrong here

    come to think of it, there is no need for an object to be returned from Injection::Create(), there's just the three pieces of information. But still, this static method could be useful for php 4-5 compatibility.

    er ... yeah

    regards

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

    Sorry, I've confused you further by my typo above. The object has not been instantiated at that point and isn't as part of the registration process. It just declares to the injector that this class can be substituted for an interface.

    Regarding using "new" here, I don't see a problem. I see it as a more general...
    PHP Code:
    $injector->register(new Declaration('Class', ...)); 
    ...where you could add overridden parameters, namespaces for instantiation or whatever. It's a hook for arbitrary extension. Factories are limited to the ideas of the Injector writer.

    The Injector::create() method is a factory of which you speak. That's normally called by the framework to fulfill the interface of course. Nothing to do with the set up of the injector.

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

  15. #15
    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)
    Quote Originally Posted by heathd
    I thought the approach I'd used was quite neat :-). I don't think it would be a hassle, even for complex code. The description of the class is right there in the code where it should be. Of course it's not as elegant as having it built into the language, but good enough IMHO.
    Actually, after looking over it a couple of time, I'd like to withdraw my previous statement. Your solution is indeed quite elegant, because it looks a lot like it would in php5.
    I think my reaction came from an inherent defensemechanism against people trying to simulate language features. (Such as when people want classes and inheritance in javascript).
    In your case it fits nice in though, since the feature exists in php5.

    And I do prefer yours over the one marcus posted below, even though that has gotten more attention for the last couple of posts.

  16. #16
    SitePoint Guru dbevfat's Avatar
    Join Date
    Dec 2004
    Location
    ljubljana, slovenia
    Posts
    684
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by lastcraft
    Sorry, I've confused you further by my typo above. The object has not been instantiated at that point and isn't as part of the registration process. It just declares to the injector that this class can be substituted for an interface.

    Regarding using "new" here, I don't see a problem. I see it as a more general...
    PHP Code:
    $injector->register(new Declaration('Class', ...)); 
    ...where you could add overridden parameters, namespaces for instantiation or whatever. It's a hook for arbitrary extension. Factories are limited to the ideas of the Injector writer.
    Let me get this straight. At the time of di-registration someone must dig for (with reflections in php5) or get (passed exclusively in php4) class instantiation information (dependencies).

    This could be either the injector itself (Phemto), or the Dependency that you introduced. In latter case, the Injector relies on that it already has all information it needs, so it's role is purely to lookup classes and instantiate them.

    If you meant the former, I've understood you the first time already. I just tried to be a wise guy and went complicating things up, as always. I tried to introduce a factory that would dig information about a class, and return it as a purely data-holding Dependency object for the Injector.

    Quote Originally Posted by lastcraft
    The Injector::create() method is a factory of which you speak. That's normally called by the framework to fulfill the interface of course. Nothing to do with the set up of the injector.
    Actually I was talking about a Dependency factory briefly explained above, but it's completely unnecessary.

  17. #17
    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)
    Quote Originally Posted by dbevfat
    At the time of di-registration someone must dig for (with reflections in php5) or get (passed exclusively in php4) class instantiation information (dependencies).
    Actually it doesn't need to happen until the time of where the DI creates an instance.

  18. #18
    SitePoint Guru dbevfat's Avatar
    Join Date
    Dec 2004
    Location
    ljubljana, slovenia
    Posts
    684
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by kyberfabrikken
    Actually it doesn't need to happen until the time of where the DI creates an instance.
    Even better, lazy digging then. But you'd have to have different implementations of DI for different php versions. Makes Dependency class redundant, though.

  19. #19
    ********* 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 dbevfat
    Let me get this straight. At the time of di-registration someone must dig for (with reflections in php5) or get (passed exclusively in php4) class instantiation information (dependencies).
    Some precalculation may happen, but mostly it happens when the instance is created to allow overrides. Part of the idea is that you can place an intercept between choosing a class/interface and actually instantiating it. It breaks the "new" operator into two pieces if you like.

    Once this trick gives you a foot in the door, you can bring in a truck load of cleverness. These include service location, lifecycle (whether to use an existing instance, a persistent instance) and decoration.

    Anyway, that tiny litle step gives it a lot of power. As someone commented on another thread, you don't reallt get DI until you first see a need for it in the code you are writing. Once you spot it the first time, that opens the floodgates.

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

  20. #20
    SitePoint Guru dbevfat's Avatar
    Join Date
    Dec 2004
    Location
    ljubljana, slovenia
    Posts
    684
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by lastcraft
    ...
    As someone commented on another thread, you don't reallt get DI until you first see a need for it in the code you are writing. Once you spot it the first time, that opens the floodgates.
    looking forward to meeting it

    regards

  21. #21
    SitePoint Wizard DougBTX's Avatar
    Join Date
    Nov 2001
    Location
    Bath, UK
    Posts
    2,498
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    DI: when you need a new instance of a class which depends on objects which already exist, but which you don't have direct access to.
    Hello World

  22. #22
    SitePoint Evangelist ghurtado's Avatar
    Join Date
    Sep 2003
    Location
    Wixom, Michigan
    Posts
    591
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by DougBTX
    DI: when you need a new instance of a class which depends on objects which already exist, but which you don't have direct access to.
    Allow me to be a little pedantic:

    DI: when you need a new instance of a class which depends on objects which may already exist, but which you don't want to have direct access to
    Garcia

  23. #23
    SitePoint Wizard DougBTX's Avatar
    Join Date
    Nov 2001
    Location
    Bath, UK
    Posts
    2,498
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by ghurtado
    Allow me to be a little pedantic:
    Pedantic is cool, how about:

    DI: when you need a new class instance which depends on objects who's existance you would rather keep outside the current scope.

    Better?
    Hello World

  24. #24
    SitePoint Evangelist ghurtado's Avatar
    Join Date
    Sep 2003
    Location
    Wixom, Michigan
    Posts
    591
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Perfect
    Garcia

  25. #25
    SitePoint Wizard DougBTX's Avatar
    Join Date
    Nov 2001
    Location
    Bath, UK
    Posts
    2,498
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by ghurtado
    Perfect
    OK, we can express DI in a sentence. Next step: an example.

    How about a form helper which gets a template engine injected? Or an Object-Relational mapper which gets a database connection instance injected?

    Douglas
    Hello World


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
  •