Slim Framework:路由和控制器

ame*_*iel 3 php slim

最初,我的Slim Framework应用程序具有经典结构

(的index.php)

<?php
$app = new \Slim\Slim();
$app->get('/hello/:name', function ($name) {
    echo "Hello, $name";
});
$app->run();
Run Code Online (Sandbox Code Playgroud)

但是当我添加更多路由和路由组时,我转向基于控制器的方法:

的index.php

<?php
$app = new \Slim\Slim();
$app->get('/hello/:name', 'HelloController::hello');
$app->run();
Run Code Online (Sandbox Code Playgroud)

HelloController.php

<?php
class HelloController {
    public static function hello($name) {
        echo "Hello, $name";
    }
}
Run Code Online (Sandbox Code Playgroud)

这是有效的,它有助于组织我的应用程序结构,同时让我为每个控制器方法构建单元测试.

但是,我不确定这是正确的方法.我觉得我在mount特殊的基础上嘲笑Silex的方法,这不可能是好的.在每个Controller方法中使用$ app上下文需要我使用\ Slim\Slim :: getInstance(),这似乎不如使用$ app那样有效.

那么......是否存在一种既能提高效率又能实现订单效率的解决方案,还是以路径/封闭梦魇为代价来提高效率?

ame*_*iel 6

我想我可以和你们分享我的所作所为.我注意到Slim\Slim中的每个路由方法在某个时刻称为mapRoute方法:

Slim.php

 protected function mapRoute($args)
    {
        $pattern = array_shift($args);
        $callable = array_pop($args);

        $route = new \Slim\Route(
              $pattern, 
              $callable, 
              $this->settings['routes.case_sensitive']
        );
        $this->router->map($route);
        if (count($args) > 0) {
            $route->setMiddleware($args);
        }

        return $route;
    }
Run Code Online (Sandbox Code Playgroud)

反过来,Slim\Route构造函数调用setCallable

Route.php

public function setCallable($callable)
{
    $matches = [];
    $app = $this->app;
    if (
         is_string($callable) && 
         preg_match(
           '!^([^\:]+)\:([a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)$!', 
           $callable, 
           $matches
         )
       ) {
            $class = $matches[1];
            $method = $matches[2];
            $callable = function () use ($class, $method) {
                static $obj = null;
                if ($obj === null) {
                    $obj = new $class;
                }
                return call_user_func_array([$obj, $method], func_get_args());
            };
        }

        if (!is_callable($callable)) {
            throw new \InvalidArgumentException('Route callable must be callable');
        }

        $this->callable = $callable;
    }
Run Code Online (Sandbox Code Playgroud)

这意味着使用Controller:方法(注意单个冒号)以可调用方式声明的路由被解释为非静态方法,因此在可调用闭包中实例化.所以我扩展了Slim\Slim和Slim\Route.在第一个我覆盖 mapRoute

\的Util\MySlim

 protected function mapRoute($args)
    {
        $pattern = array_shift($args);
        $callable = array_pop($args);

        $route = new \Util\MyRoute(
            $this, // <-- now my routes have a reference to the App
            $pattern, 
            $callable, 
            $this->settings['routes.case_sensitive']
        );
        $this->router->map($route);
        if (count($args) > 0) {
            $route->setMiddleware($args);
        }

        return $route;
    }
Run Code Online (Sandbox Code Playgroud)

你看,当instancing\Util\MyRoute我也传递了$ app,因为在MyRoute中有这样一个受保护的属性,而getCallable方法使用它来实例化控制器,从而允许使用具有$ app属性的非静态方法在他们中.

\的Util\MyRoute.php

public function setCallable($callable)
{
    $matches = [];
    $app = $this->app;
    if (
       is_string($callable) && 
       preg_match(
          '!^([^\:]+)\:([a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)$!', 
          $callable, 
          $matches
          )
       ) {
        $class = $matches[1];
        $method = $matches[2];

        $callable = function () use ($app, $class, $method) {
            static $obj = null;
            if ($obj === null) {
                $obj = new $class($app); // <--- now they have the App too!!
            }
            return call_user_func_array([$obj, $method], func_get_args());
        };
    }

    if (!is_callable($callable)) {
        throw new \InvalidArgumentException('Route callable must be callable');
    }

    $this->callable = $callable;
}
Run Code Online (Sandbox Code Playgroud)

就是这样.使用这两个类,我可以将$ app注入我在路由上声明的任何控制器,只要我使用单个冒号将控制器与方法分开.使用paamayim nekudotayim将该方法称为静态,因此如果我尝试访问其中的$ this-> app,则会抛出错误.

我使用blackfire.io运行测试......性能提升可以忽略不计.

优点:

  • 这节省了我在每个静态方法调用上调用$ app =\Slim\Slim :: getInstance()的痛苦,这些调用占整个文本的大约100行.
  • 它通过使每个控制器继承自抽象控制器类来开启进一步优化的方式,抽象控制器类又将应用程序方法包装到便捷方法中.
  • 它让我更了解Slim的请求和响应生命周期.

缺点:

  • 性能提升可以忽略不计
  • 你必须将所有路由转换为使用单个冒号而不是paamayin,并将所有控制器方法从静态转换为动态.
  • Slim基类的继承在推出v 3.0.0时可能会中断