Reputation: 42758
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
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
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
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
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
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
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
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