获取传递给调用实例方法的参数(new Reflection()?)

时间:2014-05-02 15:27:20

标签: php reflection

一般信息

  • 我有一个有实例的课程。
  • 此实例定义了__call magicc方法
  • 魔术方法__call()定义实例将响应的请求方法。
  • 使用的php版本是5.5。

我想要实现的目标

  • 魔术方法__call()定义实例将响应的请求方法。
  • $ request [0]是响应的正则表达式,$ request请求[1]闭包。
  • 我想定义一个前缀实例方法。
  • 前缀方法的第一个参数是字符串前置到$ request [0]。
  • 第二个参数是使用__call()。
  • 的实例方法数组

如果实例:

,则为magic __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(){

    }),
    ]);

我尝试了什么

我想要实现的是定义一个公共函数前缀($ prefix,$ callbackmethods = array())。这样,用户可以轻松地将字符串前置到要匹配的正则表达式。

反射类是正确的方法吗? 我在寻找错误的东西吗? 这可以通过Php实现。 还有其他选择吗? 如果反射类是正确的方法,任何人都可以告诉我如何正确使用它吗?

这对我来说是一个学习项目,所以请不要建议使用现有的路由类。

更新

我使用以下代码以不同方式解决了问题。在该代码之后,过滤在__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 个答案:

答案 0 :(得分: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获取灵感。