容器(Service Container)

Laravel 的核心就是一个 IOC 容器,也称为服务容器,服务容器是管理类依赖和执行依赖注入的强大工具

依赖注入(Dependency Injection)

当依赖不由内部创建生产,而是由外部以参数或其他形式注入的,即是依赖注入(DI),依赖注入作为控制反转最常见的一种实现方式
依赖注入的实现方式一般有:

  • 构造函数或者初始化方法注入,依赖对象通过参数注入,这是最常用的方式
  • 属性注入,通过设置对象的成员或属性来注入
  • 方法注入,通过调用对象方法来注入
<?php
class db
{
   protected  $db;

   public function select()
   {
       echo '查询数据库';
   }
}
class User
{
   protected  $db;
   //DB $db 类型约束,仅允许db类注入
   public function __construct(db $db)
   {
       $this->db = $db;
   }
   public function index() {
       $this->db->select();
   }
}
$db = new db();
//依赖注入,将DB类注入到USER类中
$user = new User($db);
$user->index();

控制反转(Inversion Of Control)

假设 A 对象依赖 B 对象。即A类需要B类协助时完成某个功能事项时,传统的情况下是在A类内创建B类的实例,但在IOC这里,创建B类的工作不再由A类来完成,而是通过容器来实现对对象的创建、管理,从在A类内创建移到了外部,消除了A类对B类创建的控制,因此称为控制反转。

传统写法与DI写法区别:

<?php
interface db
{
    public function select();
}
class MysqlDb implements db
{
    public function select(){
        echo 'MysqlDb select';
    }
}
class MongoDb implements db
{
    public function select()
    {
        echo 'MongoDb  select';
    }
}
//传统写法
class User
{
    protected  $db;
    public function __construct()
    {
        $this->db = new MysqlDb();
    }
    public function select() {
        $this->db->select();
    }
}
$user = new User();
$user->select();
//这时如果要使用MongoDb,要么新写一个MongoUser类,要么修改user类的 new MysqlDb() 为 new MongoDb()
//下面看看依赖注入写法
class DiUser
{
    protected  $db;
    public function __construct(db $db) //约束注入类型
    {
        $this->db = $db;
    }
    public function select() {
        $this->db->select();
    }
}
$user1 = new DiUser(new MysqlDb());
$user1->select();  #Mysql数据库查询用户
$user2 = new DiUser(new MongoDb());
$user2->select();  #Mongo数据库查询用户
//想用什么数据库就注入什么数据库实例即可

一个简单的容器实例

原生构建IOC容器大致可以分为三大步骤来进行容器的构建。
1、绑定对象关系到容器的数组
2、通过反射拿到执行的类构造函数,拿到构造函数的参数
3、通过反射机制创建 操作对象

<?php
/**
 * Created by PhpStorm.
 * User: biny
 * Date: 2021/7/20
 * Time: 20:16
 */
error_reporting(E_ALL);
ini_set('display_errors','On');

interface db
{
    public function select();
}
class MysqlDb implements db
{
    public function select(){
        echo 'MysqlDb select';
    }
}
class MongoDb implements db
{
    public function select(){
        echo 'MongoDb  select';
    }
}
class User
{
    protected  $db;
    public function __construct(db $db) //约束注入类型
    {
        $this->db = $db;
    }
    public function select() {
        $this->db->select();
    }
}
class Ioc
{
    public $binding = [];

    public function bind($abstract, $concrete) {
        //绑定返回一个闭包,这里还不需要执行,仅做绑定
        $this->binding[$abstract]['concrete'] =  function ($ioc) use ($concrete) {
            return $ioc->build($concrete);
        };
    }

    public function make($abstract)
    {
        //获取绑定的闭包,并执行
        return $this->binding[$abstract]['concrete']($this);
    }
    //创建对象
    public function build($concrete)
    {
        //ReflectionClass反射(reflection)类报告了一个类的有关信息
        $reflector = new ReflectionClass($concrete);
        //getConstructor获取类的构造函数
        $constructor = $reflector->getConstructor();
        if  (is_null($constructor)) {
            //实例化对象  newInstance从指定的参数创建一个新的类实例
            return $reflector->newInstance();
        }else {
            //获取构成函数的参数  getParameters获取参数
            $dependen = $constructor->getParameters();
            //获取依赖 getDependencies
            $intances = $this->getDependencies($dependen);
            //newInstanceArgs 从给出的参数创建一个新的类实例
            return $reflector->newInstanceArgs($intances);
        }
    }
    //获取依赖,如果存在依赖就创建依赖
    protected function getDependencies($dependen) {
        $dependencies = [];
        foreach ($dependen as $paramter){
            $dependencies[] = $this->make($paramter->getClass()->name);

        }
        return $dependencies;
    }
}

$ioc = new Ioc();
$ioc->bind('db','MysqlDb');
$ioc->bind('user','User');
$user = $ioc->make('user');
$user->select();

$ioc->bind('db','MongoDb');
$user = $ioc->make('user');
$user->select();

$ioc->bind('db','MysqlDb');
$user = $ioc->make('user');
$user->select();
Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