代码研磨 Slim v3 (一)--app->get()&route->add()

index.php代码如下:

$app->get('/forbase', function ($request, $response, $args){
    Example\Module\Base::instance()->init($request,$response);
    return $response;
})->add(Example\MiddleWare\MyMiddleware::instance(Example\Module\Base::instance()));

APP->get()代码如下:

/**
     * Add GET route
     *
     * @param  string $pattern  The route URI pattern
     * @param  mixed  $callable The route callback routine
     *
     * @return \Slim\Interfaces\RouteInterface
     */
    public function get($pattern, $callable)
    {
        return $this->map(['GET'], $pattern, $callable);
    }

APP->map()代码如下:

/**
     * Add route with multiple methods
     *
     * @param  string[] $methods  Numeric array of HTTP method names
     * @param  string   $pattern  The route URI pattern
     * @param  mixed    $callable The route callback routine
     *
     * @return RouteInterface
     */
    public function map(array $methods, $pattern, $callable)
    {
        if ($callable instanceof Closure) {
            $callable = $callable->bindTo($this->container); 
        }

        $route = $this->container->get('router')->map($methods, $pattern, $callable);
        if (is_callable([$route, 'setContainer'])) {
            $route->setContainer($this->container);
        }

        if (is_callable([$route, 'setOutputBuffering'])) {
            $route->setOutputBuffering($this->container->get('settings')['outputBuffering']);
        }
        return $route;
    }

执行完这个map方法后,这个route就被创建了。

 

$callable = $callable->bindTo($this->container);
  
用来将$this->container绑定到$callable中,这样$callable就可以访问container里的数据,but我没找到怎么用。这是遗留问题之一。

 

$route = $this->container->get('router')->map($methods, $pattern, $callable);
  做了两件事:
    1.获取router;
    2.router调用map().

 

看看Slim\Container类:

class Container extends PimpleContainer implements ContainerInterface
{
    /**
     * Finds an entry of the container by its identifier and returns it.
     *
     * @param string $id Identifier of the entry to look for.
     *
     * @throws ContainerValueNotFoundException  No entry was found for this identifier.
     * @throws ContainerException               Error while retrieving the entry.
     *
     * @return mixed Entry.
     */
    public function get($id)
    {
        if (!$this->offsetExists($id)) {
            throw new ContainerValueNotFoundException(sprintf('Identifier "%s" is not defined.', $id));
        }
        return $this->offsetGet($id);
    }
}
get()会调用$this->offsetGet(),这个方法在Pimple\Container里。
看看PimpleContainer类:
class Container implements \ArrayAccess
{
  public function offsetGet($id)
    {
        if (!isset($this->keys[$id])) {
            throw new \InvalidArgumentException(sprintf('Identifier "%s" is not defined.', $id));
        }

        if (
            isset($this->raw[$id])
            || !is_object($this->values[$id])
            || isset($this->protected[$this->values[$id]])
            || !method_exists($this->values[$id], '__invoke')
        ) {
            return $this->values[$id];
        }

        if (isset($this->factories[$this->values[$id]])) {
            return $this->values[$id]($this);
        }

        $raw = $this->values[$id];
        $val = $this->values[$id] = $raw($this);
        $this->raw[$id] = $raw;

        $this->frozen[$id] = true;

        return $val;
    }
}

  这个类实现了\ArrayAccess接口,官方的解释是说呢,使得访问对象像访问对象那样,即obj['name']拿到name属性。其实能够像访问数组那样访问对象的原因在于ArrayAccess这个接口里的所有方法,在obj['name']就是访问了obj的offsetGet()方法。可以自己覆写这个方法,实现数据存入哪里已经从哪里取出。

  这两句话也比较有意思:$raw = $this->values[$id];$val = $this->values[$id] = $raw($this);  一开始没搞懂$raw($this)是干什么的,因为经过上一步的$this->values[$id]其实就已经拿到Closure了,应该很应当的想到是Closure的参数。没有搞明白的原因在于我认为这一步就已经执行Closure了。我错了,$raw($this)这里才执行了闭包函数。是不是可以总结为只有Closure被调用了才执行,而调用应该来自 “=“的右侧。

  map()用来创建新的route并添加到router中。

 

public function map($methods, $pattern, $handler)
{
    if (!is_string($pattern)) {
        throw new InvalidArgumentException('Route pattern must be a string');
    }

    // Prepend parent group pattern(s)
    if ($this->routeGroups) {
        $pattern = $this->processGroups() . $pattern;
    }

    // According to RFC methods are defined in uppercase (See RFC 7231)
    $methods = array_map("strtoupper", $methods);

    // Add route
    $route = new Route($methods, $pattern, $handler, $this->routeGroups, $this->routeCounter);
    $this->routes[$route->getIdentifier()] = $route;
    $this->routeCounter++;

    return $route;
} 

$methods = array_map("strtoupper", $methods); 调用了库函数array_map,用途就是将$methods作为参数出传入'strtoupper'中。

new Route($methods, $pattern, $handler, $this->routeGroups, $this->routeCounter); 创建了新的route。

/**
 * Route
 */
class Route extends Routable implements RouteInterface
{
    public function __construct($methods, $pattern, $callable, $groups = [], $identifier = 0)
    {
        $this->methods  = $methods;
        $this->pattern  = $pattern;
        $this->callable = $callable;
        $this->groups   = $groups;
        $this->identifier = 'route' . $identifier;
    }
}

  router中还给route标识了identify,其实就是'routeXX'的样式。

$route->setContainer($this->container);

$route->setOutputBuffering($this->container->get('settings')['outputBuffering']);为新添加的route设置container和outputBuffering。
最后,app->get()会返回一个route。

route add Middleware代码即index.php 中->add();
route->add()方法其实是使用Routable这个抽象类的。

/**
 * A routable, middleware-aware object
 *
 * @package Slim
 * @since   3.0.0
 */
abstract class Routable
{
    /**
     * Prepend middleware to the middleware collection
     *
     * @param mixed $callable The callback routine
     *
     * @return static
     */
    public function add($callable)
    {
        $callable = $this->resolveCallable($callable);
        if ($callable instanceof Closure) {
            $callable = $callable->bindTo($this->container);
        }

        $this->middleware[] = $callable;
        return $this;
    }
}

  在add里还是做了一个绑定,让闭包函数可以访问$this->container。接着将Closure装入到middleware[]数组中,在这个closure也就是route middleware run的时候就会将middleware数组中的元素加入到Middleware stack中。通过CallMiddlewareStack来依次执行Middleware。

  至此,APP成功添加了一个route,并且给这个route添加了一个middleware。

 

posted @ 2016-01-28 19:24  浮萍生根  阅读(450)  评论(0编辑  收藏  举报