简单来说,Laravel IoC 容器是什么?

2024-05-28

谁能用简单易懂的语言解释依赖注入和 IoC 容器,因为我是 Laravel 的初学者。谢谢


答案变得比我最初想要的要长。我提供了一些背景信息。不过,如果您正在寻找短期解释,请阅读 IoC 容器的第一段和粗体段落。

依赖注入

依赖注入是一种设计模式,顾名思义。它将对象注入到其他对象的构造函数或方法中,使得一个对象依赖于一个或多个其他对象.

<?php

class DatabaseWriter {
    
    protected $db;

    public function __construct(DatabaseAdapter $db)
    {
        $this->db = $db;
    }

    public function write()
    {
        $this->db->query('...');
    }

}

你可以看到我们需要类构造函数aDatabaseAdapter要传递的实例。由于我们在构造函数中执行此操作,因此如果没有它,则无法实例化该类的对象:我们正在注入一个依赖项。现在,我们知道DatabaseAdapter始终存在于类中,我们可以轻松依赖它。

The write()方法只是调用适配器上的方法,因为我们肯定知道它存在,因为我们使用了 DI。

使用 DI 而不是滥用静态类、上帝对象和其他类似的东西的巨大优势是,您可以轻松追踪依赖项的来源.

另一个巨大的优势是,您可以轻松地交换依赖项。如果您想使用依赖项的另一个实现,只需将其传递给构造函数即可。您不再需要寻找硬编码实例来交换它们。

抛开以下事实不谈,通过使用依赖注入,您将能够轻松地对您的类进行单元测试,因为您可以模拟依赖项,而这对于硬编码的依赖项来说是几乎不可能的。

依赖注入的三种类型

构造函数注入

上面解释的依赖注入类型称为构造函数注入。这仅仅意味着依赖项作为参数传递给类构造函数。然后,依赖项将存储为属性,从而可在该类的所有方法中使用。这里的一大优点是,如果不传递依赖关系,类的对象就不能存在。

二传手注射

这种类型使用专用方法来注入依赖项。而不是使用构造函数。使用 Setter Injection 的优点是,您可以向对象添加依赖项创建后。它通常用于可选的依赖项。 Setter 注入也非常适合整理您的构造函数,并且仅在您需要的方法中包含依赖项。

<?php

class RegisterUserService {

    protected $logger;

    public function setLogger( Logger $logger )
    {
        $this->logger = $logger;
    }

    public function registerUser()
    {
        // Do stuff to register the user
        if($this->logger)
            $this->logger->log("User has been registered");
    }

}

$service = new RegisterUserService;
$service->registerUser(); // Nothing is Logged

$service->setLogger(new ConcreteLogger);
$service->registerUser(); // Now we log

该对象可以在没有任何依赖关系的情况下实例化。有一种方法可以注入依赖项(setLogger()) 可以选择性地调用。现在由方法实现决定是否使用依赖项(如果未设置)。

值得指出的是,对 Setter 注入要谨慎。调用尚未注入的依赖项上的方法或访问属性将导致令人讨厌的结果Fatal error: Call to a member function XXX() on a non-object 。因此,每次访问依赖项时,都必须首先对其进行空检查。一个更干净的方法来解决这个问题是使用空对象模式 http://en.wikipedia.org/wiki/Null_Object_pattern并将依赖项移至构造函数中(作为可选参数,如果未传递任何内容,则在类内部创建空对象)

接口注入

接口注入的基本思想是,注入依赖项的方法是在接口中定义的。需要依赖的类必须实现该接口。从而确保所需的依赖关系能够正确地注入到依赖对象中。它是之前解释的 Setter 注入的更严格形式。

<?php

interface Database {

    public function query();

}

interface InjectDatabaseAccess {

    // The user of this interface MUST provide
    // a concrete of Database through this method
    public function injectDatabase( Database $db );

}

class MySQL implements Database {

    public function query($args)
    {
        // Execute Query
    }

}

class DbDoer implements InjectDatabaseAccess {

    protected $db;

    public function injectDatabase( Database $db )
    {
        $this->db = $db;
    }

    public function doSomethingInDb($args)
    {
        $this->db->query();
    }

}

$user = new DbDoer();
$user->injectDatabase( new MySQL );
$user->doSomethingInDb($stuff);

接口注入的意义是有争议的。我个人从未使用过它。我更喜欢构造函数注入而不是它。这使我能够完成完全相同的任务,而无需在注入器端添加额外的接口。

依赖倒置

我们也可以依赖抽象,而不是依赖于具体实例。

<?php

class DatabaseWriter {
    
    protected $db;

