我的编程空间,编程开发者的网络收藏夹
学习永远不晚

怎么创建PHP DI容器

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

怎么创建PHP DI容器

这篇文章主要讲解了“怎么创建PHP DI容器”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“怎么创建PHP DI容器”吧!

由开车开始

先开个车,为大家举个栗子:

class Driver{    public function drive()    {        $car = new Car();        echo '老司机正在驾驶', $car->getCar(), PHP_EOL;    }}class Car{    protected $name = '普通汽车';    public function getCar()    {        return $this->name;    }}

有两个类,Driver和Car,老司机Driver有个方法driver,在调用的时候首先得整辆车$car,然后发车。大多数同学都写过这样或者类似的代码,这样的代码单看没啥毛病,挺正常的。但是,如果我要换辆车,开普通车撩不到妹。

class Benz extends Car{    protected $name = '奔驰';}

这时候就需要做一个比较恶心的操作了,得改老司机的代码了。(老司机:我做错了什么?换辆车还得让我重学驾照……)。因此我们需要把让Car为外界注入,将Driver和Car解耦,不是老司机自己开车的时候还得自己去造车。于是就有了下面的结果

class Driver{    protected $car;    public function __construct(Car $car)    {        $this->car = $car;    }    public function drive()    {        echo '老司机正在驾驶', $this->car->getCar(), PHP_EOL;    }}

此时Driver和Car两个类已经解耦,这两个类的依赖,依靠上层代码去管理。此时,老司机会这样“开车”:

$car = new Car();$driver = new Driver($car);$driver->drive();

此时,我们创建Driver依赖的实例,并注入。上面的例子,我们实现了依赖注入,不过是手动的,写起来感觉还是不爽。这么繁重的活怎么能手动来做呢,得让程序自己去做。于是乎,DI容器诞生。

依赖注入容器

依赖注入与IoC模式类似工厂模式,是一种解决调用者和被调用者依赖耦合关系的模式。它解决了对象之间的依赖关系,使得对象只依赖IoC/DI容器,不再直接相互依赖,实现松耦合,然后在对象创建时,由IoC/DI容器将其依赖(Dependency)的对象注入(Inject)其内,这样做可以最大程度实现松耦合。依赖注入说白一点,就是容器将某个类依赖的其他类的实例注入到这个类的实例中。

这段话可能说的有点抽象,回到刚才的例子吧。刚刚我手动完成了依赖注入,比较麻烦,如果一个大型的项目这样做肯定会觉得很繁琐,而且不够优雅。因此我们需要有一位总管代替我们去干这个,这个总管就是容器。类的依赖管理全部交给容器去完成。因此,一般来说容器是一个全局的对象,大家共有的。

做一个自己的DI容器

写一个功能,我们首先需要分析问题,因此我们先要明白,对于一个简单的DI容器需要哪些功能,这直接关系到我们代码的编写。对于一个简单的容器,至少需要满足以下几点:

  • 创建所需类的实例

  • 完成依赖管理(DI)

  • 可以获取单例的实例

  • 全局唯一

综上,我们的容器类大约长这样:

class Container{        protected static $instance;        protected $instances = [];    private function __construct(){}      private function __clone(){}        public function singleton($class, ...$params)    {}        public function get($class, ...$params)    {}        protected function make($class, $params = [])    {}        public static function getInstance()    {        if (null === static::$instance) {            static::$instance = new static();        }        return static::$instance;    }}

大体骨架已经确定,接下来进入最核心的make方法:

