如何用php写一个类似laravel框架的服务容器?这篇文章可能没有太多的文字。毕竟还是直接看代码比较好。我先贴出核心代码,里面有比较完整的注释。你可以直接阅读它。.另外,如果你自己测试的话,可以直接下载我的源码。源码中有示例代码说明如何测试。Gitee地址GitHub地址下面是实现容器的核心代码*/classContainer{/***当前全局可用的容器(如果有的话)**@varstatic*/privatestatic$instance;/***容器的绑定**@vararray[]*/private$bindings=[];/***容器的共享实例**@varobject[]*/private$instances=[];publicfunction__construct(){$this->instances[Container::class]=$this;}publicstaticfunctiongetInstance(){if(is_null(self::$instance)){self::$instance=newself;}self::$instance->instances[Container::class]=self::$instance;返回自我::$实例;}/***在容器中注册共享绑定**@param$abstract*@param$concrete*/publicfunctionsingleton($abstract,$concrete){$this->bind($abstract,$concrete,true);}/***注册与容器的绑定**@param$abstract*@param$concrete*@paramfalse$shared*/publicfunctionbind($abstract,$concrete,$shared=false){if($concreteinstanceofClosure){$this->bindings[$abstract]=compact('concrete','shared');}else{if(!is_string($concrete)||!class_exists($concrete)){thrownewInvalidArgumentException('参数2必须是回调或类。');$this->bindings[$abstract]=compact('concrete','shared');}/***将现有实例注册为容器中的共享实例**@paramstring$abstract*@parammixed$instance*@returnmixed*/publicfunctioninstance($abstract,$instance){$this->实例[$摘要]=$实例;返回$实例;}/***从容器中解析给定的类型**@paramstring$abstract目标类的名称*@paramarray$parameters实例化目标类所需的参数(非对象类型约束参数数组)*@返回混合|对象*/publicfunctionmake(string$abstract,array$parameters=[]){if(!isset($this->instances[$abstract])&&!isset($this->bindings[$abstract])){if(!class_exists($abstract))thrownewInvalidArgumentException("目标类[$abstract]不存在。");}if(isset($this->instances[$abstract])){return$this->instances[$abstract];}try{if(isset($this->bindings[$abstract])){$concrete=$this->bindings[$abstract]['concrete'];如果(is_callable($concrete)){$instance=$this->resolveCallable($concrete,$parameters);}else{$instance=$this->resolveClass($concrete,$parameters);}}else{$instance=$this->resolveClass($abstract,$parameters);}如果(isset($this->bindings[$abstract])&&$this->bindings[$abstract]['shared']){$this->instances[$abstract]=$instance;}返回$实例;}catch(\Exception$exception){echo($exception->getMessage().PHP_EOL);print_r($exception->getTraceAsString());}}/***解析回调函数时的依赖**@paramcallable$callbackName目标回调函数*@paramarray$realArgs*@returnmixed*@throwsReflectionException*/privatefunctionresolveCallable(callable$callbackName,array$realArgs=[]){$reflector=newReflectionFunction($callbackName);//获取回调函数的参数列表$parameters=$reflector->getParameters();$列表=[];如果(count($parameters)>0){$list=$this->resolveDependencies($parameters,$realArgs);}//调用函数参数return$reflector->invokeArgs($list);}/***解析对象时依赖**@paramstring|object$className目标类的名称*@paramarray$realArgs*@returnobject目标类对应的实例对象*@throwsReflectionException*/privatefunctionresolveClass($className,array$realArgs=[]){try{//反射目标类(解析它的方法和属性)$reflector=newReflectionClass($className);}catch(ReflectionException$e){thrownewRuntimeException("目标类[$className]不存在。",0,$e);}if(!$reflector->isInstantiable()){//检查类是否可实例化thrownewRuntimeException("Targetclass[$className]isnotinstantiable.");}//获取目标类的构造函数,当类没有构造函数时返回null$constructor=$reflector->getConstructor();//如果没有构造器,直接实例化if(is_null($constructor)){//returnnew$className;//或者你也可以这样直接实例化,因为目标类没有构造函数,不需要传参return$reflector->newInstance();}//获取构造函数的参数列表$parameters=$constructor->getParameters();//递归解析构造函数参数$list=$this->resolveDependencies($parameters,$realArgs);//根据给定的参数创建一个新的类实例return$reflector->newInstanceArgs($list);}/***递归解析依赖树**@paramarray$dependencies目标类的构造函数参数列表*@paramarray$parameters实例化目标类时的其他参数(非类型提示参数)*@returnarrayAll构造函数在实例化目标类时需要的参数*/privatefunctionresolveDependencies(array$dependencies,array$parameters=[]){//用来存储所有参数$results=[];foreach($dependenciesas$dependency){//获取类型提示class$obj=$dependency->getClass();//如果class为null,则表示依赖项是字符串或其他类型if(is_null($obj)){$parameterName=$dependency->getName();//获取参数的名称//检查参数是否有默认值if(!$dependency->isDefaultValueAvailable()){if(!isset($parameters[$parameterName])){thrownewRuntimeException($parameterName.'没有值');}else{$results[]=$parameters[$parameterName];}}else{//当参数有默认值时if(isset($parameters[$parameterName])){$results[]=$parameters[$parameterName];}else{$results[]=$dependency->getDefaultValue();//获取参数的默认值}}}else{//typehintingsure是一个类,需要递归处理依赖$objName=$obj->getName();//获取依赖的类名if(!class_exists($objName)){thrownewRuntimeException('Unabletoloadclass:'.$objName);}else{$results[]=$this->make($objName);}}}返回$结果;}}
