php container demo

一个简单的容器实现。
服务容器的目的是解决组件之间的依赖关系,降低耦合。
在系统运行过程中动态地为系统提供各种服务。

<?php

/**
 * 一个容器类
 */
class Container
{
	protected $bindings = []; // 绑定接口和生成实例的回调函数

	/**
	 * 向容器中添加一个绑定 
	 * abstract 服务名称
	 * concrete \Closure|string(命名空间+类名称)|null 服务所对应的具体内容
	 * shared这个参数用于标记绑定的服务是否为单例,但本demo并没有实现对单例服务的处理。
	 */
	public function bind($abstract, $concrete = null, $shared = false)
	{
		if (!$concrete instanceof Closure) {
			// 如果提供的参数不是回调函数,则产生默认的回调函数
			$concrete = $this->getClosure($abstract, $concrete);
		}

		// 将绑定关系存到数组中
		$this->bindings[$abstract] = compact('concrete', 'shared');
	}

	protected function getClosure($abstract, $concrete)
	{
		// $app一般为IoC容器对象,在调用回调生成实例时提供

		// 即bind函数中的 $concrete($this)

		return function ($app) use ($abstract, $concrete) {
			$method = ($abstract == $concrete) ? 'build' : 'make';

			//调用容器的make或build方法生成实例
			return $app->$method($concrete);
		};
	}

	// 从容器中解析服务
	public function make($abstract)
	{
		// 从绑定的数组中获取包含服务的回调函数
		$concrete = $this->getConcrete($abstract);
		if ($this->isBuildable($concrete, $abstract)) {
			$object = $this->build($concrete);
		} else {
			$object = $this->make($concrete);
		}

		return $object;
	}

	// 获取绑定的回调函数
	protected function getConcrete($abstract)
	{
		if ( !isset($this->bindings[$abstract])) {
			return $abstract;
		}

		return $this->bindings[$abstract]['concrete'];
	}

	// 检测对应绑定是否可build
	protected function isBuildable($concrete, $abstract)
	{
		return $concrete === $abstract || $concrete instanceof Closure;
	}

	// 实例化对象
	public function build($concrete)
	{
		// 如果绑定的内容是个闭包则返回闭包的执行结果
		if ($concrete instanceof Closure) {
			return $concrete($this);
		}

		// 此时$concrete就是个带命名空间的字符串,例如'\CCTT',然后通过PHP的反射机制,获取类的信息
		$reflector = new ReflectionClass($concrete);

		// 检测类是否可被实例化
		if (!$reflector->isInstantiable()) {
			echo $message = "Target [$concrete] is not instantiable";
		}

		// 获取类的构造函数
		$constructor = $reflector->getConstructor();

		// 如果没有构造函数则直接new该类并return
		if (is_null($constructor)) {
			return new $concrete;
		}

		// 获取构造函数的参数(依赖关系)
		$dependencies = $constructor->getParameters();

		// 获取构造函数要传的参(解决依赖注入,获取构造函数中依赖注入的参数的实例)
		$instances = $this->getDependencies($dependencies);

		// 带参数new该类并return
		return $reflector->newInstanceArgs($instances);
	}

	// 解决通过反射机制实例化对象的依赖
	protected function getDependencies($parameters)
	{
		$dependencies = [];

		foreach ($parameters as $parameter) {
			$dependency = $parameter->getClass();

			if (is_null($dependency)) {
				$dependencies[] = NULL; // 对非依赖注入参数这里暂不做处理
			} else {
				// 获取依赖注入的实例
				$dependencies[] = $this->resolveClass($parameter);
			}
		}

		return (array) $dependencies;
	}

	// 获取依赖注入的实例
	protected function resolveClass(ReflectionParameter $parameter)
	{
		// 实例化每个依赖,并返回
		return $this->make($parameter->getClass()->name);
	}
}


interface Source
{
	public function Stream();
}

class CCTT implements Source
{
	
	public function Stream()
	{
		echo __CLASS__.' Stream';
	}
}

class Qvod
{
	protected $source;
	
	public function __construct(Source $source)
	{
		$this->source = $source;
	}

	public function play()
	{
		$this->source->Stream();
	}
}

$app = new Container();
$app->bind('Source', 'CCTT');
$app->bind('player', 'Qvod');

$player = $app->make('player');
$player->play();
发布了116 篇原创文章 · 获赞 12 · 访问量 99万+

猜你喜欢

转载自blog.csdn.net/u012628581/article/details/102633340