我使用的是PHP 7.1.1版。
在我的MVC的index.php
中,我创建了一个路由集合($routes
)。为此,我想添加一个路由组(addGroup
)。此添加过程依赖于闭包(例如匿名函数),作为参数传递给addGroup
。关闭内部我试图用$this
引用该集合,以便我可以添加一个或多个路由(使用addRoute
,一个集合的方法)。
不幸的是我无法实现这一点,尽管我做了一些尝试。我想念一个封闭理论,某个地方。如果你能给我一个建议,我将不胜感激。
“问题”是,为了实现用户的简化可用性,我试图避免直接使用闭包参数。为什么?因为在addGroup
里面我已经在集合的范围内,从那里我调用了闭包。这样我就可以将集合的实例($this
)作为参数传递给executeGroupHandler
方法,因此也传递给executeGroupHandler
。
感谢您的时间和耐心!
$routes = new RouteCollection();
$routes->addGroup('/test', function() {
$this->addRoute('GET', '/group', function() {
echo 'Hello from route /test/group';
});
});
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;
}
}
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]);
}
}
答案 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
)如果他愿意的话。
$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';
});
})
;
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;
}
}
class RouteGroup {
public function executeGroupHandler(CollectionInterface $routeCollection) {
return call_user_func_array($this->groupHandler, [$routeCollection]);
}
}