2014-05-02 78 views
1

一般信息獲取參數傳遞給__call實例方法(新Reflecction()?)

  • 我有了一個實例的類。
  • 此實例具有__call magicc方法定義
  • 魔術方法__call()定義實例將響應的請求方法。
  • 使用的php版本是5.5。

我想實現

  • 的魔術方法__call什麼()定義了請求方法的實例將作出迴應。
  • $ request [0]是響應的正則表達式,而$ request [1]是閉包。
  • 我想定義一個前綴實例方法。
  • 前綴方法的第一個參數是前綴爲$ request [0]的字符串。
  • 第二個參數是一個使用__call()的實例方法數組。

魔術__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(){ 

    }), 
    ]); 

我曾嘗試

我想要實現的是定義一個公共職能前綴($前綴,$ callbackmethods =陣列())。這樣用戶可以很容易地在正則表達式前加一個字符串來匹配。

反射類是正確的方式嗎? 我在找錯誤的東西嗎? 這可以用Php來實現。 還有其他選擇嗎? 任何人都可以告訴我如何正確使用它,如果反射類是正確的方式?

這是一個學習項目,所以請不要建議使用現有的路由類。

更新

我有以下code.After不同的解決問題的代碼進行過濾的__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; 
    } 

回答

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中獲得靈感。

+0

謝謝你的回答。這對我很有幫助!我將學習Silex源代碼以瞭解它們如何處理事情。我一直在研究SPL。來自Ruby背景的所有教育都非常具有教育意義。我會很快獎勵賞金。 – Dany

+0

我已經爲我的問題添加了另一個解決方案。對於這個研究項目,我希望儘可能簡單,不要超出我的知識範圍。你的回答是非常感謝,並將與獎金研究和獎勵。 – Dany