一般信息
我想要实现的目标
如果实例:
,则为magic __call()方法public function __call($method, $request) {
$this->_links[strtoupper($method)] [$this->_baseUrl . $request[0]] = $request[1];
return $this;
}
现在的前缀方法;
public function prefix($prefix, $callbackmethods = array()) {
foreach ($callbackmethods as $closure) {
$reflection = new ReflectionFunction($closure);
}
return $this;
}
我想要实现的代码结构示例。
# Normal method call to __call
$link->get('/', function(){
});
# Prefic the regex of multiple method calls to __call
$link->prefix('/admin', [
$link->get('user/(\d+)', function(){
}),
$link->post('user/(\d+)', function(){
}),
]);
我尝试了什么
我想要实现的是定义一个公共函数前缀($ prefix,$ callbackmethods = array())。这样,用户可以轻松地将字符串前置到要匹配的正则表达式。
反射类是正确的方法吗? 我在寻找错误的东西吗? 这可以通过Php实现。 还有其他选择吗? 如果反射类是正确的方法,任何人都可以告诉我如何正确使用它吗?
这对我来说是一个学习项目,所以请不要建议使用现有的路由类。
更新
我使用以下代码以不同方式解决了问题。在该代码之后,过滤在__call()方法内完成。请参阅下面提供的答案,以获得更优雅的解决方案。
/**
*
* @param type $prefix
* @param type $requestMethod
* @return \Link
*/
public function prefix($prefix, $requestMethod = false) {
$this->_applyPrefix = true;
if ($requestMethod != false) {
$this->_prefixMethod = strtoupper($requestMethod);
}
$this->_prefix = $prefix;
return $this;
}
/**
*
* @return \Link
*/
public function end() {
$this->_applyPrefix = false;
$this->_prefixMethod = false;
$this->_prefix = false;
return $this;
}
答案 0 :(得分:1)
此设置的问题是__call()
方法本身会将路由添加到路由列表中。因此,在对prefix()
的调用中包含这些调用并不会改变,__call()
仍将首先执行。
因此它与匿名函数/闭包的工作原理无关,问题在于执行的顺序。
我建议你选择一种稍微不同的方法:
Route
)的类。您可以通过这种方式更轻松地管理它。__call()
方法创建并返回一个Route对象,但是不要让它将路由添加到列表中。prefix()
方法根据传递给它的路由创建新的Route
对象。add()
,将路线添加到列表中。这看起来像这样:
class Router
{
/**
* @type array
*/
private $routes = array();
/**
* @param Route|Route[] $routes
*/
public function add($routes)
{
foreach ((array)$routes as $route) {
$this->routes[] = $route;
}
}
/**
* @param string $prefix
* @param Route[] $routes
* @return Route[]
*/
public function prefix($prefix, array $routes)
{
$prefixedRoutes = array();
foreach ($routes as $route) {
$prefixedRoutes[] = new Route(
$route->getMethod(),
$prefix . $route->getUri(),
$route->getController()
);
}
return $prefixedRoutes;
}
/**
* @param string $name
* @param array $arguments
* @return Route
*/
public function __call($name, array $arguments)
{
$method = $name;
$uri = $arguments[0];
$controller = $arguments[1];
return new Route($method, $uri, $controller);
}
}
class Route
{
/**
* $var string
*/
private $method;
/**
* @var string
*/
private $uri;
/**
* @var callable
*/
private $controller;
/**
* @param string $method
* @param string $uri
* @param callable $controller
*/
public function __construct($method, $uri, $controller)
{
$this->method = $method;
$this->uri = $uri;
$this->controller = $controller;
}
/**
* @param string $prefix
*/
public function prefix($prefix)
{
$this->uri = $prefix . $this->uri;
}
/**
* @return string
*/
public function getMethod()
{
return $this->method;
}
/**
* @return string
*/
public function getUri()
{
return $this->uri;
}
/**
* @return callable
*/
public function getController()
{
return $this->controller;
}
}
你可以像这样使用它:
$router->add(
$router->get('/', function() {
// ...
});
);
$router->add(
$router->prefix('/blog', array(
$router->get('/(\d+)', function() {
// ...
}),
$router->post('/(\d+)', function() {
// ...
})
))
);
现在这是一个非常非常简单的设置。它可以更优雅地解决。
我强烈建议您查看Silex(这是一个基于Symfony2组件的微框架)。它有一个看起来很像很多的路由器,就像你想要实现的那样。你可以从that code获取灵感。