它是依赖注入吗,是一种不好的做法吗? [英] Is it dependency injection and is it a bad practice?

查看:91
本文介绍了它是依赖注入吗,是一种不好的做法吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个小框架,我这样编码.我不确定是否称为依赖注入.我不知道这是否像一种设计模式.我也不知道并且不知道将$this作为参数传递是否是错误的做法.

I have a small framework and I coded it like this. I'm not sure if it is called dependency injection or not. I don't know if it is like a design pattern or not. I also don't know and wonder if passing $this as param is a bad practice.

看看这个; (这不是一个可行的示例,只需将这些代码写到浏览器中进行解释即可.)

Have a look at this; (Not a working example, just wrote those codes into browser for explanation.)

/* This is engine model */
require_once('Database.class.php');
require_once('Image.class.php');
require_once('Misc.class.php');
require_once('BBCode.class.php');

class FrameWork_Engine_Model
{
    public $database, $config, $misc, $bbcode, $controller, $image;

    function __construct($config)
    {
            $this->database = new Database($configParams);
            $this->image = new Image($this);
            $this->misc = new Misc($this);
            $this->bbcode = new BBCode($this);
            $this->controller = new Controller($this); //here I call Register controller depending on routing, in this case, register controller.
    }
 ...
 }


 /* This is register controller */
 class Register extends Base_Controller
 {
       /*I can access anything over Engine Model in my controllers */
       $this->engine->database->query(); //I access database model
       $this->engine->bbcode->tag('you'); //I access bbcode model
       $this->engine->image->sanitizeUploadedFile(); //I access image model

       //etc. I can access others models like this.
 }

基本上,我的控制器可以通过引擎模型访问任何模型.我相信dependency injection is all about injecting dependencies into controllers?类似,我的注册控制器需要一个数据库模型,路由模型和模板模型才能工作.在这里,它具有它所依赖的一切.我误会了吗?

Basically, my controllers can access any models via engine model. I believe dependency injection is all about injecting dependencies into controllers? Like, my register controller needs a database model, routing model, and templating model to work. Here it has everything it depends on. Am I mistaken?

说了这些,我的问题是:

With those said, my questions are:

  1. 这是一个有效的依赖注入示例吗?如果不是,那是什么?它在设计模式中有名称吗?

  1. Is it a valid dependency injection example? If not, what it is? Does it have a name in design patterns?

如果与依赖注入无关,那么需要做哪些更改才能成为DI?

If it is nothing related to dependency injection, what changes needs to be done to be DI?

在新创建的类上传递$this参数是不好的做法吗?如果是这样,为什么?

Is passing $this parameter on newly created classes is a bad practise? If so, why?

Ps.我知道在一个主题中问3个问题并不是stackoverflow喜欢的,但是我不想复制粘贴整个文本来问他们.

Ps. I know asking 3 questions in a topic isn't something stackoverflow likes, but I don't want to copy paste entire text to ask them.

推荐答案

您快到了.

不,我不认为它是有效的依赖注入示例.它有点像服务定位器(因为您是将整个容器注入服务中,并使用它来定位"依赖的服务).

No, I don't see it as a valid dependency injection example. It resembles a bit a service locator (because you're injecting the entire container into your services and use it to "locate" dependent services).

您在依赖注入和依赖注入容器之间造成了一些混乱.

You're making a small confusion between dependency injection and a dependency injection container.

首先,依赖项注入意味着在运行时将依赖项推入对象中,而不是创建/拉动它们.

First of, dependency injection means pushing dependencies into an object at runtime instead of creating/pulling them.

举例说明:

//hardcoded dependecies
class BadService
{
    public function __construct() 
    {
        $this->dep1 = new ConcreteObject1();
        $this->dep2 = new ConcreteObject2();
    }
}

因此在上面的示例中,BadService使得无法在运行时连接其他依赖项,因为它们已经被硬拉入构造函数本身了.

So in the example above, the BadService makes it imposible to wire other dependencies at runtime because they are already hard pulled into the constructor itself.

//service locator pattern
class AlmostGoodService
{
    public function __construct(Container $container)
    {
        $this->dep1 = $container->getADep1();
        $this->dep2 = $container->getADep2();
    }
}

AlmostGoodService示例中,我们从上一个示例中删除了硬性依赖关系,但是我们仍然依赖于容器的特定实现(这意味着我们的服务在不提供该容器的实现的情况下是不可重用的).这是与您的工作相匹配的示例.

