2013-06-25 3 views
4

내 응용 프로그램의 라우팅 부분에 Route and Router 클래스가 있습니다. Route는 특정 매핑 된 경로 및 해당 정보를 설정하고 가져 오는 메서드에 대한 정보 만 보유합니다. 나는이 때 나는이instanceof Closure returns false

$route = new Route(); 
$route->setTarget($target); 

* 두 번째 매개 변수처럼,

Router::map('/', function(){}, array()); 

는 내가 두 번째 매개 변수 (폐쇄)를 저장, 같은 폐쇄를 전달하는 시도하고

변수 $ 대상

$target = $route->getTarget(); 
if($target instanceof Closure) 
{ 
    echo 1; 
}else 
{ 
    echo 0; 
} 

0을 인쇄하지만 시도 할 때 print_r($target) 나는

Closure Object () 

클래스 경로

class Router { 

    /** 
    * Array that holds all Route objects 
    * @var array 
    */ 
    private static $_routes = array(); 

    /** 
    * Array to store named routes in, used for reverse routing. 
    * @var array 
    */ 
    private static $_namedRoutes = array(); 

    /** 
    * The base REQUEST_URI. Gets prepended to all route url's. 
    * @var string 
    */ 
    private static $_basePath = ''; 

    /** 
    * Set the base url - gets prepended to all route url's. 
    * @param string $base_url 
    */ 
    public function setBasePath($basePath) { 
     static::$_basePath = (string) $basePath; 
    } 

    /** 
    * Route factory method 
    * 
    * Maps the given URL to the given target. 
    * @param string $routeUrl string 
    * @param mixed $target The target of this route. Can be anything. You'll have to provide your own method to turn *  this into a filename, controller/action pair, etc.. 
    * @param array $args Array of optional arguments. 
    */ 
    public static function map($routeUrl, $target, array $args = array()) { 
     $route = new Route(); 

     $route->setUrl(static::$_basePath . $routeUrl); 

     $route->setTarget($target); 

     if(isset($args['methods'])) { 
      $methods = explode(',', $args['methods']); 
      $route->setMethods($methods); 
     } 

     if(isset($args['filters'])) { 
      $route->setFilters($args['filters']); 
     } 

     if(isset($args['name'])) { 
      $route->setName($args['name']); 
      if (!isset(static::$_namedRoutes[$route->getName()])) { 
       static::$_namedRoutes[$route->getName()] = $route; 
      } 
     } 

     static::$_routes[] = $route; 
    } 

    /** 
    * Matches the current request against mapped routes 
    */ 
    public static function matchCurrentRequest() { 
     $requestMethod = (isset($_POST['_method']) && ($_method = strtoupper($_POST['_method'])) && in_array($_method,array('PUT','DELETE'))) ? $_method : $_SERVER['REQUEST_METHOD']; 
     $requestUrl = $_SERVER['REQUEST_URI']; 

     // strip GET variables from URL 
     if(($pos = strpos($requestUrl, '?')) !== false) { 
      $requestUrl = substr($requestUrl, 0, $pos); 
     } 

     return static::match($requestUrl, $requestMethod); 
    } 

    /** 
    * Match given request url and request method and see if a route has been defined for it 
    * If so, return route's target 
    * If called multiple times 
    */ 
    public static function match($requestUrl, $requestMethod = 'GET') { 

     foreach(static::$_routes as $route) { 

      // compare server request method with route's allowed http methods 
      if(!in_array($requestMethod, $route->getMethods())) continue; 

      // check if request url matches route regex. if not, return false. 
      if (!preg_match("@^".$route->getRegex()."*[email protected]", $requestUrl, $matches)) continue; 

      $params = array(); 

      if (preg_match_all("/:([\w-]+)/", $route->getUrl(), $argument_keys)) { 

       // grab array with matches 
       $argument_keys = $argument_keys[1]; 

       // loop trough parameter names, store matching value in $params array 
       foreach ($argument_keys as $key => $name) { 
        if (isset($matches[$key + 1])) 
         $params[$name] = $matches[$key + 1]; 
       } 

      } 

      $route->setParameters($params); 

      if($route) 
      { 
       static::respond($route); 
      } 
      return $route; 



     } 

     return false; 
    } 



