thinkphp5.1之Container容器和依赖注入

本文深入解析ThinkPHP5.1中的Container容器和依赖注入机制。Container通过set方法绑定类别名,get方法实现类实例化及依赖注入。文章详细介绍了Container内部工作流程,包括make方法的递归调用,invokeClass方法的类实例化过程,以及bindParams方法的参数绑定逻辑。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

thinkphp5.1之Container容器和依赖注入

Container容器的命名空间:namespace think;
Container容器通过 set 方法绑定类的别名和完整的类名,数据会放到 $this->bind 数组里以便后面实例化类用;然后通过 get 的方法实例化类和类的自动依赖注入。

例子

container::set(‘demo2’,’\app\common\Demo’);//绑定类的命名空间名,为实例化做准备。
container::get(‘demo2’,[‘name’=>‘小可爱’]);//获取容器中的对象实例

container::get方法详解

在获取容器中的对象实例是,首先调用了make()方法。
$abstract为标识时先取出对应的类名或匿名函数。如果是匿名函数调用$this->invokeFunction实例化类,如果是类名把标识和类名保存到$this->name数组中,最后调用自己make()方法。

if ($concrete instanceof Closure) {
	//匿名函数
    $object = $this->invokeFunction($concrete, $vars);
} else {
	//类名
    $this->name[$abstract] = $concrete;
    return $this->make($concrete, $vars, $newInstance);
}

$abstract为类名时调用$object = $this->invokeClass($abstract, $vars)来实例化类,如果不需要每次实例化会把实例保存到$this->instances数组中,已完整类名为键。

/**
 * 调用反射执行类的实例化 支持依赖注入
 * @access public
 * @param  string    $class 类名
 * @param  array     $vars  参数
 * @return mixed
 */
public function invokeClass($class, $vars = [])
{
    try {
	//调用类反射机制
        $reflect = new ReflectionClass($class);
	//判断有没有__make方法
        if ($reflect->hasMethod('__make')) {
	   //调用方法反射机制,参数(类名,方法名)
            $method = new ReflectionMethod($class, '__make');

            if ($method->isPublic() && $method->isStatic()) {
                $args = $this->bindParams($method, $vars);
		//使用数组给方法传送参数,并执行他。参数(调用方法的对象_如果是静态对象设置为null,使用数组传送的方法参数)
                return $method->invokeArgs(null, $args);
            }
        }
	//获取构造函数的参数
        $constructor = $reflect->getConstructor();
	//绑定构造函数的参数
        $args = $constructor ? $this->bindParams($constructor, $vars) : [];
	//实例化类
        return $reflect->newInstanceArgs($args);

    } catch (ReflectionException $e) {
        throw new ClassNotFoundException('class not exists: ' . $class, $class);
    }
}
    /**
     * 绑定参数
     * @access protected
     * @param  \ReflectionMethod|\ReflectionFunction $reflect 反射类
     * @param  array                                 $vars    参数
     * @return array
     */
    protected function bindParams($reflect, $vars = [])
    {
        // 判断数组类型 数字数组时按顺序绑定参数
        reset($vars);
        $type   = key($vars) === 0 ? 1 : 0;
        $params = $reflect->getParameters();//获取参数
    
        foreach ($params as $param) {
            $name      = $param->getName();//参数名
            $lowerName = Loader::parseName($name);//整理参数名
            $class     = $param->getClass();//参数是否是类
    
            if ($class) {
    	   //参数是类时
                $args[] = $this->getObjectParam($class->getName(), $vars);
            } elseif (1 == $type && !empty($vars)) {
    	   //传入参数是数字数组,删除第一个并绑定到$args[]
                $args[] = array_shift($vars);
            } elseif (0 == $type && isset($vars[$name])) {
    	   //传入参数是关联数组,绑定到$args[]
                $args[] = $vars[$name];
            } elseif (0 == $type && isset($vars[$lowerName])) {
    	   //传入参数是关联数组,绑定到$args[]
                $args[] = $vars[$lowerName];
            } elseif ($param->isDefaultValueAvailable()) {
    	   //传入数组找不到使用默认值,否则抛出异常
                $args[] = $param->getDefaultValue();
            } else {
                throw new InvalidArgumentException('method param miss:' . $name);
            }
        }
    
        return $args;
    }

判断构造函数中有依赖注入调用$this->getObjectParam函数完成依赖注入的实例化,但不可传入参数。

  /**
 * 获取对象类型的参数值,用于依赖注入
 * @access protected
 * @param  string   $className  类名
 * @param  array    $vars       参数
 * @return mixed
 */
protected function getObjectParam($className, &$vars)
{
    $array = $vars;
    $value = array_shift($array);

    if ($value instanceof $className) {
        $result = $value;
        array_shift($vars);
    } else {
	 //实例化依赖注入,不可传入参数
        $result = $this->make($className);
    }

    return $result;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值