Justin E
Justin E

Reputation: 1250

PHP Closure returns an object

Closures allow me to use for example:

$app->register('test', function() { return 'test closure'; });
echo $app->test();

Problem is, it's not working when the closure is returning an object. As in:

$app->register('router', function() { return new Router(); });
$app->router->map($url, $path);

I get: Fatal error: Call to undefined method Closure::map() in index.php on line 22

/** app.php **/
class App {
    public function __construct(){
        $this->request = new Request();
        $this->response = new Response();
    }
    public function register($key, $instance){
        $this->$key = $instance;
    }
    public function __set($key, $val){
        $this->$key = $val;
    }
    public function __get($key){
        if($this->$key instanceof Closure){
            return $this->$key();
        }else return $this->$key;
    }
    public function __call($name, $args){
        $closure = $this->$name;
        call_user_func_array( $closure, $args ); // *
    }
}

/** router.php **/
class Router {
    public function map($url, $action){

    }  
}

Addon Details:

Does Work:

$app->register('router', new Router());
$app->router->map($url, $action);

but the purpose of returning an object in a closure is to provide last minute configuration as needed...I tried researching this, however most of the topics just describe how to call closures, which I already understand. That is why there is a __call method in the app class...

Edit:

$app->router()->map($url, $action);
Fatal error: Call to a member function map() on null in

Upvotes: 2

Views: 563

Answers (1)

Matteo Riva
Matteo Riva

Reputation: 25060

The point is that a closure returns a Closure object, that's why it's different from the "Does work" version.

Also when you call

$app->router()

__call kicks in, not __get, so you get nothing since no callable router is defined in your class. I don't think there is a direct syntax to do what you want, you have to pass through a temp variable like:

$temp = $app->router;
$temp()->map($url, $action);

Upvotes: 1

Related Questions