3

I understand how to create a class, instantiate it, as well as access properties and methods, but $myobject->function() is about as complicated as it gets for me for now.

What is this structure?

$myobject->function()->something. I am repeatedly seeing this more and more, especially as I start wrapping my head around PDO queries. For example:

$query->function1($arg)
  ->function2($arg)
  ->function3($arg);

What's happening here? is it simply chaining one call of multiple methods in the class, or are those sub-functions of function1()? What would the class definition look like?

Dharman
  • 30,962
  • 25
  • 85
  • 135
user658182
  • 2,148
  • 5
  • 21
  • 36
  • 'Method Chaining' - that's what it's called. That opened up a whole new world of search results for me, thanks for that. One of many that I am reading that has proved very helpful so far is http://www.talkphp.com/advanced-php-programming/1163-php5-method-chaining.html. So, by returning the '$this' object, I can simply continue calling methods and properties of the '$this' object. Thanks to everyone for the answers so far, they are really helpful. @mehaase Thanks especially for your very informative response. It's very enlightening to see it from an operator perspective. – user658182 Sep 22 '12 at 04:25

6 Answers6

6

This is a design pattern called Fluent Interface. It's become popularized through some notable frameworks that use it, such as jQuery. It's a neat trick for writing compact, readable code (in some cases) but like many design patterns it is not suited to all situations.

The -> symbol is actually just an operator. Similar to the way that + or - can be used to operate on numbers, the -> operator can operate on objects and members. The PHP interpreter can simplify an expression like 5 + 4 down to just 9, and it can simplify an expression like $a->b as well. The expression $a->b is evaluated by looking inside $a for a member called b.

Just like the + operator can be used several times in an expression, e.g. 5 + 2 + 7, the -> operator can also be used several times. The PHP interpreter is left associative for the + operator, which means it evaluates 5 + 2 + 7 as if it were written (5 + 2) + 7, which evaluates to 7 + 7, which in turn evaluates to 14.

The -> operator is also left associative. So an expression like $a->b->c is interpreted in a similar fashion to the previous example: first the interpreter evaluates $a->b by looking for a member called b in a, then it looks for a member called c in that! This assumes that $a->b actually evaluates to an object; if it doesn't, then the PHP interpreter will give you an error: "Trying to get property of non-object".

This paradigm can be extended indefinitely: $a->b->c->d->e->f->g->.... etc.

In the Fluent Interface design pattern, this is implemented by having all instance methods return the instance. So $a->b() returns $a. Therefore, $a->b()->c() is exactly the same as calling $a->b() and then calling $a->c().

Some people think the former is more readable than the latter. In some cases that's true but in other cases it's not. Like most design patterns, you need to use good judgement when deciding whether to use this pattern or not. Keep in mind this pattern can only work if the instance methods are called purely for their side effects. You can't return any other value from an instance method besides the instance itself, or else you will break the fluent interface.

Mark E. Haase
  • 25,965
  • 11
  • 66
  • 72
4

$myobject->function() is returning an object, ->something would access a field on that object.

Basically, the main concept in this programming method is that an object contains data and methods (or "functions") to interact with the contained data. These containers can be conveniently passed around. PHP is giving you some shorthand so you don't have to assign everything to a variable.

Returning objects is a way to layer functionality, so your PDO object, which has a query method, may return a row object. The row object has its own set of methods (e.g. for getting column values), so you can then invoke those methods.

So:

$pdo->queryOneRow(...)->getValue(<some column>)

Is really just shorthand for:

$result = $pdo->queryOneRow(...);
$result->getValue(<some column>)
Mark Elliot
  • 75,278
  • 22
  • 140
  • 160
1
$query->function1($arg) ->function2($arg) ->function3($arg);

means :

$some_object1 = $query->function1($arg); 
$some_object2 = $some_object2->function2($arg); 
$final_result = $some_object2->function3($arg);

SO your function 1 and function 2 must be returning objects of some class.

