简体   繁体   English

Slim Framework中的依赖注入 - 将Container传递给您自己的类

[英]Dependency Injection in Slim Framework - passing Container into your own classes

I've already commented on this thread but it seems to be dead so I'm opening a new one: Dependency Injection Slim Framework 3 我已经对这个帖子做过评论,但似乎已经死了所以我开了一个新的: 依赖注入Slim Framework 3

The post above explains how pass Slims Container to a class you've written yourself. 上面的帖子解释了如何将Slims Container传递给您自己编写的课程。

However, the OP has asked if it's possible to get Slim to Dependency Inject ALL their classes. 但是,OP已经询问是否可以将Slim转换为Dependency Inject 所有类。

I'm also interested in knowing if there's a way to do this since it seems to be anything but DRY if you have to pass the container to every class that you want to use it. 我也有兴趣知道是否有办法这样做,因为如果你必须将容器传递给你想要使用它的每个类,它似乎只是DRY。

As an example, if I want to use one of Slim's functions (such as doing a redirect, in one of my own classes ) I cannot use this as per the documentation: 作为一个例子,如果我想使用Slim的一个函数(比如在我自己的一个类中进行重定向),我不能按照文档使用它:

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

Because $res (the response object) is not within the scope of my class, unless I inject/pass it. 因为$res (响应对象)不在我的类的范围内,除非我注入/传递它。

The problem with this is, if I have say 100 classes, do I have to pass (or inject) the container 100 times? 问题是,如果我说100个课程,我是否必须通过(或注入)容器100次? That seems really, really tedious. 这看起来真的非常乏味。

In frameworks like CakePHP you can use the 'AppController' to globally do stuff like this, ie define things once, and make it available in ALL your classes. 在像CakePHP这样的框架中,您可以使用'AppController'来全局执行这样的操作,即定义一次,并使其在所有类中可用。 Does Slim not provide this functionality? Slim不提供此功能吗? If not, that's a serious drawback, IMO. 如果没有,这是一个严重的缺点,IMO。


Edit - I'm adding this from one of the comments I've made to try and explain the issue further: 编辑 - 我在其中一条评论中添加此内容,尝试进一步解释问题:

If you look at the First Application Tutorial - http://slimframework.com/docs/tutorial/first-app.html - they are adding a PDO database connection to the container. 如果您查看First Application Tutorial - http://slimframework.com/docs/tutorial/first-app.html - 他们正在向容器添加PDO数据库连接。

Let's say I have 100 separate classes in a sub-directory (the example has a ../classes/ directory) and autoload them in index.php using spl_autoload_register() . 假设我在子目录中有100个单独的类(该示例具有../classes/目录)并使用spl_autoload_register()在index.php中自动加载它们。 The container is NOT available in any of those classes. 容器不适用于任何类别。

If I had to pass something 100 separate times, each time I use one of my classes, just to get a PDO connection (and that's just one example) then that makes the code very repetetive, ie not DRY. 如果我不得不分别传递100次,每次我使用我的一个类,只是为了获得一个PDO连接(这只是一个例子),那么这使代码非常重复,即不是DRY。

Slim comes with Pimple by default. Slim默认配有Pimple Some developers argue (and I tend to agree with them) that Pimple is not a dependency injection container, but a service locator, since it doesn't resolve dependencies on its own, you need to register them. 一些开发人员认为(并且我倾向于同意这些),Pimple不是依赖注入容器,而是服务定位器,因为它不能自己解决依赖关系,需要注册它们。

Slim 3 works with any dependency manager that implements Container interop interface , which PHP-DI does. Slim 3可以与任何实现Container互操作接口的依赖管理器一起使用,PHP-DI就是这样做的。

Go for this package . 去寻找这个包 This is what I'm using for my projects and it's simply amazing, because of autowiring . 这就是我用于我的项目,因为自动装配 ,它简直太棒了。 To put it simply, PHP-DI reads constructor of the class and understands what needs to be injected, son you don't have to register dependencies as you would with Pimple. 简单地说,PHP-DI读取类的构造函数并理解需要注入的内容,不需要像使用Pimple那样注册依赖项。

Sometimes I think (hope?) that PHP-DI will replace Pimple as Slim's default DI container, because it's simply more advanced. 有时我认为(希望?)PHP-DI将取代Pimple作为Slim的默认DI容器,因为它更简单。

Here's how you do with Pimple: 以下是您对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);
    }
}

Here's the same controller with PHP-DI: 这是与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);
    }
}

The problem with this is, if I have say 100 classes, do I have to pass (or inject) the container 100 times? 问题是,如果我说100个课程,我是否必须通过(或注入)容器100次? That seems really, really tedious. 这看起来真的非常乏味。

If you use Slim bundled with PHP-DI, the problem is solved autmatically with autowiring. 如果您使用与PHP-DI捆绑在一起的Slim,则问题会通过自动装配自动解决。 :) :)

The simplest way to do this is like so: 最简单的方法就像这样:

index.php 的index.php

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

TestController.php 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);
    }
}

I'm not sure if this is the "correct" way of doing it, but what happens is that the constructor of TestController receives the container as the first argument. 我不确定这是否是“正确”的方法,但是发生的是TestController的构造函数接收容器作为第一个参数。 This is mentioned in their documentation: http://www.slimframework.com/docs/objects/router.html#container-resolution 这在他们的文档中提到: http//www.slimframework.com/docs/objects/router.html#container-resolution

So when you're using a function like TestController::mytest() it has access to anything in the container, such as the PDO Database instance you set up in index.php (if following their First Application example tutorial). 因此,当您使用类似TestController::mytest()的函数时,它可以访问容器中的任何内容,例如您在index.php中设置的PDO数据库实例(如果遵循其第一个应用程序示例教程)。

As I say, I'm not sure if that's the "right" way of doing it, but it works. 正如我所说,我不确定这是否是“正确”的做法,但它确实有效。

If you uncomment the var_dump($ci) line in you'll see the Slim Container object. 如果取消注释var_dump($ci)行,您将看到Slim Container对象。

If anyone has any feedback on this please comment as I'd be interested in knowing. 如果有人对此有任何反馈,请发表评论,因为我有兴趣知道。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM