Php和decorator模式中的路由
我不知道我是否正确使用了术语“路由”,但情况如下: 我创建了一个Php和decorator模式中的路由,php,design-patterns,url-routing,decorator,Php,Design Patterns,Url Routing,Decorator,我不知道我是否正确使用了术语“路由”,但情况如下: 我创建了一个.htaccess文件来“处理”(如果我的术语正确,则不知道)我的应用程序的url,如下所示: RewriteEngine On RewriteCond %{REQUEST_FILENAME} !-d RewriteCond %{REQUEST_FILENAME} !-f RewriteRule ^(.+)$ index.php?url=$1 [QSA,L] 现在我有这个: http://appname/controller/
.htaccess
文件来“处理”(如果我的术语正确,则不知道)我的应用程序的url,如下所示:
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.+)$ index.php?url=$1 [QSA,L]
现在我有这个:
http://appname/controller/method/parameter
http://appname/$url[0]/$url[1]/$url[2]
我所做的是:
$target = new $url[0]()
$controller = new Controller($target)
该方法的问题是,我无法使用在控制器构造函数中传递的对象中的方法:
我是这样决定的:
class Controller {
protected $target;
protected $view;
public function __construct($target, $view) {
$this->target = $target;
$this->view = $view;
}
public function __call($method, $arguments) {
if (method_exists($this->target, $method)) {
return call_user_func_array(array($this->target, $method), $arguments);
}
}
}
这很好,问题出现在我做路由的索引中,在这里
if(isset($url[2])){
if(method_exists($controller, $url[1])){
$controller->$url[1]($url[2])
}
} else {
if(method_exists($controller, $url[1])){
$controller->$url[1]()
}
}
其中$controller=新控制器($target)
问题是该方法不存在,尽管我可以直接使用它而不检查方法是否存在,但我如何解决这个问题?正如您已经发现的,当它被一个神奇的
\u调用
方法处理时,您无法使用方法\u存在。但是,您可以向控制器添加一个额外的公共方法来解决此问题:
class Controller {
protected $target;
protected $view;
public function __construct($target, $view) {
$this->target = $target;
$this->view = $view;
}
public function hasMethod($method) {
return is_callable(array($this->target, $method));
}
public function __call($method, $arguments) {
if (!is_callable(array($this->target, $method))) {
throw new \BadMethodCallException("Method `$method` is not callable");
}
return call_user_func_array(array($this->target, $method), $arguments);
}
}
所以
编辑:将method\u exists
更改为可调用
,以确保只有公共方法返回true。正如您已经发现的,当它被magic\u调用
方法处理时,您无法使用method\u exists
。但是,您可以向控制器添加一个额外的公共方法来解决此问题:
class Controller {
protected $target;
protected $view;
public function __construct($target, $view) {
$this->target = $target;
$this->view = $view;
}
public function hasMethod($method) {
return is_callable(array($this->target, $method));
}
public function __call($method, $arguments) {
if (!is_callable(array($this->target, $method))) {
throw new \BadMethodCallException("Method `$method` is not callable");
}
return call_user_func_array(array($this->target, $method), $arguments);
}
}
所以
编辑:将method\u exists
更改为is\u callable
,以确保只有公共方法返回true。使用is\u callable()
而不是method\u exists()
将返回正确的结果。使用is\u callable()
而不是method\u exists()
,它将返回正确的结果。简短回答:您做错了。现在再长一点
这里的主要问题是您试图将路由机制固定在控制器中。现代MVC模式中的控制器负责从用户输入中获取信息,并将其应用于模型层和/或当前视图以更改其状态
它应该而不是负责从原始输入数据中提取信息。这应该通过某种形式的路由机制来完成,在代码实际命中MVC三元组之前使用这种机制。最好是在应用程序的引导/启动阶段
基本上你会做一些类似的事情:
$uri = isset( $_GET['url'] ) ? $_GET['url'] : '/';
$request = new Request;
$request->setUrl( $url );
$router = new Router;
$router->route( $request );
$class = $request->getParameter('controller');
$method = $request->getParameter('action');
if ( !class_exists( $class ))
{
$class = 'ErrorController';
$method = 'missingController';
}
if ( !is_callable( [$class, $method] ))
{
$class = 'ErrorController';
$method = 'missingAction';
}
$controller = new $class( /* inject some dependencies */ );
$controller->{$method}( $request );
这当然是一个简化且有些笨拙的例子请勿复制生产代码中的粘贴。
简短回答:你做错了。现在再长一点
这里的主要问题是您试图将路由机制固定在控制器中。现代MVC模式中的控制器负责从用户输入中获取信息,并将其应用于模型层和/或当前视图以更改其状态
它应该而不是负责从原始输入数据中提取信息。这应该通过某种形式的路由机制来完成,在代码实际命中MVC三元组之前使用这种机制。最好是在应用程序的引导/启动阶段
基本上你会做一些类似的事情:
$uri = isset( $_GET['url'] ) ? $_GET['url'] : '/';
$request = new Request;
$request->setUrl( $url );
$router = new Router;
$router->route( $request );
$class = $request->getParameter('controller');
$method = $request->getParameter('action');
if ( !class_exists( $class ))
{
$class = 'ErrorController';
$method = 'missingController';
}
if ( !is_callable( [$class, $method] ))
{
$class = 'ErrorController';
$method = 'missingAction';
}
$controller = new $class( /* inject some dependencies */ );
$controller->{$method}( $request );
这当然是一个简化且有些笨拙的例子请勿复制生产代码中的粘贴。
这是误导性的-当在decorator上调用is_callable时,由于magic\u调用
回退,它将始终返回true。它没有考虑这次通话的结果。在这种情况下,获得所需结果的唯一方法是询问装饰器的对象是否具有该方法。虽然在这个方法中使用is\u callable
可能更好,尽管as方法存在,但是对于不可调用的受保护/私有方法,它将返回true。这是误导性的-is\u callable在装饰器上调用时总是返回true,因为有神奇的\u call
回退。它没有考虑这次通话的结果。在这种情况下,获得所需结果的唯一方法是询问装饰器的对象是否具有该方法。虽然在该方法中使用是可调用的
可能更好,但对于不可调用的受保护/私有方法,
将返回true。请停止将路由机制强制进入控制器。你违反了,我把它换了。。我昨天意识到了:谢谢!!!请停止将路由机制强制进入控制器。你违反了,我把它换了。。我昨天意识到了:谢谢!!!我想知道$router->route($request)是什么意思代码>你做了什么?它是否处理了$request
,然后将其返回变量?route()
方法“准备”了请求
实例。在实际的实现中,我将在路由器
实例中导入可能的路由,并将其转换为正则表达式。在这种情况下,route()
方法将遍历所有表达式,直到找到第一个匹配项。在这种情况下,从该regexp中提取的数据被分配给请求
实例。基本上,route()
方法准备了请求
。我想在Request
类中会有setUri
函数和getParameter
函数,而Router
类准备了请求,大概它设置了相应的控制器和操作,。。因此,在请求
调用获取参数
之前,控制器和操作
已经设置好了,所以我想象在路由器
类中,它设置了一个请求
数组,例如设置->请求('controller',$this->controller)
,就像这样吗?事实是,控制器