Hope that helps...

Pro_da
  • 29
  • 3
1

Here's a simple demo that's a little fun:

<?php

class ChainMe {

    public function hello() {
        echo 'Hello ';

        return $this;
    }

    public function good($is = false) {
        if ($is === true) {
            echo 'beautiful ';
        }

        return $this;
    }

    public function day() {
        echo "world!\n\n";

        return $this;
    }

}

$happy = new ChainMe();
$happy
    ->hello()
    ->good(true)
    ->day();

$meh = new ChainMe();
$meh->hello()->good()->day();

?>

http://codepad.org/zlQEMPqK

If you're familiar at all with jQuery and have ever seen something like:

jQuery('#my .awesome[selector]')
    .fadeToggle('fast')
    .addClass('rocks')
    .fadeToggle();

Then you've experience chaining. For instance, look at the jQuery variable's definition in the source:

// Define a local copy of jQuery
jQuery = function( selector, context ) {
    // The jQuery object is actually just the init constructor 'enhanced'
    return new jQuery.fn.init( selector, context, rootjQuery );
},

And also jQuery.extend, jQuery.fn/jQuery.fn.init, $ and window._$. You'll see many of it's member methods return this (or return another method that in turn returns this). There is in turn . When jQuery debuted, that was the first time many "Javascript" developers had ever seen the pattern. It took some getting used to. :)

In jQuery, under many conditions, it's supposed to give a good performance boost to method chain (for instance, in animation queues where timing is important). I don't know if that's the case in PHP, but that's entirely possible. I'm more in the browser than on the server, so I haven't seen it as much in PHP. But the point is, it's a power concept to grasp.

Jared Farrish
  • 48,585
  • 17
  • 95
  • 104
0

The -> syntax is the operator you use to access your class' methods and members. When you do something like this:

$someObject -> function1(arg) -> function2(arg) ... You are just accessing the returned object even further.

Suppose you have a class Bike. This bike has a method called SpeedUp(arg) that takes a float as a parameter. The SpeedUp method returns the object that called the method (The $this pointer). To vary a little, we will add a SlowDown(arg) method.

class myBike
{
    private function SpeedUp($arg)
    {
        //Do something with $arg, then return "this"...
        return $this;
    }

    private function SlowDown($arg)
    {
        //Do somethign with $arg, then return "this".
        return $this;
    }
}

Bike myBike;
MyBike -> SpeedUp(50.3) -> SpeedUp(40.3) -> SlowDown(30.4);

So what is going on here? The existence of the parameters is irrelevant, first. Whether you have it or not your method can still return this object.

You are able use so many -> operators because this bike returns itself to the caller. So when you call MyBike -> SpeedUp(), this will return MyBike, so in the second SpeedUp call, it will essentially be myBike -> SpeedUp(40.3), and since that returns the same bike again, you can slow it down in the same line.

DISCLAIMER: This example is really generic but it should help illustrate the answer to the question.

Andy Ibanez
  • 12,104
  • 9
  • 65
  • 100
0

With Object oriented programing, the objects can have multiple instances. The properties in these instances can have different values.

for eg.

class Person {
    public var $name;
    public var $age:

    public function simpleGetter() {
       echo "name : ". $this->name;
       echo "age : ". $this->age;
       return $this;
    }

    public function addAgeByOne($instance = null) {
        return ++$instance->age;
    }
}

$student = new Person();
$student->name = "Student\'s name";
$student->age = 23;

$teacher = new Person();
$teacher->name = "Teacher\'s name";
$teacher->age = 45;

$student->simpleGetter(); // will display the property value from student instance
$teacher->simpleGetter(); // will display the property value from teacher instance


// yes this is chaining, it will first retrieve the results from simpleGetter() and then
// pass on to addAgeByOne
$student->simpleGetter()->addAgeByOne();  
Kishor Kundan
  • 3,135
  • 1
  • 23
  • 30