【问题标题】:Dependency Injection in Slim Framework - passing Container into your own classesSlim 框架中的依赖注入 - 将 Container 传递到您自己的类中
【发布时间】:2017-03-03 17:31:49
【问题描述】:

我已经评论了这个帖子,但它似乎已经死了,所以我要开一个新帖子:Dependency Injection Slim Framework 3

上面的帖子解释了如何将 Slims Container 传递给您自己编写的类。

然而,OP 已经询问是否有可能让 Slim 依赖注入 ALL 他们的类。

我也很想知道是否有办法做到这一点,因为如果你必须将容器传递给你想使用它的 每个 类,它似乎不是 DRY。

例如,如果我想使用 Slim 的功能之一(例如进行重定向,在我自己的一个类中)我不能按照文档使用它:

$res->withStatus(302)->withHeader('Location', 'your-new-uri');

因为$res(响应对象)不在我的班级范围内,除非我注入/传递它。

问题是,如果我有 100 个类,我是否必须通过(或注入)容器 100 次?这看起来真的,真的很乏味。

在像 CakePHP 这样的框架中,您可以使用“AppController”来全局执行此类操作,即定义一次,并使其在您的所有类中可用。 Slim 不提供这个功能吗?如果不是,那将是一个严重的缺陷,IMO。


编辑 - 我从我制作的其中一个 cmets 中添加此内容,以尝试进一步解释该问题:

如果您查看第一个应用程序教程 - http://slimframework.com/docs/tutorial/first-app.html - 他们正在向容器添加 PDO 数据库连接。

假设我在一个子目录中有 100 个单独的类(该示例有一个 ../classes/ 目录)并使用 spl_autoload_register() 在 index.php 中自动加载它们。该容器在任何这些类中都不可用。

如果我必须通过 100 次不同的时间,每次我使用我的一个类时,只是为了获得一个 PDO 连接(这只是一个示例),那么这会使代码非常重复,即不是 DRY。

【问题讨论】:

  • 由于 Slim 默认使用 Pimple 作为 DIC,也许您应该研究一下? pimple.sensiolabs.org
  • AFAIK,Pimple 没有任何方法可以自动解决构造函数依赖项。因此,您需要将所有类注册到容器中。但是,我不明白为什么这会违背 DRY?当您将类注册到容器时,您仍然会从容器中注入依赖项,因此所有类只注册和解析一次...查看 Pimples 站点以获取示例。
  • @MagnusEriksson 举个例子-如果您查看第一个应用程序教程-slimframework.com/docs/tutorial/first-app.html-他们正在向容器添加 PDO 数据库连接。现在..假设我在一个子目录中有 100 个单独的类(该示例有一个 ../classes/ 目录)并使用 spl_autoload_register() 在 index.php 中自动加载它们。该容器在任何这些类中都不可用。如果我必须写 100 次东西才能在每个类中获得我的 PDO 连接,那并不是 DRY,因为我将本质上相同的代码重复 100 次。
  • 您仍将只创建一个 PDO 连接并将该连接传递给所有类。当然,您需要将相同的实例注入所有类,但这并不反对 DRY(您不是在重复相同的代码,您只是在重用相同的类实例)。您仍然只创建每个类一次(包括 PDO),并注入它们的依赖项。然而,这就是我不喜欢 Pimple 和类似容器的原因。我更喜欢像 Illuminate\Container 这样的容器,它使用反射来自动解决依赖注入。
  • 您查看我发布的第一个链接了吗? Slims 容器基于 Pimple,因此您可以查看该页面以更详细地了解如何使用该容器。例如,查看关于定义服务的部分。为容器定义服务和自动加载类是两件不同的事情......

标签: php slim


【解决方案1】:

Slim 默认带有Pimple。一些开发者认为(我倾向于同意他们)Pimple 不是一个依赖注入容器,而是一个服务定位器,因为它不能自己解决依赖关系,所以你需要注册它们。

Slim 3 可与任何实现 Container interop interface 的依赖管理器配合使用,PHP-DI 就是这样做的。

去this package。这就是我在项目中使用的,因为autowiring,它简直太棒了。简而言之,PHP-DI 读取类的构造函数并了解需要注入的内容,因此您不必像使用 Pimple 那样注册依赖项。

有时我认为(希望?)PHP-DI 将取代 Pimple 作为 Slim 的默认 DI 容器,因为它更先进。

以下是你如何处理 Pimple:

<?php
namespace Controllers;

class UsersController
{
    // Inject Container in controller (which is bad, actually)
    public function __construct(ContainerInterface $container)
    {
        // grab instance from container
        $this->repository = $container['userRepository'];
    }

    // Handler of a route
    public function getAllUsers($request, $response)
    {
        $user = $this->repository->getAllUsers();
        return $response->withJson($users);
    }
}

这是与 PHP-DI 相同的控制器:

<?php
namespace Controllers;

class UsersController
{
    // Declare your dependencies in constructor:
    // PHP-DI will find the classes and inject them automatically
    public function __construct(UserRepository $repository)
    {
        $this->repository = $repository;
    }

    // Handler of a route
    public function getAllUsers($request, $response)
    {
        $user = $this->repository->getAllUsers();
        return $response->withJson($users);
    }
}

问题是,如果我有 100 节课,我必须通过吗? (或注入)容器 100 次?好像真的真的 乏味。

如果您使用与 PHP-DI 捆绑的 Slim,则问题会通过自动装配自动解决。 :)

【讨论】:

  • 您对下面给出的解决方案有任何 cmets(用户“Audrey Roberts”)吗?我已经接受了你的回答,但其他解决方案不依赖于使用默认 Slim 安装不附带的东西,而且看起来更简单。
  • 奥黛丽的方案完全可以接受;它在 Slim 的教程中提供。但是,将容器作为构造函数参数传递确实使依赖注入的目的无效并增加了可测试性的复杂性。只是看起来更简单。
  • Slim 的文档中关于依赖注入的内容非常令人担忧(并且有些烦人),而且它确实没有真正正确地使用它。这实际上不是我正确意识到的事情,并且花了很长时间阅读 DI 和 Slim,却发现它甚至没有正确使用它 - 非常令人沮丧。不过,我会更详细地研究自动装配和 Slim Bridge,谢谢您的建议。
【解决方案2】:

最简单的方法是这样的:

index.php

$app->get('/mytest', '\TestController:mytest');

TestController.php

class TestController {

    protected $ci;

    public function __construct(Slim\Container $ci) {
        //var_dump($ci);
        $this->ci = $ci;
    }

    public function mytest() {
        $sql = ''; // e.g. SQL query
        $stmt = $this->ci->db->prepare($sql);
    }
}

我不确定这是否是“正确”的做法,但会发生TestController 的构造函数接收容器作为第一个参数。这在他们的文档中提到:http://www.slimframework.com/docs/objects/router.html#container-resolution

因此,当您使用像 TestController::mytest() 这样的函数时,它可以访问容器中的任何内容,例如您在 index.php 中设置的 PDO 数据库实例(如果遵循他们的第一个应用程序示例教程)。

正如我所说,我不确定这是否是“正确”的做法,但它确实有效。

如果您取消注释 var_dump($ci) 行,您将看到 Slim Container 对象。

如果有人对此有任何反馈,请发表评论,我很想知道。

【讨论】:

    猜你喜欢
    • 2016-08-19
    • 2015-02-12
    • 1970-01-01
    • 1970-01-01
    • 2014-09-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多