protected function make($class, $params = []){  //如果不是反射类根据类名创建  $class = is_string($class) ? new ReflectionClass($class) : $class;  //如果传的入参不为空,则根据入参创建实例  if (!empty($params)) {    return $class->newInstanceArgs($params);  }  //获取构造方法  $constructor = $class->getConstructor();  //获取构造方法参数  $parameterClasses = $constructor ? $constructor->getParameters() : [];  if (empty($parameterClasses)) {    //如果构造方法没有入参,直接创建    return $class->newInstance();  } else {    //如果构造方法有入参,迭代并递归创建依赖类实例    foreach ($parameterClasses as $parameterClass) {      $paramClass = $parameterClass->getClass();      $params[] = $this->make($paramClass);    }    //最后根据创建的参数创建实例,完成依赖的注入    return $class->newInstanceArgs($params);  }}

为了容器的易用,我做了一些完善:

  • 实现ArrayAccess接口,使单例实例可以直接通过array的方式获取,如果该实例没有,则创建

  • 重写__get方法,更方便的获取

最终版:

class Container implements ArrayAccess{        protected static $instance;        protected $instances = [];    private function __construct(){}    private function __clone(){}        public function singleton($class, ...$params)    {        if (isset($this->instances[$class])) {            return $this->instances[$class];        } else {            $this->instances[$class] = $this->make($class, $params);        }        return $this->instances[$class];    }        public function get($class, ...$params)    {        return $this->make($class, $params);    }        protected function make($class, $params = [])    {        //如果不是反射类根据类名创建        $class = is_string($class) ? new ReflectionClass($class) : $class;        //如果传的入参不为空,则根据入参创建实例        if (!empty($params)) {            return $class->newInstanceArgs($params);        }        //获取构造方法        $constructor = $class->getConstructor();        //获取构造方法参数        $parameterClasses = $constructor ? $constructor->getParameters() : [];        if (empty($parameterClasses)) {            //如果构造方法没有入参,直接创建            return $class->newInstance();        } else {            //如果构造方法有入参,迭代并递归创建依赖类实例            foreach ($parameterClasses as $parameterClass) {                $paramClass = $parameterClass->getClass();                $params[] = $this->make($paramClass);            }            //最后根据创建的参数创建实例,完成依赖的注入            return $class->newInstanceArgs($params);        }    }        public static function getInstance()    {        if (null === static::$instance) {            static::$instance = new static();        }        return static::$instance;    }    public function __get($class)    {        if (!isset($this->instances[$class])) {            $this->instances[$class] = $this->make($class);        }        return $this->instances[$class];    }    public function offsetExists($offset)    {        return isset($this->instances[$offset]);    }    public function offsetGet($offset)    {        if (!isset($this->instances[$offset])) {            $this->instances[$offset] = $this->make($offset);        }        return $this->instances[$offset];    }    public function offsetSet($offset, $value)    {    }    public function offsetUnset($offset) {        unset($this->instances[$offset]);    }}

现在借助容器我们写一下上面的代码:

$driver = $app->get(Driver::class);$driver->drive();//output:老司机正在驾驶普通汽车复制代码

就这么简单,老司机就能发车。这里默认注入的是Car的实例,如果需要开奔驰,那只需要这样:

$benz = $app->get(Benz::class);$driver = $app->get(Driver::class, $benz);$driver->drive();//output:老司机正在驾驶奔驰复制代码

按照PSR-11的要求,依赖注入容器需要实现Psr\Container\ContainerInterface接口,这里只是演示并未去实现,因为那需要引入Psr依赖库,比较麻烦,其实也很简单,只是多了几个方法,有兴趣的可以自己去了解下PSR-11的要求(传送门)。

这里只是实现了一个非常简陋的DI容器,实际中还需要考虑很多,而且这里的容器功能上还很简陋。还有一些坑没处理,比如出现循环依赖怎么处理、延迟加载的机制……

感谢各位的阅读,以上就是“怎么创建PHP DI容器”的内容了,经过本文的学习后,相信大家对怎么创建PHP DI容器这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是编程网,小编将为大家推送更多相关知识点的文章,欢迎关注!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

怎么创建PHP DI容器

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

怎么创建PHP DI容器

这篇文章主要讲解了“怎么创建PHP DI容器”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“怎么创建PHP DI容器”吧!由开车开始先开个车,为大家举个栗子:class Driver{
2023-06-21

C++怎么创建vector容器

这篇文章主要介绍“C++怎么创建vector容器”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“C++怎么创建vector容器”文章能帮助大家解决问题。vector基本概念功能:vector数据结构和
2023-07-02

php怎么创建文件并写入内容

在PHP中,可以使用`file_put_contents`函数来创建文件并写入内容。该函数接受两个参数,第一个参数是要创建的文件的路径和名称,第二个参数是要写入文件的内容。下面是一个示例代码:```php$file = 'example.t
2023-08-11

ASP.NET Core依赖注入DI容器怎么实现

这篇文章主要介绍“ASP.NET Core依赖注入DI容器怎么实现”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“ASP.NET Core依赖注入DI容器怎么实现”文章能帮助大家解决问题。ASP.NE
2023-07-05

Spring IOC容器FactoryBean工厂Bean怎么创建

本篇内容主要讲解“Spring IOC容器FactoryBean工厂Bean怎么创建”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Spring IOC容器FactoryBean工厂Bean怎么创
2023-06-30

k8s中pod创建的容器怎么查看

要查看k8s中pod创建的容器,可以使用以下命令:首先获取pod的名称:kubectl get pods然后通过pod的名称查看容器的详情:kubectl describe pod 或者直接查看pod中的容器:kubectl
k8s中pod创建的容器怎么查看
2024-03-14

PHP中Cookie怎么创建

这篇文章主要介绍PHP中Cookie怎么创建,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!Cookie 是什么?cookie 常用于识别用户。cookie 是一种服务器留在用户计算机上的小文件。每当同一台计算机通过浏
2023-06-15

PHP的phar怎么创建

这篇文章主要介绍“PHP的phar怎么创建”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“PHP的phar怎么创建”文章能帮助大家解决问题。一 phar文件是什么Jar(Java Archive)文
2023-06-30

php怎么创建图像

这篇文章将为大家详细讲解有关php怎么创建图像,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。php创建图像具体步骤:1、设定标头,告诉浏览器要生成的MIME类型;2、创建一个画布;3、进行颜色管理;4、填
2023-06-20

如何创建Docker容器

本篇内容介绍了“如何创建Docker容器”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!GIScript2016是支持Python3的地理空间
2023-06-19

docker容器中怎么创建一个MariaDB镜像

docker容器中怎么创建一个MariaDB镜像,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。基于commit命令方式创建docker的安装[root@test01 ~]#
2023-06-04

vps怎么创建php环境

要创建VPS上的PHP环境,需要执行以下步骤:1. 安装Apache服务器:- 使用apt-get命令(适用于Debian/Ubuntu系统):```sudo apt-get updatesudo apt-get install apach
2023-08-20

vps怎么创建php环境

通过SSH创建PHP环境使用SSH连接到VPS,更新系统并安装PHP。安装所需模块并创建信息文件以测试安装。通过cPanel创建PHP环境登录cPanel,选择"软件"部分,并从下拉菜单中选择所需的PHP版本。保存更改。通过Plesk创建PHP环境登录Plesk,选择你的域名,并从"PHP设置"选项卡中选择所需的PHP版本。保存更改。
vps怎么创建php环境
2024-04-13

PHP怎么创建PPT文档

本篇内容介绍了“PHP怎么创建PPT文档”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!PHP功能非常强大,目前被许多程序员用来WEB开发。它
2023-06-17

怎么在Google Container Engine上申请创建Docker容器

本篇内容主要讲解“怎么在Google Container Engine上申请创建Docker容器 ”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“怎么在Google Container Engin
2023-06-12

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录