3

If I have a class like:

class MyClass
{
   public function foo() 
   {
      echo "foo";
   }
}

And then outside of the class instantiate it and try to create an anonymous function in it:

$mine = new MyClass();

$mine->bar = function() {
   echo "bar";
}

And then try to call it like $mine->bar(), I get:

Fatal error: Call to undefined method MyClass::bar() in ...

How can I create an anonymous function / closure on a class instance?

Aside: Before you tell me I should rethink my logic or use interfaces and OOP properly, in my case, it's a convenience method that applies to this specific instance of a bastardized class in an attempt to clean-up a legacy procedural application. And yes, I'm using PHP 5.3+

3 Answers 3

3

See my blog article here: http://blog.flowl.info/2013/php-container-class-anonymous-function-lambda-support/

You need to add a magic __call function:

public function __call($func, $args) {
    return call_user_func($this->$func, $args);
}

The problem is that within this construct you can call private methods from public scope. I suggest not to simply add new variables to a class that are not defined. You can avoid this using magic __set functions and catch all undefined variables in a container (= array, like in my blog post) and change the call_user_func behaviour to call only inside the array:

// inside class:
public $members = array();

public function __call($func, $args) {
    // note the difference of calling only inside members:
    return call_user_func($this->members[$func], $args);
}
Sign up to request clarification or add additional context in comments.

2 Comments

Great! It just so happened the class extended a class implementing magic methods so it was no sweat adding this in. One addition I made is to check with is_callable() before actually calling it. Thanks!
this can be extended in some ways, but you get the idea behind it B-)
1

__call

This will work.

class Foo {

    public $bar;
    public function __construct()
    {
        $this->bar = function()
        {
            echo 'closure called';
        };

        $this->bar();
    }

    public function __call($method, $args) {
        return call_user_func($this->$method, $args);
    }

}

new Foo();

1 Comment

First come - first served :)
1

The function IS being created. PHP has a problem with calling it.

Dirty, but works:

$f = $mine->bar;
$f();

2 Comments

Interesting. Reminds me of the issue with dynamic namespaces. You have to put it in a variable first before instantiating like $ns = "\\App\\Lib\\" . $myClass; $object = new $ns();`
@cillosis you can (at least in PHP 5.4) use brackets: $object = new {$ns}(); same with fluent classes: does not work: $x = new xxx()->method(); does work: $x = (new xxx())->method();

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.