Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/php/240.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在PHP web应用程序中使用依赖项注入_Php_Dependency Injection - Fatal编程技术网

在PHP web应用程序中使用依赖项注入

在PHP web应用程序中使用依赖项注入,php,dependency-injection,Php,Dependency Injection,我最近读了很多关于依赖注入的书,从理论上讲,它很有意义。拥有易于测试的单一责任类的想法听起来很聪明。然而,我正挣扎着要走多远 我现在正在开发一个PHPWeb应用程序,它有一个CMS组件,并且是数据库驱动的。在CMS中,您可以创建页面,页面本身是使用各种小部件构建的。这些小部件可以是直接的HTML(来自WYSIWYG编辑器),也可以稍微复杂一些,比如照片库。这是一个重要的部分,照片库小部件依赖于其他数据库模型,如PhotoGallery和photogalleryimage,以便正常工作 根据,我不

我最近读了很多关于依赖注入的书,从理论上讲,它很有意义。拥有易于测试的单一责任类的想法听起来很聪明。然而,我正挣扎着要走多远

我现在正在开发一个PHPWeb应用程序,它有一个CMS组件,并且是数据库驱动的。在CMS中,您可以创建页面,页面本身是使用各种小部件构建的。这些小部件可以是直接的HTML(来自WYSIWYG编辑器),也可以稍微复杂一些,比如照片库。这是一个重要的部分,照片库小部件依赖于其他数据库模型,如
PhotoGallery
photogalleryimage
,以便正常工作

根据,我不应该通过应用程序的不同层传递对依赖项的引用。相反,每个类应该简单地“请求”它所需要的任何依赖项。以他的例子来看,情况如下:

$db = new Database()
$repo = new UserRepository($db);
$page = new LoginPage($repo);
虽然我可以看到这在我的应用程序的服务层中工作得很好,但我真的不明白这在我的值对象/实体中是如何工作的。在我看来,这种模式要求我在应用程序的最高层实例化所有模型。然而,当我需要我的页面类来告诉我需要实例化哪些小部件时,如何在该级别实例化我的所有小部件?在不知道我正在创建哪些小部件的情况下,我如何知道需要创建和注入哪些小部件依赖关系

理论上,DI对我来说很有意义。然而,事实证明,在我的新web应用程序中实现这种模式更加困难。关于DI和IoC,我还缺少什么吗?谢谢

更新:对Tandu的回应 非常感谢Tandu的回复。我认为DI实际上可能不是我的问题,因为我认为我非常清楚它是什么,无论它是构造函数还是setter注入,或者它是使用容器还是穷人的方式完成的。我认为正在发生的是,DI正在挑战我重新思考我目前的编程方式。我认为我的OOP设计就是问题所在。为了说明这一点,我通常会对这个问题进行编程:

class Page
{
    public $id;
    public $name;

    public function widgets()
    {
        // Perform SQL query to select all widgets
        // for this page from the database, and then
        // return them as Widget objects.
    }
}

interface Widget
{
    public $id;
    public $page_id;
    public $type;

    public function widgetize();
}

class PhotoGallery_Widget implements Widget
{
    public $id;
    public $page_id;
    public $type;

    public function widgetize()
    {
        $gallery = new Photogallery();

        foreach($gallery->images())
        {
            // Create gallery HTML code
        }
    }
}

// Finally, to create the page, I would:
$page = new Page(1);
foreach($page->widgets() as $widget)
{
    $widget->widgetize();
}
显然这里有一些问题。
页面
模型取决于
小部件
模型。
PhotoGallery\u小部件
模型取决于
PhotoGallery
模型,甚至
PhotoGallery
模型也取决于
photogalleryimage
模型。问题是,这种发展方式对我很有效。随着我越来越深入到应用程序的各个层,每一层都承担着创建所需对象的责任。引入DI对我的思维方式产生了重大影响。然而,我想学习如何正确地做到这一点。就因为这对我来说很有效,并不意味着我应该继续这样做

你提到使用工厂。但是工厂实际上不是因为实例化对象而破坏DI吗

您可能还注意到,我的模型负责与数据库交互。我怀疑这也是我的设计中的一个问题。我是否应该使用某种类型的数据映射来消除模型中的这种责任


鉴于这个关于我目前如何实现代码的更具体的例子,您还有其他建议吗,或者您能进一步说明我应该如何以不同的方式实现吗?

不看具体的实现,很难给出具体的建议,因此我将提供我可以提供的一般建议(事实上,我不是很好)。听起来你可以使用一个“依赖注入容器”(google It..找到一个你喜欢的容器,或者为你自己的目的滚动)来管理类的大型互锁依赖关系

您应该记住的一件事是,您的代码应该轻轻地落在设计周围,这将非常有力地支撑它。您不应该努力让代码遵循您创建的设计。如果您试图做的事情不符合您对设计的理解,那么可能是时候进行重写了

您也只使用构造函数注入的例子,我相信您知道在适当的时候可以使用其他类型的注入,比如setter注入

正如我所说,我没有看到你的代码,但是你的设计的问题是,它不是应该知道它需要什么小部件的页面,而是服务。如果你将特定的小部件实现绑定到一个页面,这违反了依赖倒置(并使依赖注入更加困难)。相反,您的代码应该更符合以下内容:

interface Widget {
   function widgetize();
}

class ConcretePage {
   private $widgets = array();

   public function addWidget(Widget $widget) {
      $this->widgets[] = $widget;
   }

   public function run() {
      foreach ($this->widgets as $widget) {
         $widget->widgetize();
      }
   }
}
该服务将创建一个页面并添加所需的小部件。该页面不应该关心这些小部件。您可能还需要在页面和小部件之间实现一个桥梁。该服务也可以处理这一点

正如您提到的文章作者所说,您应该有专门用于构建整个对象图的代码(这是所有
操作符的所在)。想象一下,如果没有这些小部件的类定义,测试需要五个特定小部件的页面会有多困难!您需要依赖抽象

这可能不符合DI的精神,但更简单的解决方案是使用
WidgetFactory

class Page {
    private $wf;
    private $widgets = array('whiz', 'bang');
    public function __construct(WidgetFactory $wf) {
       $this->wf = $wf;
    }
    public function widgetize() {
       foreach ($this->widgets as $widget) {
          $widget = $this->wf::build($widget);
       }
    }
}

WidgetFactory
接口可以从应用程序到应用程序,甚至在测试中都是独立的。这仍然可以为窗口小部件页面提供某种程度的抽象。

对我来说,依赖注入只会有用,因为我可以在语法$This->method()或$obj->method()之间进行选择;调用相同的方法。这可以通过使用神奇的函数set、get和call来完成。

很抱歉,我花了这么长时间才做出响应,但我不得不花了很多时间