    public function __construct(DatabaseAdapterInterface $db)
    {
        $this->db = $db;
    }

    public function write()
    {
        $this->db->query('...');
    }

}

Now we 反转控制 http://en.wikipedia.org/wiki/Dependency_inversion_principle。我们现在可以注入任何消耗该实例的实例,而不是依赖于具体实例类型提示 http://php.net/manual/en/language.oop5.typehinting.php界面。该接口负责确保后面的具体实例实现我们将要使用的所有方法,以便我们仍然可以在依赖类中依赖它们。

确保你得到了它,因为它是 IoC 容器的核心概念。

国际奥委会容器

我能想到的最简短的术语是这样描述 IoC 容器的:

IoC-Container 是一个知道实例如何创建并知道如何all它们的潜在依赖关系以及如何解决它们。

如果我们以上面的例子为例,想象一下DatabaseAdapter本身有它自己的依赖关系。

class ConcreteDatabaseAdapter implements DatabaseAdapterInterface{

    protected $driver;

    public function __construct(DatabaseDriverInterface $driver)
    {
        $this->driver = $driver;
    }

}

所以为了能够使用DatabaseAdapter你需要传递一个实例DatabaseDriverInterface抽象作为依赖。

但你的DatabaseWriter班级不知道,也不应该知道. The DatabaseWriter不应该关心如何DatabaseAdapter有效,它应该只关心DatabaseAdapter是通过的,而不是需要如何创建的。这就是 IoC 容器派上用场的地方。

App::bind('DatabaseWriter', function(){
    return new DatabaseWriter(
        new ConcreteDatabaseAdapter(new ConcreteDatabaseDriver)
    );
});

正如我已经说过的,DatabaseWriter它本身不知道任何有关它的依赖项的依赖项的信息。但 IoC 容器知道它们的一切,也知道在哪里可以找到它们。所以最终当DatabaseWriter类将被实例化,首先询问 IoC-Container需要如何实例化。这就是 IoC 容器的作用。

简单地说(如果您喜欢设计模式)。它有点像一个组合依赖注入容器(我上面已经解释过)和服务定位器 http://en.wikipedia.org/wiki/Service_locator_pattern.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

