如何在封闭中引用它

时间:2018-01-15 20:24:47

标签: php oop model-view-controller routing closures

我使用的是PHP 7.1.1版。

在我的MVC的index.php中,我创建了一个路由集合($routes)。为此,我想添加一个路由组(addGroup)。此添加过程依赖于闭包(例如匿名函数),作为参数传递给addGroup。关闭内部我试图用$this 引用该集合,以便我可以添加一个或多个路由(使用addRoute,一个集合的方法)。

不幸的是我无法实现这一点,尽管我做了一些尝试。我想念一个封闭理论,某个地方。如果你能给我一个建议,我将不胜感激。

“问题”是,为了实现用户的简化可用性,我试图避免直接使用闭包参数。为什么?因为在addGroup里面我已经在集合的范围内,从那里我调用了闭包。这样我就可以将集合的实例($this)作为参数传递给executeGroupHandler方法,因此也传递给executeGroupHandler

感谢您的时间和耐心!

的index.php

$routes = new RouteCollection();

$routes->addGroup('/test', function() {
    $this->addRoute('GET', '/group', function() {
        echo 'Hello from route /test/group';
    });
});

RouteCollection

class RouteCollection implements CollectionInterface {

    public function addGroup(string $groupPattern, callable $groupHandler) {
        $group = new RouteGroup($groupPattern, $groupHandler);

        return $group->executeGroupHandler($this);
    }

    public function addRoute($httpMethod, string $routePattern, $routeHandler) {
        //...
        return $this;
    }

}

RouteGroup

class RouteGroup {

    private $groupPattern;
    private $groupHandler;

    public function __construct(string $groupPattern, callable $groupHandler) {
        $this->groupPattern = $groupPattern;
        $this->groupHandler = $groupHandler;
    }

    public function executeGroupHandler(CollectionInterface $routeCollection) {
        return call_user_func_array($this->groupHandler, [$routeCollection]);
    }

}

3 个答案:

答案 0 :(得分:0)

试试这个:

$routes->addGroup('/test', function() use ($routes) {
    $routes->addRoute('GET', '/group', function() {
        echo 'Hello from route /test/group';
    });
});

您正尝试从类范围之外的闭包中访问$this$routes

答案 1 :(得分:0)

从抽象的意义上说,你可以使用闭包的bind函数来实现这个目的:

$routes = new RouteCollection();
$routeHandler = Closure::bind(function() {
    $this->addRoute('GET', '/group', function() {
       echo 'Hello from route /test/group';
   });
}, $routes);

$routes->addGroup('/test', $routeHandler);

当你想要传递这个闭包但想要保持范围时,这很有用。

答案 2 :(得分:0)

我决定在这篇文章中提出解决方案,作为公认的答案,仅提供对其的简要概述及其实施。但是:

现金:

优雅地满足我所有要求的解决方案,以及我选择使用的解决方案,由@apokryfos友情提供。 @ArtisticPhoenix提出的想法也非常正确。

非常感谢你们!感谢您的帮助。

解决方案:

这个想法是,如果你将闭包绑定到一个对象 - 在我的例子中是集合($routes),那么该对象可以在闭包的范围内访问,并且可以用$this

基于这个想法,我可以实现一个实现,它不仅允许用户不将任何参数传递给组处理程序回调(闭包函数),而且还传递参数(容器对象$routes)如果他愿意的话。

解决方案的实施:

的index.php

$routes = new RouteCollection();

$routes
    // The most simple and elegant use-case.
    ->addGroup('/group1', function() {
        $this->addRoute('GET', '/route1', function() {
            echo 'Hello from route /group1/route1';
        });
    })
    // An optional use-case.
    ->addGroup('/group2', function($routes) {
        $routes->addRoute('GET', '/route1', function() {
            echo 'Hello from route /group2/route1';
        });
    })
    // Another optional use-case.
    ->addGroup('/group3', function() use ($routes) {
        $routes->addRoute('GET', '/route1', function() {
            echo 'Hello from route /group3/route1';
        });
    })
;

RouteCollection

class RouteCollection implements CollectionInterface {

    public function addGroup(string $groupPattern, callable $groupHandler) {
        if ($groupHandler instanceof Closure) {
            $groupHandler = $groupHandler->bindTo($this);
        }

        $group = new RouteGroup($groupPattern, $groupHandler);

        $group->executeGroupHandler($this);

        return $this;
    }

}

RouteGroup

class RouteGroup {

    public function executeGroupHandler(CollectionInterface $routeCollection) {
        return call_user_func_array($this->groupHandler, [$routeCollection]);
    }

}