In the AlmostGoodService example, we've removed the hard dependencies from the previous example but we are still depending on a specific implementation of our container (meaning that our service is not reusable without providing the implementation for that container). This is the example that matches what you're doing.

//dependecy injection    
class GoodService
{
    public function __construct($dep1, OptionalInterface $dep2)
    {
        $this->dep1 = $dep1;
        $this->dep2 = $dep2;
    }
}

GoodService服务与它的具体依赖关系的创建无关,可以很容易地在运行时与实现$dep1的协议"或$dep2的OptionalInterface的任何依赖关系连接"(因此,其名称为控制反转-依赖关系注入背后的基本概念).

The GoodService service is not concerned with the creation of it's concrete dependencies and can easily be "wired" at runtime with any dependencies that implement the "protocol" of the $dep1 or the OptionalInterface for the $dep2 (therefore the name of Inversion of Control - the underlying concept behind Dependency Injection).

执行此连接的组件称为依赖注入容器.

The component that does this wiring is called a dependency injection container.

现在,在其中的依赖注入容器最简单的形式不过是一个对象,它能够基于某种配置形式在运行时连接您的对象.

Now, a dependency injection container, in it's simplest form, is nothing more than an object capable of wiring up your objects at runtime based on some form of configuration.

我说过您已经差不多了,但是您的实现存在一些问题:

I said that you are almost there but there are some problems with your implementation:

  • 接线应该是懒惰的(您不希望在构造函数中完成所有工作,因为随着应用程序的增长,它的运行速度会大大降低)
  • 您不应将整个容器($this)作为依赖项传递,因为这样您会后退到较弱的控制反转,即服务定位器.相反,您应该将具体的依赖项传递给服务构造函数
  • the wiring should be lazy (you do not want to make all that work in your constructor, as your application would slow down considerably as it grows)
  • you should not pass the entire container ($this) as a dependency because then you fallback to a weaker inversion of control, namely a service locator. You should instead pass the concrete dependencies to your service constructors

在某些情况下,您会发现自己希望将整个$container作为依赖项传递给服务(即控制器或惰性服务工厂),但通常最好避免这种做法,因为它将使您的服务更可重用且更易于测试.当您感觉您的服务具有过多的依赖关系时,这是一个很好的信号,表明您的服务执行了太多操作,现在是拆分服务的好时机.

There are some cases when you'll find yourself wanting to pass the entire $container as a dependency to a service (namely controllers or lazy service factories), but generally it will be better to stay away from this practice as it will make your services more reusable and easier to test. When you're feeling that your service has too many dependencies, then that it's a good sign that you're service does too much and it's a good time to split it.

因此,根据我上面的回答,这是一个经过修订的(远非完美)实现:

So, based on my answers above, here is a revised (far from perfect) implementation:

/* This is the revised engine model */
class FrameWork_Engine_Model
{
    function __construct($config)
    {
            $this->config = $cofig; 
    }

    public function database()
    {
        require_once('Database.class.php');
        return new Database($this->config['configParams']);
    }

    public function bbcode()
    {
        require_once('BBCode.class.php');
        return new BBCode($this->database());
    }

    public function image()
    {
        require_once('Image.class.php');
        $this->image = new Image($this->config['extensionName']);
    }
    ....

    public function register_controller($shared = true)
    {
        if ($shared && $this->register_controller) {
          return $this->register_controller;
        }

        return $this->register_controller = new Register_Controller($this->database(), $thus->image(), $this->bbcode());
    }
 }

现在,要使用您的服务:

Now, to use your services:

$container = new FrameWork_Engine_Model(); 
$container->register_controller()->doSomeAction()

有什么可以改进的?您的容器应:

What could be improved? Your container should:

  • 提供一种共享服务的方法-即仅初始化一次
  • 可锁定-提供一种在配置后锁定它的方法
  • 能够与其他容器合并"-这样您的应用程序将成为真正的模块化
  • 允许可选依赖项
  • 允许范围
  • 支持标记服务
  • provide a way to share services - that is, to initialise them only once
  • be lockable - provide a way to lock it after configuration
  • be able to "merge" with other containers - that way your application will be really modular
  • allow optional dependencies
  • allow scopes
  • support tagging services

所有这些都附带了有关依赖注入

All of these are accompanied with clear documentation about Dependency Injection

  • Pimple - PHP 5.3 lightweight DI container
  • Symfony2 DI Container - PHP 5.3 feature full DI container
  • Juice DI - Small PHP 5.2 DI container

这篇关于它是依赖注入吗,是一种不好的做法吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