


One article to understand and implement IOC containers in modern PHP frameworks
This article brings you relevant knowledge about PHP, which mainly introduces the relevant content about IOC containers. The full name of IOC is: Inversion Of Control, inversion control. Let’s talk about it together. Take a look, hope it helps everyone.
What is a container?
I believe many people have heard of dependency injection. The basic conditions for dependency injection implementation are inseparable from containers. Containers are used to manage class dependencies and injection, and are responsible for service management and decoupling components. The simplest understanding is We can understand a container as a super large array dedicated to storing objects.
As shown in the figure, the caller obtains the object instance through the label of the container. As can be seen in the figure, it can be obtained through ::class or directly through the object. Indicates getting the instance object.
What is IOC?
You may have heard of IOC containers. The full name of IOC is: (Inversion Of Control, inversion control).
Let’s understand what inversion of control is. In our traditional coding, our dependencies between classes are usually passed by new objects through coding, but using inversion of control we You can give control of the object to the container or framework for implementation. The purpose is to allow us to create objects without hard coding. As you can see from Figure 1, there are many objects stored in the container, and we can use them directly when we want to use them. The objects in the container do not require us to create them in code. When a certain class object is needed, the object will be obtained from the container. If the object does not exist, it will be automatically created. This means that we omit the process of creating objects in the code, and the container helps us realize this creation process. This is called inversion control. To sum up IOC in one sentence: transfer the control of creating objects to the instantiation of the container implementation class.
For example: If we want to create a class without using IOC
<?php class Sunny{ } $sunny = new Sunny();
We need to manually create a new class. In this case, it is hard-coded in the code.
The code using the IOC container can be written like this.
<?php class Sunny{ } $sunny = Container::getBean(Sunny::class);
Help us implement this class inside the container. Some students may have questions when they see this. If I use new Sunny, won’t the code be shorter and simpler? Let’s look at an example after looking at dependency injection.
Dependency Injection
Now that we know what IOC is, a new question arises. When we create a class, what should we do if the constructors of some classes require us to pass parameters? Through the study of IOC, we know that the IOC container will help us solve the problem of object instance creation. When creating an object in the container, it will perform a dependency search if it finds that the class has other dependencies. The process of the container finding the required objects is called DL ( Dependency Lookup, dependency lookup). Injecting required dependencies into code fragments is called DI (Dependency Injection, dependency injection).
For example, the new Sunny example mentioned in IOC. If there are multiple dependencies between classes.
<?php class Computer{ public function run(){ echo "编程中....\n"; } } class Sunny{ private $computer; public function __construct(Computer $computer){ $this->computer = $computer; } public function program(){ $this->computer->run(); } } $sunny = new Sunny(new Computer()); $sunny->program();
Here you can see that the Sunny class wants to depend on the Computer class for programming. If you use the IOC container to implement dependency injection, the code will be simple.
<?php class Computer{ public function run(){ echo "编程中....\n"; } } class Sunny{ private $computer; public function __construct(Computer $computer){ $this->computer = $computer; } public function program(){ $this->computer->run(); } } $sunny = Container::getBean(Sunny::class); $sunny->program();
One sentence summary: Solve the dependence on other classes when creating class instances, and dynamically provide an object with other objects it needs.
Dependency Inversion
The problem solved by dependency inversion is to loosely couple the heavy dependencies between modules. The upper modules should not rely on the underlying modules, they should all rely on abstractions. Usually, a simple understanding of dependency inversion is programming towards interfaces or abstractions. Let's take a look at interface-oriented programming through the following example.
class Cache{ public function set($key,$value){ $redis = new CFile(); $redis->set($key,$value); } } class CFile{ public function set($key,$value){ echo "file:{$key}->{$value}\n"; } } $cache = new Cache(); $cache->set("name","sunny");
The above code seems to have no big problem, but what if one day the file cache is changed to Redis cache?
class Cache{ public function set($key,$value){ $redis = new CRedis(); $redis->set($key,$value); } } class CRedis{ public function set($key,$value){ echo "redis:{$key}->{$value}\n"; } } $cache = new Cache(); $cache->set("name","sunny");
It can be seen from this code that when the driver used by a cache changes, the Cache code must also make corresponding changes, because the code is written on the caller and the coupling degree becomes high. . It's the same as modifying the code, allowing programmers to program towards the interface, making the code more versatile and standardized.
interface ICache{ public function set($key,$value); } class CRedis implements ICache { public function set($key,$value) { echo "redis:{$key}->{$value}\n"; } } class CFile implements ICache{ public function set($key,$value) { echo "file:{$key}->{$value}\n"; } } class Cache{ private $drive; public function __construct(ICache $drive) { $this->drive = $drive; } public function set($key,$value){ $this->drive->set($key,$value); } } $cache = new Cache(new CFile()); $cache->set("name","sunny");
Many people think when they see this code, shouldn’t I just pass the desired object directly into the constructor? Why do we need to define an interface? In fact, the interface is defined to standardize the code. No matter which driver you use, as long as it implements my interface, you can use it. Without an interface, developers will not know what methods should be included in the driver when developing the driver. When we use interface, we only need to program for the interface. Cache does not care about how the class is implemented. Cache only operates according to the interface method.
Summary in one sentence: Dependency inversion to achieve loose coupling
Practical combat: Implementing containers based on container principles
<?php class Container { // 当前容器对象 private static $instance; // 存放在容器里面到实例 protected $instances = []; private function __construct() { } public static function getInstance() { if (!self::$instance) { self::$instance = new static(); } return self::$instance; } /** * 获取对象实例 * @param $key * @return mixed */ public function get($key) { if (isset($this->instances[$key])) { return $this->instances[$key]; } } /** * 绑定对象、闭包、类到容器 * @param $key * @param null $concrete * @return Container */ public function bind($key, $concrete = null) { if ($concrete instanceof Closure) { $this->instances[$key] = $concrete; } elseif (is_object($concrete)) { $this->instances[$key] = $concrete; } return $this; } } class Sunny { public function getName() { echo time() . "\n"; } } $app = Container::getInstance(); $sunny = $app->bind(Sunny::class,new Sunny()); $sunny = $app->get(Sunny::class); $sunny->getName();
Practical combat: Implementing dependency injection
Container.php <?php class Container { // 当前容器对象 private static $instance; // 存放在容器里面到实例 protected $instances = []; private function __construct() { } public static function getInstance() { if (!self::$instance) { self::$instance = new static(); } return self::$instance; } /** * 获取对象实例 * @param $key * @return mixed * @throws ReflectionException */ public function get($key) { if (isset($this->instances[$key])) { return $this->instances[$key]; } return $this->make($key); } /** * 绑定对象、闭包、类到容器 * @param $key * @param null $concrete * @return Container * @throws ReflectionException */ public function bind($key, $concrete = null) { if ($concrete instanceof Closure) { $this->instances[$key] = $concrete; } elseif (is_object($concrete)) { $this->instances[$key] = $concrete; } else { $this->make($key, $concrete); } return $this; } /** * 创建类绑定到类实例 * @param $abstract * @param null $atgs * @return mixed * @throws ReflectionException */ public function make($abstract, $atgs = null) { if (isset($this->instances[$abstract])) { return $this->instances[$abstract]; } $object = $this->invokeClass($abstract); $this->instances[$abstract] = $object; return $object; } /** * 反射解析类 * @param $abstract * @return object * @throws ReflectionException */ public function invokeClass($abstract) { $reflectionClass = new \ReflectionClass($abstract); // 获取构造方法 $construct = $reflectionClass->getConstructor(); // 获取参数得到实例 $params = $construct ? $this->parserParams($construct) : []; $object = $reflectionClass->newInstanceArgs($params); return $object; } /** * 解析构造方法参数 * @param $reflect * @return array * @throws ReflectionException */ public function parserParams(ReflectionMethod $reflect) { $args = []; $params = $reflect->getParameters(); if (!$params) { return $args; } if (count($params) > 0) { foreach ($params as $param) { $class = $param->getClass(); if ($class) { $args[] = $this->make($class->getName()); continue; } // 获取变量的名称 $name = $param->getName(); // 默认值 $def = null; // 如果有默认值,从默认值获取类型 if ($param->isOptional()) { $def = $param->getDefaultValue(); } $args[] = $_REQUEST[$name] ?? $def; } } return $args; } } Test.php <?php class Test { public $name; private $test1; public function __construct(Test1 $test1) { $this->test1 = $test1; $this->name = $this->test1->getName(); } } Test1.php <?php class Test1 { public function getName(){ return "test1返回的名字"; } } Sunny.php <?php require_once "./Container.php"; require_once "./Test.php"; require_once "./Test1.php"; class Sunny { private $test; public function __construct(Test $test) { $this->test = $test; } public function getName() { echo "获取test里面的name:{$this->test->name}\n"; } } $app = Container::getInstance(); $sunny = $app->get(Sunny::class); $sunny->getName();
Recommended learning: "PHP Video Tutorial"
The above is the detailed content of One article to understand and implement IOC containers in modern PHP frameworks. For more information, please follow other related articles on the PHP Chinese website!

Hot AI Tools

Undresser.AI Undress
AI-powered app for creating realistic nude photos

AI Clothes Remover
Online AI tool for removing clothes from photos.

Undress AI Tool
Undress images for free

Clothoff.io
AI clothes remover

Video Face Swap
Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Article

Hot Tools

Notepad++7.3.1
Easy-to-use and free code editor

SublimeText3 Chinese version
Chinese version, very easy to use

Zend Studio 13.0.1
Powerful PHP integrated development environment

Dreamweaver CS6
Visual web development tools

SublimeText3 Mac version
God-level code editing software (SublimeText3)

Hot Topics

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

If you are an experienced PHP developer, you might have the feeling that you’ve been there and done that already.You have developed a significant number of applications, debugged millions of lines of code, and tweaked a bunch of scripts to achieve op

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

JWT is an open standard based on JSON, used to securely transmit information between parties, mainly for identity authentication and information exchange. 1. JWT consists of three parts: Header, Payload and Signature. 2. The working principle of JWT includes three steps: generating JWT, verifying JWT and parsing Payload. 3. When using JWT for authentication in PHP, JWT can be generated and verified, and user role and permission information can be included in advanced usage. 4. Common errors include signature verification failure, token expiration, and payload oversized. Debugging skills include using debugging tools and logging. 5. Performance optimization and best practices include using appropriate signature algorithms, setting validity periods reasonably,

A string is a sequence of characters, including letters, numbers, and symbols. This tutorial will learn how to calculate the number of vowels in a given string in PHP using different methods. The vowels in English are a, e, i, o, u, and they can be uppercase or lowercase. What is a vowel? Vowels are alphabetic characters that represent a specific pronunciation. There are five vowels in English, including uppercase and lowercase: a, e, i, o, u Example 1 Input: String = "Tutorialspoint" Output: 6 explain The vowels in the string "Tutorialspoint" are u, o, i, a, o, i. There are 6 yuan in total

This tutorial demonstrates how to efficiently process XML documents using PHP. XML (eXtensible Markup Language) is a versatile text-based markup language designed for both human readability and machine parsing. It's commonly used for data storage an

Static binding (static::) implements late static binding (LSB) in PHP, allowing calling classes to be referenced in static contexts rather than defining classes. 1) The parsing process is performed at runtime, 2) Look up the call class in the inheritance relationship, 3) It may bring performance overhead.

What are the magic methods of PHP? PHP's magic methods include: 1.\_\_construct, used to initialize objects; 2.\_\_destruct, used to clean up resources; 3.\_\_call, handle non-existent method calls; 4.\_\_get, implement dynamic attribute access; 5.\_\_set, implement dynamic attribute settings. These methods are automatically called in certain situations, improving code flexibility and efficiency.
