0

I have the following string:

$str = "methodA()->methodB()->methodC"

And i want to call that "chain" on an object

$obj->$str

I am currently splitting with ()-> and calling one by one, but there must be abetter way.

How can i call it on one line? thanks!

EDIT: Some more context information:

I created a Doctrine Behaviour for symfony 1.4 to be able to make certain tables from the schema searchable with Zend Lucene.

In short, i need a way to say to the behaviour "To get the searchable field you must call methodA()->methodB()->methodC()"

EDIT2: Maybe i wasnt clear enough. $obj and $str are determined at runtime, so some of your suggestions are not applicable.

EDIT3: In case you are wondering, i am currently doing this:

  <?php
  $chain = explode("()->",$str);
  $method = array_shift($chain);
  $value = $obj->$method();
  foreach($chain as $method){
    $value = $value->$method();
  }
5
  • So is the value in the string being created dynamically? Commented Sep 12, 2012 at 14:28
  • You could implement a helper function that would do it one by one. After that, you'd do it in one line. That's usually the way programming works. Commented Sep 12, 2012 at 14:30
  • @JavierIEH I think that without knowing there are going to be a fixed number of methods to where you could do something like $obj->{$method[0]}()->{$method[1]}()->{$method[2]}(), and assuming you don't want to use eval(), your current approach is actually suitable. Commented Sep 12, 2012 at 19:52
  • I thought PHP had a method to do this by default, i guess i'll make my own method like you pointed out Commented Sep 13, 2012 at 14:55
  • Your code makes it look like you are calling the first method in the chain twice. Seems like line 3 should just be $value = $obj; Commented Aug 13, 2015 at 18:42

6 Answers 6

2

After writing my comment to the main question I thought of a possible solution, though a little verbose and manual (you would have to make as many case statements as you would reasonably expect for the number of chained methods).

function chain_execute($obj, $str) {
    $chain = explode("->",$str);
    $chain = array_map('trim', $chain);
    $chain_count = count($chain);
    switch($chain_count) {
        case 1:
            return $obj->{$chain[0]}();
            break;
        case 2:
            return $obj->{$chain[0]}()->{$chain[0]}();
            break;
        case 3:
            return $obj->{$chain[0]}()->{$chain[1]}()->{$chain[2]}();
            break;
        // etc.
        default:
            // not a value you were expecting
            throw new Exception('Invalid number of methods chained: ' . $chain_count);
            break;
    }
}

Usage would be:

$result = chain_execute($obj, "methodA->methodB->methodC");
Sign up to request clarification or add additional context in comments.

3 Comments

I like this. What is the difference between doing $obj->$chain[0]() and $obj->{$chain[0]}() ?
@JavierIEH That is just bracket notation around the variable which I think makes it a little more readable in this case. I also want to say that at some point I tried it without brackets and was having problems, but I have been doing with brackets so long I don't know if that is still the case.
Note I just now changed up the explode bit, as the previous format would have had an extra "()" in the name on the last array member. You can make the explode whatever you like. Or keep the old string format and strip the "()".
0

I generally recommend against using eval, but...

eval("$obj->$str;");

I would re-evaluate your case, though, and probably call each function directly one-by-one as expected.

Comments

0

Your method is already good but... try

$str = "{$obj->methodA()->methodB()->methodC()}";

3 Comments

The $obj is determined at runtime.
so what? change $obj to your current runtime object
I guess what i dont understand is what does the "{ }" do to make the difference. ¿What does it do? Thanks
0

That is an evil approach.

Could you provide (I'm curious) a use case?

You could use call_user_func() in succession, for which you can write a helper method which is able to parse your notation and call the chain.

1 Comment

I created a Doctrine Behaviour for symfony 1.4 to be able to make certain tables from the schema searchable with Zend Lucene. In short, i need a way to say to the behaviour "To get the searchable field you must call methodA()->methodB()->methodC()"
0

Does the following work?

$str = $methodA()->$methodB()->$methodC();

Comments

0

My answer assumes you have access to the methods (methodA, methodB and methodC), can edit them, and that each method belongs to the class which $obj is an instance of.

Update each method to return an instance of the class, this will work assuming they don't return any primitive datatype like int, bool, string or otherwise:

<?php
class Example {
    public function methodA() {
        echo "method a\n";
        return $this;
    }
    public function methodB() {
        echo "method b\n";
        return $this;
    }
    public function methodC() {
        echo "method c\n";
        return $this;
    }
}
?>

Now instantiate Example, store into $obj and call your methods in succession:

<?php
$obj = new Example();
$obj->methodA()->methodB()->methodC();
?>

Which will output:

method a
method b
method c

1 Comment

Those methods don't belong to the same class. Instead, the method "methodB()" is called on the return of "methodA()" and so on

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.