douhui4699 2012-12-13 16:53
浏览 68

在Php和装饰模式中路由

I do not know if I am using the term 'routing' correctly, but here is the situation:

I created an .htaccess file to 'process' (dunno if my term is right) the url of my application, like this :

RewriteEngine On

RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f

RewriteRule ^(.+)$ index.php?url=$1 [QSA,L]

Now I have this :

http://appname/controller/method/parameter
http://appname/$url[0]/$url[1]/$url[2]

What I did is:

  1. setup a default controller, in case it is not specified in the url
  2. setup a Controller wrapper

I did it like this

$target = new $url[0]()
$controller = new Controller($target)

The problem with that one is that I can't use the methods in the object I passed in the constructor of the Controller:

I resolved it like this :

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

This is working fine, the problem occurs in the index where I did the routing, here it is

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]()
    }
}

where $controller = new Controller($target)

The problem is that the method doesn't exist, although I can use it directly without checking if method exist, how can I resolve this?

  • 写回答

3条回答 默认 最新

  • dtnnpt11795 2012-12-13 16:58
    关注

    As you've already discovered, you aren't able to use method_exists when it is being handled by a magic __call method. However, you can add an extra public method to your Controller to get around this problem:

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

    So...

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

    EDIT: Changed method_exists to is_callable to ensure only public methods return true.

    评论

报告相同问题?

悬赏问题

  • ¥15 matlab中使用gurobi时报错
  • ¥15 WPF 大屏看板表格背景图片设置
  • ¥15 这个主板怎么能扩出一两个sata口
  • ¥15 不是,这到底错哪儿了😭
  • ¥15 2020长安杯与连接网探
  • ¥15 关于#matlab#的问题:在模糊控制器中选出线路信息,在simulink中根据线路信息生成速度时间目标曲线(初速度为20m/s,15秒后减为0的速度时间图像)我想问线路信息是什么
  • ¥15 banner广告展示设置多少时间不怎么会消耗用户价值
  • ¥16 mybatis的代理对象无法通过@Autowired装填
  • ¥15 可见光定位matlab仿真
  • ¥15 arduino 四自由度机械臂