简单来说,Laravel IoC 容器是什么? 的相关文章

  • octobercms 任务调度不起作用

    我正在使用基于 Laravel 的 OctoberCMS 我没有 SSH 访问我的服务器的权限 每天我需要删除一些注册后 24 小时内未激活帐户的用户 所以我正在考虑使用任务调度 如 cronjobs 根据 10 月 CMSdocs htt
  • laravel 中的 jwt 中的“无法从请求中解析令牌”

    我面临着 无法从请求中解析令牌 Laravel 中的 JWT 错误 我在 localhost Windows 7 中的 Xampp 中尝试了相同的代码 它正在工作 但在服务器上它不起作用 我已经通过了 授权 标头中的令牌也发生了变化 hta
  • 通知用户消息仍在输入中

    我正在使用 Laravel 5 6 7 Socket IO 和 vue js 我没有使用 Pusher 和 redis 下面是我的代码 用于向与我一对一聊天的用户发送消息 var url http localhost 6001 apps M
  • 如何在 Laravel 5 中设置基本路径

    I moved Laravel 公共文件夹 to the 根文件夹 然后我搬家了Laravel to 它自己的文件夹 所以我可以在共享主机上使用 Laravel 它看起来像这样 2015 08 04 18 13
  • 控制器中的 Lumen (laravel) 翻译

    我需要翻译 电子邮件 作业和控制器中使用的字符串 我读到了这个 https laravel com docs 5 2 localization https laravel com docs 5 2 localization所以我知道你可以通
  • 如何暂停 Laravel 队列

    我有一个将请求发送到远程服务的队列 有时此服务会进行维护 我希望所有队列任务在遇到这种情况时暂停并在 10 分钟内重试 我该如何实施 您可以使用Queue looping 用于暂停整个队列或连接 而不仅仅是单个作业类 的事件侦听器 与其他方
  • 从 Laravel 中的命令调用控制器方法

    我有一个通过 Redis Pub Sub 监听的命令 收到发布后 我想调用控制器方法 以便可以更新数据库 但是 我无法找到任何关于如何从项目内部但在路由外部调用带有参数的控制器方法的解决方案 我见过的最接近的东西是这样的 return re
  • 当 Axios 中的 responseType 为 blob 和 VueJs 时,如何读取 http 错误? [复制]

    这个问题在这里已经有答案了 我在 VueJS 应用程序中使用 Blob responseType 和 Axios 从服务器下载文档 当响应代码为 200 时 它工作正常并下载文件 但是当出现任何 http 错误时 我在捕获错误时无法读取状态
  • Laravel 插入三向数据透视表

    Summary 我正在构建音乐发现服务 我的问题是 如何将数据插入三向数据透视表 标签 跟踪 用户 Schema 我看到了这个架构在 LaravelSD http www laravelsd com share WNmzz8 它由六个主表
  • Laravel 中正则表达式规则的自定义验证消息?

    非常基本的问题 我正在尝试自定义 Laravel 中正则表达式验证规则的错误消息 特定规则适用于密码 要求密码包含 6 20 个字符 至少有一个数字以及一个大写和小写字母 因此我想将此信息传达给用户 而不仅仅是显示格式为 的默认消息 无效的
  • Laravel:在刀片页面中使用 asset 方法有什么好处?

    在一些 Laravel 示例中 我看到资产被这样调用 与这样做相比 使用该方法有什么优点 如果您选择后者 则当您访问任何包含正斜杠的 URL 时 这些 URL 将不起作用 例如 不使用asset如果您在主页上 则看起来工作正常 但如果您在
  • 在 Laravel 5.2 中按 id 显示图像文件

    我有一个名为 files 的表 它保存与属性表相关的图像的名称 我试图使这些图像显示为以下关系 这是属性表的一部分 这是表文件及其与属性表的关系 我可以在控制器 PropertyController 的 show 方法中传递什么参数 目前我
  • Laravel 5 多租户应用程序具有单独的数据库 - 用户可以访问多个安装

    在过去的几年里 我开发了一个非常定制的 PHP MySQL 应用程序 用于许多客户 到目前为止 我一直在为每个客户端创建一个新的数据库和新的安装 这里第一个明显的问题是让多个安装保持最新的任何代码更改 第二个问题是每次安装都有大量用户 对于
  • Laravel 5.1 完成后如何捕获作业队列详细信息?

    在 Laravel 5 1 中 我希望在作业完成时收到通知 并提供有关作业的详细信息 具体来说 user id and customer id 我正在使用Queue after方法中的方法AppServiceProvider作为 Larav
  • laravel services.json 未创建

    有时我的services json运行后丢失composer update or php artisan clear compiled 我检查了权限 甚至将存储文件夹的权限更改为 777 但没有帮助 我怎样才能调试出什么问题 我的 lara
  • 通过 Laravel 框架集成现有项目?

    我已经从 github 克隆了一个项目 现在我需要集成该项目 那么如何使用 laravel 框架 我是否需要创建一个新项目然后需要替换文件夹 或任何其他替代方案 因为我是这个框架的新手 帮助我 这是一个广泛的问题 因为这取决于您的项目 而我
  • Laravel 带条件的连接查询

    我有4张桌子 User table id col1 col2 指定课程 table id user id course id approved 课程信息 table id parent id 课程家长 table id start date
  • 从辅助类将输出写入控制台

    我有一个运行帮助程序类的控制台命令 我想用以下命令编写输出 this gt info 从助手类到控制台 我的代码如下所示 App Http Console Commands SomeCommand php function handle H
  • 使用 Laravel Eloquent 关系构建三元关系

    拥有三个实体 Project Employee 就业 问题描述 员工可以从事多个项目 每个项目都有一份工作 我想要访问所有项目以及您推荐的某个员工的就业情况 我不确定 但这种关系一定看起来像ternary 物理表尚未定义 因此 可以自由地设
  • 检查 Laravel 模型是否已保存或查询是否已执行

    我见过很多人使用这种方式来检查 Laravel 模型是否已保存 所以现在我想知道这是否是一种安全的方法 我还可以检查下面的查询是否像这样执行 检查模型是否已保存 Eg myModel new User myModel gt firstnam

