Slim Framework:路由和控制器

时间:2015-02-28 00:41:25

标签: php slim

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

(的index.php)

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

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

的index.php

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

HelloController.php

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

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

但是,我不确定这是正确的方法。我觉得我在特殊的基础上嘲笑Silex的mount方法,这不可能是好的。在每个Controller方法中使用$ app上下文需要我使用\ Slim \ Slim :: getInstance(),这似乎比使用$ app更有效,就像一个闭包可以。

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

1 个答案:

答案 0 :(得分: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;
    }

反过来,Slim \ Route构造函数名为 setCallable

Route.php

public function setCallable($callable)
    {
        $matches = [];
        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];
            //\Util\Helpers::prdie('Matches are', $matches);
            $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;
    }

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

\的Util \ MySlim

 protected function mapRoute($args)
    {
        $pattern = array_shift($args);
        $callable = array_pop($args);
        $route = new \Util\MyRoute($this, $pattern, $callable, $this->settings['routes.case_sensitive']);
        $this->router->map($route);
        if (count($args) > 0) {
            $route->setMiddleware($args);
        }

        return $route;
    }

你看,当实例化\ 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);
            }
            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;
}

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

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

优点

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

<强>缺点:

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