    /** 
    * Reverse route a named route 
    * 
    * @param string $route_name The name of the route to reverse route. 
    * @param array $params Optional array of parameters to use in URL 
    * @return string The url to the route 
    */ 
    public function generate($routeName, array $params = array()) { 
     // Check if route exists 
     if (!isset(static::$_namedRoutes[$routeName])) 
      throw new Exception("No route with the name $routeName has been found."); 

     $route = static::$_namedRoutes[$routeName]; 
     $url = $route->getUrl(); 

     // replace route url with given parameters 
     if ($params && preg_match_all("/:(\w+)/", $url, $param_keys)) { 

      // grab array with matches 
      $param_keys = $param_keys[1]; 

      // loop trough parameter names, store matching value in $params array 
      foreach ($param_keys as $i => $key) { 
       if (isset($params[$key])) 
        $url = preg_replace("/:(\w+)/", $params[$key], $url, 1); 
      } 
     } 

     return $url; 
    } 

    private static function respond($route) 
    { 
     $target = $route->getTarget(); 
     $path = null; 

     if($target instanceof Closure) 
     { 
      call_user_func($target); 

     }else 
     { 
      if(is_string($target)) 
      { 
       $target   = explode('@', $target); 
       $target[0]  = explode(':', $target[0]); 
       $controller  = $target[0][0]; 
       $method   = $target[0][1]; 
       $application = $target[1]; 
       $path   = path('app') . $application . '/controllers/' . ucfirst($controller) . '.php'; 

      } 

      if(is_array($target)) 
      { 
       $controller  = $target['controller']; 
       $method   = $target['method']; 
       $application = $target['application']; 
       $path   = path('app') . $application . '/controllers/' . ucfirst($controller) . '.php'; 
      } 


      if(file_exists($path)) 
      { 
       $obj = require($path); 
       $obj = new $controller(); 
       $obj->$method(); 
      }else 
      { 
       echo '404'; 
      } 
     } 
    } 

} 
+2

코드를 훨씬 더 간결한 예제로 살펴보십시오. 그렇게하면 [제공되는 코드가 작동합니다] (http://3v4l.org/BgDmb). – nickb

+0

주제에 대해 IMHO'instanceof Closure '는 코드를 너무 많이 가정하기 때문에 코드를 작성하는 좋은 방법이 아닙니다. 내 자신의 코드에서 나는 항상 is_object ($ c) && is_callable ($ c)'를 사용한다. – Jon

+0

네임 스페이스 내에 있습니까? 'var_dump '를 사용하여 타입을 다시 확인하십시오. 빠른 테스트 결과는 다음과 같습니다. http://phpfiddle.org/main/code/iud-tcr - 또한 Jon은 좋은 점을 제공합니다. –

답변

20

이 코드에서 네임 스페이스를 사용하고

class Route { 

    /** 
    * URL of this Route 
    * @var string 
    */ 
    private $url; 

    /** 
    * Accepted HTTP methods for this route 
    * @var array 
    */ 
    private $methods = array('GET','POST','PUT','DELETE'); 

    /** 
    * Target for this route, can be anything. 
    * @var mixed 
    */ 
    private $target; 

    /** 
    * The name of this route, used for reversed routing 
    * @var string 
    */ 
    private $name; 

    /** 
    * Custom parameter filters for this route 
    * @var array 
    */ 
    private $filters = array(); 

    /** 
    * Array containing parameters passed through request URL 
    * @var array 
    */ 
    private $params = array(); 

    public function getUrl() { 
     return $this->url; 
    } 

    public function setUrl($url) { 
     $url = (string) $url; 

     // make sure that the URL is suffixed with a forward slash 
     if(substr($url,-1) !== '/') $url .= '/'; 

     $this->url = $url; 
    } 

    public function getTarget() { 
     return $this->target; 
    } 

    public function setTarget($target) { 
     $this->target = $target; 
    } 

    public function getMethods() { 
     return $this->methods; 
    } 

    public function setMethods(array $methods) { 
     $this->methods = $methods; 
    } 

    public function getName() { 
     return $this->name; 
    } 

    public function setName($name) { 
     $this->name = (string) $name; 
    } 

    public function setFilters(array $filters) { 
     $this->filters = $filters; 
    } 

    public function getRegex() { 
     return preg_replace_callback("/:(\w+)/", array(&$this, 'substituteFilter'), $this->url); 
    } 

    private function substituteFilter($matches) { 
     if (isset($matches[1]) && isset($this->filters[$matches[1]])) { 
       return $this->filters[$matches[1]]; 
      } 

      return "([\w-]+)"; 
    } 

    public function getParameters() { 
     return $this->parameters; 
    } 

    public function setParameters(array $parameters) { 
     $this->parameters = $parameters; 
    } 




} 

급 라우터거야?

그렇다면 전역 이름 공간으로 이스케이프하려면 클로저 클래스 이름을 \Closure으로 지정해야합니다.

+0

빌어 먹을, 네가 네임 스페이스를 잊어 버렸어. 너는 생명의 은인, thnx 야. –