Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/php/295.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 依赖注入总是正确的答案吗?_Php_Dependency Injection_Service Locator - Fatal编程技术网

Php 依赖注入总是正确的答案吗?

Php 依赖注入总是正确的答案吗?,php,dependency-injection,service-locator,Php,Dependency Injection,Service Locator,我现在正在考虑很多关于依赖注入的问题,它是赞成和反对的。一般来说,似乎有一种共识,即依赖注入在大多数情况下都是正确的选择。我看到了它的方便之处,以及它如何使代码更具可读性。因此,我试图用尽可能多的依赖注入来创建我的类,将关注点分离为多个对象。在我70%的日常工作中,这很好。它起作用了,我看到了它的好处 然而,剩下的30%让我有点挣扎。我对依赖注入本身的概念没有问题,但我认为PHP确实有一些“特殊属性”,这让我怀疑依赖注入是否是正确的选择 使用DI而不是服务定位器的主要观点似乎是,您有“编译时错误

我现在正在考虑很多关于依赖注入的问题,它是赞成和反对的。一般来说,似乎有一种共识,即依赖注入在大多数情况下都是正确的选择。我看到了它的方便之处,以及它如何使代码更具可读性。因此,我试图用尽可能多的依赖注入来创建我的类,将关注点分离为多个对象。在我70%的日常工作中,这很好。它起作用了,我看到了它的好处

然而,剩下的30%让我有点挣扎。我对依赖注入本身的概念没有问题,但我认为PHP确实有一些“特殊属性”,这让我怀疑依赖注入是否是正确的选择

  • 使用DI而不是服务定位器的主要观点似乎是,您有“编译时错误”而不是“运行时错误”。我知道,对于Java或C这样的语言,PHP中没有“编译时错误”这样的东西不会自动导致“运行时错误”。至少我从未遇到过

  • 在只启动一次的程序中,将其源代码加载到内存中,并在执行过程中一直保持在内存中,我明白了为什么要使用DI。这是有道理的,你不必(通常)担心应用程序需要多长时间才能达到运行状态,你应该(通常)有足够的内存来保存所有代码。因此,加载所有依赖项并将它们保存在内存中似乎很好。但是,PHP脚本在Apache、NGINX或其他上下文中使用时,每次用户访问它时都会启动。除此之外,我们希望我们的应用程序运行得尽可能快,使用尽可能少的资源来充分利用服务器硬件。问题是,如果我每次都加载整个库,即使我只访问一小部分代码,这似乎是相当浪费的。。。(下面我举了一个例子来说明我的意思)

  • 如上所述,我尽量使用DI。但是剩下的30%我仍然使用服务定位器模式处理,因为I a.)在特定条件下只需要依赖项,或者b.)我访问一个或多或少可以用全局函数替换的服务/帮助器类。(见下面的示例)

  • 在这方面,我读了很多关于a.)Helper类是如何邪恶的b.)当你在你的类中只使用一次依赖项时,你应该将它拆分成一个单独的类(老实说,这是我不太明白的一点,因为当你使用DI时,你无论如何都必须创建类,那么为什么要将它从普通类中拆分出来呢?)

    我创建了一些虚拟代码来展示30%的服务定位器,我认为(在编写本文时)服务定位器(在PHP中)比DI更合理

    类记录处理程序{
    //使用特征启用对getInstanceOf()方法的访问,
    //它是指向服务容器singleton的全局实例的链接
    使用ContainerWareTrait;
    /**
    *@var EnvService
    */
    受保护的服务;
    /**
    *RecordHandler构造函数。
    *
    *@param EnvService$EnvService
    */
    公共功能构造(EnvService$EnvService){
    $this->envService=$envService;
    }
    //…其他方法。。。
    公共函数filterRecords(数组$记录):数组{
    //使用普通DI对象。。。
    如果($this->envService->isStaging()){
    //做些不同的事。。。
    返回[];
    }
    foreach($recordId=>$record的记录){
    //这可能发生在10%的时间里。。。
    //我不知道这里的数据库是否已经连接。
    //在容器中注册的工厂将在创建对象时初始化连接。。。
    如果(空($记录)){
    $record=$this->getInstanceOf(DbService::class)->查询(“从'stored_record_table中选择*,其中id=?”,[$recordId]);
    }
    //这可能发生,但在50%的情况下不会发生。。。
    如果(!empty($record[“xmlField”])){
    $record[“xmlField”]=$this->getInstanceOf(XmlService::class)->handleXml($record[“xmlField”]);
    }
    //正在基于记录的值创建类实例。。。
    如果(!empty($record[“classField]”)和&class_存在($record[“classField]”)和&
    在数组中(HandlerInterface::class,class_实现($record[“classField”])){
    $i=$this->getInstanceOf($record[“classField]”);
    $i->handle($record);
    }
    }
    }
    
    请注意,EnvService和DbService在使用过的服务容器中被标记为“Singleton”,这意味着一旦它们被创建,容器将一次又一次地返回相同的实例

    我真的很想看看是否有更好的解决方案,因为我使用了多种解决方案进行了测试,这样做可以节省30-50%的执行时间,而执行时间的波动取决于所处理的记录类型

    此外,我也意识到了隐藏依赖项等缺点。为了防止这个问题,我尝试创建“上下文对象”,它们基本上是硬编码的DI容器,但它们似乎也不是选项


    最后,我尝试使用“延迟加载”为了避免上述问题,例如PHP-DI在其文档中明确指出,您不应该为超过3-4个类创建延迟加载代理,这似乎没有多大帮助。

    没有模式始终是答案;在不能延迟的情况下,做出明智、实用的架构决策非常重要

    您说得对,在PHP的情况下,由于每个请求都必须实例化整个对象图,DI可能会导致性能损失

    然而,依赖注入显然与性能无关