SitePoint Sponsor

User Tag List

Page 1 of 4 1234 LastLast
Results 1 to 25 of 99

Thread: Method Chaining

Hybrid View

  1. #1
    SitePoint Evangelist
    Join Date
    Apr 2003
    Location
    Chicago, USA
    Posts
    417
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    Method Chaining

    Hi,

    I notice some developers using this kind of syntax:

    PHP Code:
    $object->method1()->method2()->...->methodN(); 
    One example is CodeIgniter's database class:

    PHP Code:
    $this->db->select('title')->from('mytable')->where('id'$id)->limit(1020); 
    I don't know why, but it just doesn't seem right to me as far as OOP principles go. I mean, does a database contain a select object which contains a from object which contains a where object and so on? Maybe I am thinking too much in terms of composition. I mean it's nice to have a shortcut way of doing things, but how far do you go with these shortcut methods before the code becomes inflexible, etc.? What do you think of method chaining?

  2. #2
    SitePoint Zealot
    Join Date
    Sep 2005
    Posts
    122
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    It's called a "fluent interface". Martin Fowler explains it well here:
    http://www.martinfowler.com/bliki/FluentInterface.html

    Personally I like it. It reads like a book.

  3. #3
    SitePoint Addict
    Join Date
    Sep 2006
    Posts
    219
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    I also like this approach and use it in my own query abstraction code.. I simply return $this from the method.

    In my opinion, It reads better than:

    PHP Code:

    $db
    ->select('*');
    $db->from('table');
    ... 
    etc.. 
    Quote Originally Posted by Caldus
    I mean, does a database contain a select object which contains a from object which contains a where object and so on?
    select, from, where are not objects, they are methods of the db object, so they each return $this whch is an instance of the db.
    Last edited by danh2000; May 8, 2007 at 20:07.

  4. #4
    SitePoint Wizard stereofrog's Avatar
    Join Date
    Apr 2004
    Location
    germany
    Posts
    4,324
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by shea View Post
    It's called a "fluent interface". Martin Fowler explains it well here:
    http://www.martinfowler.com/bliki/FluentInterface.html

    Personally I like it. It reads like a book.
    As dynamic language users, we don't have to use patterns designed to overcome java's rigidity. I agree that method chaining looks confusing (though 'cool'), in php we can write the same in a more transparent way, e.g.

    PHP Code:
    $db->select(array(
       
    'from' => 'mytable',
       
    'where' => array('id''>'10),
       
    'limit' => array(1020)
    )); 
    Well, this 'array' all the time looks quite stupid... but so is the php programming.

  5. #5
    SitePoint Wizard dreamscape's Avatar
    Join Date
    Aug 2005
    Posts
    1,080
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by stereofrog View Post
    I agree that method chaining looks confusing (though 'cool'), in php we can write the same in a more transparent way, e.g.

    PHP Code:
    $db->select(array(
       
    'from' => 'mytable',
       
    'where' => array('id''>'10),
       
    'limit' => array(1020)
    )); 
    And that is better than a fluid interface, exactly how?

    That's got to be one of the worst interfaces I have ever seen. I'd personally take a crappy and poorly thought out fluid interface over that garbage any day. ;-)
    <.smarter.web.development.>
    PHP Stuff: Plexus | Chocolate (BDD Framework... coming soon)
    Graphite

  6. #6
    SitePoint Wizard
    Join Date
    Feb 2007
    Posts
    1,274
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by dreamscape View Post
    That's got to be one of the worst interfaces I have ever seen. I'd personally take a crappy and poorly thought out fluid interface over that garbage any day. ;-)
    Oh my, you are going to hate Rails. It is practically littered with code like this, except Rails has the "symbol" instead of plain strings.

  7. #7
    SitePoint Evangelist
    Join Date
    Apr 2003
    Location
    Chicago, USA
    Posts
    417
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Oh got it.

    Still though, it looks like you're calling the where() method from a "from" object and so on. You usually don't return $this in most methods so that's how it would read to people who aren't aware of the details of this technique.

  8. #8
    SitePoint Guru
    Join Date
    Nov 2002
    Posts
    841
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    I was not a fan of this style, but I ran across an example where it seemed to work. My original code was:
    PHP Code:
    $this->addParameter(new PostParameter('name''name')); 
    This caused confusion because the most common case is that the optional second parameter would be the same as the first. You could solve this by passing an array:
    PHP Code:
    $this->addParameter(new PostParameter(array('name'=>'name''modelLocation' => 'name'))); 
    Well, I really didn't like this. It stinks when you don't specify the optional modelLocation parameter. I generally don't like passing configuration arrays to object constructors, so I went fluid:
    PHP Code:
    $this->addParameter(new PostParameter('name'))->setModelLocation('name'); 
    Better, but then I adopted fluid names:
    PHP Code:
    $this->defineInput(new PostParameter('name'))->bindToModel('name'); 
    Now, the most common case is that both values are the same. This can be encoded now into bindToModel, which can now have its parameter be optional. So we have:
    PHP Code:
    $this->defineInput(new PostParameter('name'))->bindToModel(); 
    Better?

  9. #9
    SitePoint Evangelist
    Join Date
    Mar 2005
    Posts
    423
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Nice example selkirk

  10. #10
    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)
    Maybe I'm missing a point here, but if the second parameter is optional, what about:
    PHP Code:
    $this->addParameter(new PostParameter('name')); 
    As you said, it's only confusing when the second parameter is equal to the first; In cases, where you do supply the second parameter, there's no confusion:
    PHP Code:
    $this->addParameter(new PostParameter('name''foobar')); 

  11. #11
    SitePoint Guru
    Join Date
    Nov 2002
    Posts
    841
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by kyberfabrikken View Post
    Maybe I'm missing a point here, but if the second parameter is optional, what about:
    PHP Code:
    $this->addParameter(new PostParameter('name')); 
    Because this call does not have enough information to distinguish between these two cases:
    1. No binding at all.
    2. Bind, but use the same name as the parameter for binding.

  12. #12
    SitePoint Wizard stereofrog's Avatar
    Join Date
    Apr 2004
    Location
    germany
    Posts
    4,324
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by Selkirk View Post
    Better?
    In general, method chaining is a good thing, as long as one follows common naming rules: methods are actions, method names are verbs, methods return objects, which are nouns.
    PHP Code:
    $users->map('trim')->sort_by_id()->format_as('html')->send_to('me@mail'); 
    is good, because each function is independent and has a well-defined purpose. The whole thing looks much like unix piping and is indeed very nice and useful.

  13. #13
    SitePoint Evangelist
    Join Date
    Apr 2003
    Location
    Chicago, USA
    Posts
    417
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Selkirk, nice example.

    In general, method chaining is a good thing, as long as one follows common naming rules: methods are actions, method names are verbs, methods return objects, which are nouns.
    Yeah, I think this is a case where the naming of methods is very crucial.

  14. #14
    SitePoint Evangelist
    Join Date
    Apr 2003
    Location
    Chicago, USA
    Posts
    417
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    I also do not like configuration arrays as input either. It always seems odd to do it that way.

  15. #15
    SitePoint Addict Mastodont's Avatar
    Join Date
    Mar 2007
    Location
    Czech Republic
    Posts
    375
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    $this->db->select('title')->from('mytable')->where('id', $id)->limit(10, 20);

    What about speed of execution? Every reference (->) must be evaluated ... I guess that more arguments to less objects is better solution. (experience from other language)

  16. #16
    SitePoint Addict Jasper Bekkers's Avatar
    Join Date
    May 2007
    Location
    The Netherlands
    Posts
    282
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by Mastodont View Post
    What about speed of execution?
    It's irrelevant, PHP isn't for performance, it's for convenience. For performance, use a platform optimized C++ implementation.

  17. #17
    SitePoint Zealot
    Join Date
    Dec 2005
    Posts
    117
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Personally, I think it's extremely stupid, and very inefficient. For example, take a look at the following two lines:

    Code:
    $this->db->select('title')->from('mytable')->where('id', $id)->limit(10, 20); 
    
    mysql_query("SELECT title FROM mytable WHERE id = $id LIMIT 10,20");
    It's quite obvious which one is simpler, and cleaner to use. Not to mention the second statement doesn't have to go through a bunch of PHP code to generate the actual SQL statement. In my opinion, CodeIgniter pulled a Microsoft. They tried to make things so easy and user friendly, they only made things worse. Not to mention, what happens when you need to execute a more complex SQL statement, like say:

    Code:
    SELECT transaction.id FROM transaction,transaction_details WHERE transaction.id = transaction_details.transaction_id AND transaction.userid = 55 AND transaction.status = 'approved' AND transaction_details.index_id = 12
    Kiopa Software -- Demo Now Online! Check it out!
    Goal: Consolidate all data & tools you use on a daily basis.
    Grand opening special, licenses FREE for a limited time.

  18. #18
    Non-Member
    Join Date
    Jan 2003
    Posts
    5,748
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Don't worry about performance in regards to PHP5s object model as it's not here nor there; When you actually do have a performance issue, there will be other, more highter priority areas that would need to be addressed first, before you even get near hand a script.

  19. #19
    SitePoint Enthusiast
    Join Date
    May 2007
    Posts
    74
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    $this->db->select('title')->from('mytable')->where('id', $id)->limit(10, 20);

    bad , bad coding for relational DB. man , spent some time learn relational theory and sql !!!

    regards

  20. #20
    SitePoint Evangelist
    Join Date
    Apr 2003
    Location
    Chicago, USA
    Posts
    417
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Tell the CodeIgniter developers that, not me. So what's wrong with it?

  21. #21
    SitePoint Enthusiast
    Join Date
    May 2007
    Posts
    74
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    $this->db->select('title')->from('mytable')->where('id', $id)->limit(10, 20);

    first, this is a simple sql right? how about we do it in sql:

    $sql = "select tilte from mytable where id = {$id} limit 10,20";

    so , what is the point to cut an sql statement into separate parts then glue it back?

    second, every method try to return an object, but why a select() return an object, it does not make sense for me.

    third, try to build an sql statement with over 20 lines (most complext sql statments has over 100 even 1000 lines), then tell me how you feeling with method chaining.

    the method chaining is good in some context , like chaning some small procedures to finish a big procedure , but it NOT FOR cut sql statement into small pieces then glue it back.

    regards

  22. #22
    SitePoint Evangelist
    Join Date
    Apr 2003
    Location
    Chicago, USA
    Posts
    417
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    but why a select() return an object, it does not make sense for me.
    That was actually what I was trying to convey in my original post.

  23. #23
    SitePoint Wizard
    Join Date
    Feb 2007
    Posts
    1,274
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    One obvious difference is that with method chaining the builder object can automatically protect against sql injection attacks.

    The variable interpolated sql string is actually prone to injection attacks.

  24. #24
    SitePoint Enthusiast
    Join Date
    Oct 2004
    Posts
    88
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Hi,
    Should we uses a feature by the simple fact that it exists. I'm using the array way for interfaces, it works fine. Why should i use fluent interfaces?



    PHP Code:
    $model->action('module_article''get_node_articles'
                    array(  
    'result'    => & $viewVar['article'],
                            
    'id_node'   => int,
                            
    'order'     => array('title' => 'asc'),
                            
    'limit'     => array('numItems' => int,
                                                 
    'numPage' => int),
                            
    'fields'    => array('id_article','title',
                                                 
    'header')
                        )); 

  25. #25
    SitePoint Addict chestertondevelopment's Avatar
    Join Date
    Dec 2005
    Location
    Essex, UK
    Posts
    241
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    I think the CodeIgniter/SQL example is just a case of unfortunate function naming. Perhaps "select('title')" should be "getField('title')".

    Personally I like this way of constructing SQL queries, it makes it more obvious exactly what is happening. It also allows easier conditional elements, e.g.
    PHP Code:
    $db->getFields('title')->from('mytable')->where('id'$id);
     
    if (
    $_GET['all'] != 'true') {
        
    $db->limit(10);
    }
     
    $result $db->retrieve(); 
    As for method chaining, I think it's good in circumstances where you are constructing something or adding to something, e.g.
    PHP Code:
    $output $xml->attach(new Element)->attach(new Element)->output(); 
    Seems much clearer/concise/easier-to-read than..
    PHP Code:
    $xml->attach(new Element);
    $xml->attach(new Element);
    $output $xml->output(); 
    Obviously these examples are very primitive.


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
  •