2

我不知道我是否正确使用了“路由”一词,但情况如下:

我创建了一个.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]

我所做的是:

  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 = new Controller($target)

问题是方法不存在,虽然我可以直接使用它而不检查方法是否存在,我该如何解决这个问题?

4

3 回答 3

2

method_exists正如您已经发现的那样,当它被魔术__call方法处理时,您无法使用。但是,您可以向 Controller 添加一个额外的公共方法来解决此问题:

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);
  }
}

所以...

if(isset($url[2])){
    if($controller->hasMethod($url[1])){
         $controller->$url[1]($url[2])
    }
} else {
    if($controller->hasMethod($url[1])){
         $controller->$url[1]()
    }
}

编辑:更改method_existsis_callable确保只有公共方法返回 true。

于 2012-12-13T16:58:36.183 回答
1

使用is_callable()代替,method_exists()它将返回正确的结果。

于 2012-12-13T17:01:40.983 回答
1

简短的回答:你做错了。现在长一点...

这里的主要问题是您试图在控制器中硬塞路由机制。现代 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 );

这当然是简化且有些笨拙的示例。不要在生产代码中复制粘贴。

于 2012-12-26T23:04:27.297 回答