Table of Contents
First, let’s look at a piece of code:
Let’s optimize the code
面向接口
工厂
DI(重点来了)
dependency injection container
使用示例
针对接口
Home Backend Development PHP Tutorial How to parse PHP dependency injection

How to parse PHP dependency injection

Aug 16, 2017 am 09:27 AM
php method injection


Abstract: High-level modules should not depend on low-level modules, both should rely on abstractions. Abstractions should not depend on details, details should depend on abstractions.

First, let’s look at a piece of code:

1

2

3

4

5

6

7

8

class A{        public function echo()

        {                echo 'A'.PHP_EOL;

        }

}class EchoT {        protected  $t;        public function __construct()

        {              $this->t = new A();

        }        public function echo(){                $this->t->echo();

        }

}

Copy after login

Initially, we all use the new method internally, and the EchoT class relies heavily on class A. Whenever class A changes, class EchoT must also change.

Let’s optimize the code

1

2

class EchoT {        protected  $t;        public function __construct($t//构造器注入由构造器注入到其中        {              $this->t = $t;

        }

Copy after login

You can see that if you do this. On a large scale, we decouple the program. No matter how you change class A, class EchoT does not need to be changed. No longer dependent on A. But a new problem has come again. We only have A now. What if B or CDEFG comes?

面向接口

1

2

3

4

5

6

7

8

9

10

11

interface T{        public function echo();

}class A{        public function echo()

        {                echo 'A'.PHP_EOL;

        }

}class B implements T{        public function echo()

        {                echo 'B'.PHP_EOL;

        }

}class EchoT {        protected  $t;        public function __construct(T $t//构造器注入由构造器注入到其中        {              $this->t = $t;

        }        public function echo(){                $this->t->echo();

        }

}

Copy after login

将T抽象出为接口,这样,EchoT类中的echo方法变成一个抽象的方法,不到运行那一刻,不知道他们的Method方式是怎么实现的。

工厂

1

2

3

function getT($str) {    if(class_exists($str)){        return new $str();

        }

}

Copy after login

T要使用哪个是不明确的,因此,我们可以将其工厂化。【看上去很简单,在DI实际上有体现】

DI(重点来了)

首先,我们看一下PHP的psr规范。

http://www.php-fig.org/psr/psr-11/

官方定义的接口

1

2

Psr\Container\ContainerInterface

包含两个方法function get($id);function has($id);

Copy after login

仔细看上面的工厂,是不是和get($id)很一致,PHP官方将其定义为容器(Container,我个人理解,就是一个复杂的工厂)

dependency injection container

依赖注入容器

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

namespace Core;use Psr\Container\ContainerInterface;class Container implements ContainerInterface{        protected $instance = [];//对象存储的数组

        public function __construct($path) {                $this->_autoload($path);  //首先我们要自动加载  psr-autoload

        }        public function build($className)

        {                if(is_string($className) and $this->has($className)) {                        return $this->get($className);

                }                //反射

                $reflector = new \ReflectionClass($className);                if (!$reflector->isInstantiable()) {                        throw new \Exception("Can't instantiate ".$className);

                }                // 检查类是否可实例化, 排除抽象类abstract和对象接口interface

                if (!$reflector->isInstantiable()) {                        throw new \Exception("Can't instantiate ".$className);

                }                /** @var \ReflectionMethod $constructor 获取类的构造函数 */

                $constructor = $reflector->getConstructor();                // 若无构造函数,直接实例化并返回

                if (is_null($constructor)) {                        return new $className;

                }                // 取构造函数参数,通过 ReflectionParameter 数组返回参数列表

                $parameters = $constructor->getParameters();                // 递归解析构造函数的参数

                $dependencies = $this->getDependencies($parameters);                // 创建一个类的新实例,给出的参数将传递到类的构造函数。

                $class $reflector->newInstanceArgs($dependencies);                $this->instance[$className] = $class;                return $class;

        }        /**

         * @param array $parameters

         * @return array

         */

        public function getDependencies(array $parameters)

        {

                $dependencies = [];                /** @var \ReflectionParameter $parameter */

                foreach ($parameters as $parameter) {                        /** @var \ReflectionClass $dependency */

                        $dependency = $parameter->getClass();                        if (is_null($dependency)) {                                // 是变量,有默认值则设置默认值

                                $dependencies[] = $this->resolveNonClass($parameter);

                        } else {                                // 是一个类,递归解析

                                $dependencies[] = $this->build($dependency->name);

                        }

                }                return $dependencies;

        }        /**

         * @param \ReflectionParameter $parameter

         * @return mixed

         * @throws \Exception

         */

        public function resolveNonClass(\ReflectionParameter $parameter)

        {                // 有默认值则返回默认值

                if ($parameter->isDefaultValueAvailable()) {                        return $parameter->getDefaultValue();

                }                throw new \Exception($parameter->getName().' must be not null');

        }        /**

         * 参照psr-autoload规范

         * @param $path

         */

        public function _autoload($path) {

                spl_autoload_register(function(string $class) use ($path) {

                        $file = DIRECTORY_SEPARATOR.str_replace('\\',DIRECTORY_SEPARATOR, $class).'.php';                        if(is_file($path.$file)) {                                include($path.$file);                                return true;

                        }                        return false;

                });

        }        public function get($id)

