Skip to content

容器解析

在 Slim 中,你不仅限于为路由定义一个函数。有几种不同的方法可以定义路由操作函数。

除了函数之外,你还可以使用以下方式:

  • container_key:method
  • Class:method
  • 实现了 __invoke() 方法的类
  • container_key

这个功能是通过 Slim 的 Callable Resolver 类实现的。它将字符串转换为函数调用。 示例:

$app->get('/', '\HomeController:home');

或者,你可以利用 PHP 的 ::class 运算符,它与 IDE 查找系统很好地配合,并产生相同的结果:

$app->get('/', \HomeController::class . ':home');

你也可以传递一个数组,其中第一个元素包含类的名称,第二个元素包含要调用的方法的名称:

$app->get('/', [\HomeController::class, 'home']);

在上面的代码中,我们定义了一个 / 路由,并告诉 Slim 在 HomeController 类上执行 home() 方法。

Slim 首先在容器中查找 HomeController 的实例,如果找到该实例,则使用该实例;否则,它将使用容器作为第一个参数来调用其构造函数。一旦创建了类的实例,它将使用你所定义的策略来调用指定的方法。

使用容器注册控制器

创建一个具有 home 动作方法的控制器。构造函数应接受所需的依赖项。例如:

<?php

use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Slim\Views\Twig;

class HomeController
{
    private $view;

    public function __construct(Twig $view)
    {
        $this->view = $view;
    }

    public function home(ServerRequestInterface $request, ResponseInterface $response, array $args): ResponseInterface
    {
      // 这里是你的代码
      // 使用 $this->view 来渲染HTML
      // ...

      return $response;
    }
}

在容器中创建一个工厂函数,用于使用依赖项实例化控制器:

use Psr\Container\ContainerInterface;
// ...

$container = $app->getContainer();

$container->set('HomeController', function (ContainerInterface $container) {
    // 从容器中获取 'view'
    $view = $container->get('view');

    return new HomeController($view);
});

这使你可以利用容器进行依赖注入,并将特定的依赖项注入到控制器中。

允许 Slim 实例化控制器

或者,如果容器中没有该类的条目,则 Slim 将把容器的实例传递给构造函数。你可以构建具有多个动作的控制器,而不是只处理一个动作的可调用类。

<?php

use Psr\Container\ContainerInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;

class HomeController
{
   private $container;

   // 构造函数接收容器实例
   public function __construct(ContainerInterface $container)
   {
       $this->container = $container;
   }

   public function home(ServerRequestInterface $request, ResponseInterface $response, array $args): ResponseInterface
   {
        // 使用容器中的元素代码... $this->container->get('');

        return $response;
   }

   public function contact(ServerRequestInterface $request, ResponseInterface $response, array $args): ResponseInterface
   {
        // 使用容器中的元素代码... $this->container->get('');

        return $response;
   }
}

你可以这样使用控制器方法。

$app->get('/', \HomeController::class . ':home');
$app->get('/contact', \HomeController::class . ':contact');

使用可调用类

你不需要在路由可调用函数中指定一个方法,你可以将其设置为一个可调用类,例如:

<?php

use Psr\Container\ContainerInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;

class HomeAction
{
   private $container;

   public function __construct(ContainerInterface $container)
   {
       $this->container = $container;
   }

   public function __invoke(ServerRequestInterface $request, ResponseInterface $response, array $args): ResponseInterface
   {
        // 使用容器中的元素代码... $this->container->get('');

        return $response;
   }
}

你可以像下面这样使用这个类。

$app->get('/', \HomeAction::class);

同样地,如果你将类名注册到容器中,那么你可以创建一个工厂并将所需的特定依赖项注入到你的动作类中。