Industrial
Industrial

Reputation: 42758

Chaining methods in PHP5

Ok, guys. Here's something I've been thinking about for a while:

As it's possible to chain methods in PHP5, I wonder if it is possible to take the concept even further by in a smart way determining if a method is the last in the chain to be executed - and that's without utilizing a third method named getResult()?

Normal method calling:

$myClass->dofirst(); // Data is returned from the dofirst-method

What I would like;

$myclass->dofirst()->sortOutputfromDofirstAndReturn();

The idea is that the second method, sortOutputfromDofirstAndReturn() would prevent the dofirst() method from returning, and instead perform the logic stated inside the second method, without needing a third method to bounce the return to the user.

Maybe a bit confusing so let me know if I need to clarify anything!

Upvotes: 2

Views: 143

Answers (7)

codez
codez

Reputation: 1391

I think it is only posible if data is string, using magic method

class MyClass{
  public function __toString(){
    return $this->data;
  }
  public function dofirst(){
    $this->data='Hello';
    return $this;
  }
  public function sort(){
    $this->data.=' World';
    return $this;
  }    
}

$obj = new MyClass;
echo $obj->dofirst(); //Hello
echo $obj->dofirst()->sort(); //Hello world

Upvotes: 1

petraszd
petraszd

Reputation: 4297

There are few possibilities:

Add one (or few special) methods (see Doctrien 1.2) that finish chain (execute is special)

$q = new Doctrine_Query();
$q->select('Foo')->where('bar = 1')->orderBy('bar')->execute();

If final result is always array like object than You can implement Iterator interface with Your chain logic.

class Chain implements Iterator { /* implementation */ }
$c = new Chain();
foreach ($c->first()->second() as $item) { /* do stuff */ }

Half stupid one. If Your result is string, than reimplement __toString method...

Upvotes: 0

Endophage
Endophage

Reputation: 21473

You're basically asking if you can chain methods where the previous one passes it's data on to the next one without "returning". Given that you only chain methods on objects and don't capture any return values from anything but the last method called (which if you're chaining should just return another reference to the object you already have), it's doing that already. It really doesn't matter if dofirst() returns some value that never gets seen. There is no performance enhancement to be found here.

EDIT

I think I misunderstood your question as you indicated you understood method chaining. What you're asking about is simply functions that return the object they are part of. When you call $myclass->dofirst() you are simply calling the dofirst function from the $myclass object. If you want to chain a method to this, you need dofirst to return the object again so that another function can be called on it.

class MyClass{

    function dofirst()
    {
        // do something
        return $this; // return the object you were calling this function on
    }
}

If you now look at how the code would execute, $myclass->dofirst() would return a reference to $myclass which you would then call sortOutputfromDofirstAndReturn() on in your chain: $myclass->dofirst()->sortOutputfromDofirstAndReturn();.

Have a look at the factory pattern to see an example of where method chaining gets used a lot.

Upvotes: 0

Zelda
Zelda

Reputation: 2124

I'm not 100% sure what you're asking; if you want the second "sort" function to do something with doFirst's output, why don't you just use

$myclass->sortOutputfromDofirstAndReturn(dofirst());

And have doFirst() return something? As others have said, doFirst has to return $this or an object to work properly. If I'm reading correctly you just want to use method 2 to manipulate something method 1 should be returning.

Upvotes: 0

Karoly Horvath
Karoly Horvath

Reputation: 96266

Method calls are executed sequentially, you have to return an object so you can call a method on it. If dofirst() returns plain data this is not possible.

Upvotes: 1

MitMaro
MitMaro

Reputation: 5917

If I understand the question correctly then this will work. I have always called this a fluidic interface but I have no idea if that is the correct name for this or not. Essentially it works by returning this at the end of each method like in the example below.

class Foo {
    public function doFirst() {
        $this->bar = array('b', 'c', 'a');
        return $this;
    }

    public function sortOutputfromDofirstAndReturn() {
        sort($this->bar);
        return $this;
    }

}

Upvotes: 1

George Cummins
George Cummins

Reputation: 28906

doFirst() must return something (specifically, an object) for it to be eligible for chaining. sortOutputfromDofirstAndReturn() will operate on the object returned by doFirst(), so doFirst() should return like this:

public function doFirst() {
     // snip
     return $this;
}

Therefore, the last method (sortOutputfromDofirstAndReturn() in this case) cannot and should not prevent earlier methods in the chain from returning. However, it is up to the developer to ensure that those earlier methods return an object (rather than output or other data).

Upvotes: 0

Related Questions