        {                if($this->has($id)) {                        return $this->instance[$id];

                }                if(class_exists($id)){                        return $this->build($id);

                }                throw new ClassNotFoundException('class not found');  //实现的PSR规范的异常

        }        public function has($id)

        {                return isset($this->instance[$id]) ? true : false;

        }

}

Copy after login

使用示例

1

$container = new Container('../');//假设这是路径$echoT = $container->get(\Test\EchoT::class);     //假设echoT类的命名空间是\Test$echoT->echo();

Copy after login

这个时候,会出现一个问题:

1

2

3

4

5

  // 检查类是否可实例化, 排除抽象类abstract和对象接口interface

                if (!$reflector->isInstantiable()) {                        throw new \Exception("Can't instantiate ".$className);

                }

因为接口T是无法实例化的,所以,一般在程序内,我们都加上别名(参照laravel框架)

$container->alisa(\Test\T::class,\Test\T\A::class);  //指定接口T使用类A(控制反转)

Copy after login

针对接口

下面是alias方法

1

2

3

4

5

6

7

8

9

10

     public function alias(string $key, $class, bool $singleton = true)

       {                if($singleton) {                        $this->singleton[] = $class;

               }                $this->aliases[$key] = $class;                return $this;

       }    //同时,我们需要在build的时候进行判断是否为别名

public function build($className)

       {                if(is_string($className) and $this->has($className)) {                        return $this->get($className);

               }                if(isset($this->aliases[$className])) {                        if(is_object($this->aliases[$className])) {                               return $this->aliases[$className];

                       }

                       $className = $this->aliases[$className];

               }

Copy after login

就此,一个简单的PHP容器就实现了。

The above is the detailed content of How to parse PHP dependency injection. For more information, please follow other related articles on the PHP Chinese website!

Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn

Hot AI Tools

Undresser.AI Undress

Undresser.AI Undress

AI-powered app for creating realistic nude photos

AI Clothes Remover

AI Clothes Remover

Online AI tool for removing clothes from photos.

Undress AI Tool

Undress AI Tool

Undress images for free

Clothoff.io

Clothoff.io

AI clothes remover

AI Hentai Generator

AI Hentai Generator

Generate AI Hentai for free.

Hot Article

R.E.P.O. Energy Crystals Explained and What They Do (Yellow Crystal)
3 weeks ago By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. Best Graphic Settings
3 weeks ago By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. How to Fix Audio if You Can't Hear Anyone
3 weeks ago By 尊渡假赌尊渡假赌尊渡假赌
WWE 2K25: How To Unlock Everything In MyRise
3 weeks ago By 尊渡假赌尊渡假赌尊渡假赌

Hot Tools

Notepad++7.3.1

Notepad++7.3.1

Easy-to-use and free code editor

SublimeText3 Chinese version

SublimeText3 Chinese version

Chinese version, very easy to use

Zend Studio 13.0.1

Zend Studio 13.0.1

Powerful PHP integrated development environment

Dreamweaver CS6

Dreamweaver CS6

Visual web development tools

SublimeText3 Mac version

SublimeText3 Mac version

God-level code editing software (SublimeText3)

PHP 8.4 Installation and Upgrade guide for Ubuntu and Debian PHP 8.4 Installation and Upgrade guide for Ubuntu and Debian Dec 24, 2024 pm 04:42 PM

PHP 8.4 brings several new features, security improvements, and performance improvements with healthy amounts of feature deprecations and removals. This guide explains how to install PHP 8.4 or upgrade to PHP 8.4 on Ubuntu, Debian, or their derivati

CakePHP Date and Time CakePHP Date and Time Sep 10, 2024 pm 05:27 PM

To work with date and time in cakephp4, we are going to make use of the available FrozenTime class.

CakePHP File upload CakePHP File upload Sep 10, 2024 pm 05:27 PM

To work on file upload we are going to use the form helper. Here, is an example for file upload.

Discuss CakePHP Discuss CakePHP Sep 10, 2024 pm 05:28 PM

CakePHP is an open-source framework for PHP. It is intended to make developing, deploying and maintaining applications much easier. CakePHP is based on a MVC-like architecture that is both powerful and easy to grasp. Models, Views, and Controllers gu

CakePHP Creating Validators CakePHP Creating Validators Sep 10, 2024 pm 05:26 PM

Validator can be created by adding the following two lines in the controller.

CakePHP Logging CakePHP Logging Sep 10, 2024 pm 05:26 PM

Logging in CakePHP is a very easy task. You just have to use one function. You can log errors, exceptions, user activities, action taken by users, for any background process like cronjob. Logging data in CakePHP is easy. The log() function is provide

How To Set Up Visual Studio Code (VS Code) for PHP Development How To Set Up Visual Studio Code (VS Code) for PHP Development Dec 20, 2024 am 11:31 AM

Visual Studio Code, also known as VS Code, is a free source code editor — or integrated development environment (IDE) — available for all major operating systems. With a large collection of extensions for many programming languages, VS Code can be c

CakePHP Quick Guide CakePHP Quick Guide Sep 10, 2024 pm 05:27 PM

CakePHP is an open source MVC framework. It makes developing, deploying and maintaining applications much easier. CakePHP has a number of libraries to reduce the overload of most common tasks.

See all articles