随机推荐

  • 框架中有通用的交换方法吗?

    框架中是否存在这样的方法 public static void Swap
  • 在 opencv 中一次性将旋转和平移结合起来

    我有一段用于旋转和平移图像的代码 Point2f pt 0 in rows double angle atan trans c trans b 180 M PI Mat r getRotationMatrix2D pt angle 1 0
  • 将 Azure Blob 与 Azure 网站结合使用

    我正在制作一个MVC Windows Azure涉及用户上传图像的网站 我想将图像存储在 blob 中 我搜索了教程 但大多数都涉及Webapps而不是 MVC 网站 我发现的唯一有用的教程是 http www codeproject co
  • 在matlab中融合2个以上的图像

    在 MATLAB 中 如何融合两个以上的图像 例如 我想要做什么imfuse但对于超过 2 个图像 使用两张图像 这是我的代码 A imread file1 jpg B imread file2 jpg C imfuse A B blend
  • Windows 上的 git 忽略文件名大小写更改 [重复]

    这个问题在这里已经有答案了 我有一个reactjs应用程序 我正在将所有文件名标准化为小写以符合Nodejs 最佳实践 https devcenter heroku com articles node best practices stic
  • qvariant 作为 qhash 中的键

    我想创建一个带有 QVariants 键的数据结构 它看起来像这样 QHash
  • 无法禁用 CALayer>>removeFromSuperlayer 的动画

    我希望从其超级层中删除 CALayer 而无需设置动画 这里发生的事情是图层动画到一个位置 效果很好 但是当动画停止时 执行此代码 将图层返回到其开始位置 并淡出 大概然后从超级层中删除 如何阻止它动画 removeFromSuperlay
  • UIBarButtonItem 按下后更改字体,在外观代理中指定

    我设置了UIBarButtonItem标题字体通过appearanceAppDelegate 中的代理 UIBarButtonItem appearance setTitleTextAttributes NSDictionary dicti
  • 如何使用 aether 从 Java 找到最新版本的 Maven 工件?

    他们的文档非常薄弱 我无法弄清楚 我找到了部分答案here https stackoverflow com questions 27428068 how to retrieve the latest also snapshot versio
  • 字符串中数字的连续相加

    我是一名正在学习 python 的新程序员 并且在如何完成此任务方面遇到了困难 所以本质上我有一个从文件导入的数字字符串需要读取 并且需要将第一个数字的总和添加到第二个数字并将其转换为正确的 ascii 字符 因此 例如 如果我正在读取字符
  • 如何在 CSS 中选择纯 HTML 文本?

    你们有人知道如何在 CSS 中选择纯 HTML 文本吗 我有以下结构 div p class caption caption1 p div class tabs div class moving bg div p class text ta
  • Java EE 6 的 Maven 与 Eclipse 项目 Facets

    我在 Eclipse 中使用以下原型创建了 Maven 项目 ejb javaee6 webapp javaee6 这些项目是在没有方面的情况下创建的 将此类 Maven 项目转换为多面形式有意义吗 哪些方面会有帮助 哪些方面可能会给 Ma
  • 套接字编程-listen() 和accept() 有什么区别?

    我一直在读本教程 http www cs rpi edu moorthy Courses os98 Pgms socket html了解套接字编程 看来listen and accept 系统调用都做同样的事情 即阻塞并等待客户端连接到使用
  • 作曲家和 Cygwin

    如果您尝试 全局 安装 Composer 则 Composer 无法在 Cygwin 中正确运行 将composer phar放入 usr local bin composer 然后尝试运行它会导致错误 Could not open inp
  • R 中 write.table 文件名中的变量

    请帮助我解决一个幼稚的问题 已经用谷歌搜索 并尝试了很多变体 但失败了 如何使用 R 中 write table 的文件名中的变量保存文件 脚本循环遍历 dir 中的文件 应用一些函数 然后将结果保存到具有相同名称但附加结尾的文件中 谢谢
  • 如何在 github 复合操作步骤中动态设置环境变量?

    我确实需要它作为一个环境变量 这是为了复合动作具体来说 在复合操作中 我尝试了许多不同的设置环境变量的方法 我发现做到这一点的唯一方法是使用env在步骤本身内 runs using composite steps name A step e
  • Nightmare.js 截图缓冲区长度 0

    我正在运行一个 night js 脚本 我试图在其中截取页面上多个元素的屏幕截图 The first元素被捕获得很好 但折叠下方的所有其他元素都以零长度捕获 我正在努力调试这个问题 任何帮助将非常感激 基本上这个脚本会遍历一个页面并选择al
  • T-SQL 中结果集的幂集(所有组合)

    我需要一个 t sql 代码来获取结果集的幂集 输入示例 ColumnName 1 2 3 Example Output one columns as nvarchar 1 2 3 1 2 1 3 2 3 1 2 3 输出集可能包含重复值
  • 在 doxygen 中使用 @see 或 @link

    我之前用 Javadoc 记录并使用了标签 see link or see foo and link foo 在我的描述中链接到其他课程 现在我尝试了doxygen 似乎这些标签不兼容 如果我运行 doxygen 完整的标签将被简单地解释为
  • 简单来说,Laravel IoC 容器是什么?

    谁能用简单易懂的语言解释依赖注入和 IoC 容器 因为我是 Laravel 的初学者 谢谢 答案变得比我最初想要的要长 我提供了一些背景信息 不过 如果您正在寻找短期解释 请阅读 IoC 容器的第一段和粗体段落 依赖注入 依赖注入是一种设计