PHP通过反射动态加载第三方类和获得类源码的实例
使用反射动态加载第三方类
用反射加载第三方类用处在于:
使用XML或其他配文件配置要加载的类,从而和系统源代码分离。
对加载的类进行类检查,是加载的类符合自己定义的结构。
<?php abstractclassModule{#核心Module类库 functionbaseFunc(){ echo"IambaseFunc"; } abstractfunctionexecute(); } classModuleRunner{ private$configData=array(#模拟xml配置,动态配置需要加载的Module "PersonModule"=>array("person"=>"bob"), "FtpModule"=>array("host"=>"example.com","user"=>"anon") ); private$modules=array(); functioninit(){#初始化ModuleRunner,加载配置中的Module $parent=newReflectionClass("Module"); foreach($this->configDataas$moduleName=>$params){#检查配置中的Module是否合法 $moduleClass=newReflectionClass($moduleName); if(!$moduleClass->isSubclassOf($parent)){#检查是否是Module的子类型 thrownewException("unknowntype:{$moduleName}"); } $module=$moduleClass->newInstance(); foreach($moduleClass->getMethods()as$method){#检查配置中的函数的参数格式是否正确 $this->handleMothod($module,$method,$params); } array_push($this->modules,$module);#加载Module } } privatefunctionhandleMothod(Module$module,ReflectionMethod$method,$params){#检查Module中的方法参数是
否和传入的$params名字相同,并且具有set方法
$name=$method->getName(); $args=$method->getParameters(); if(count($args)!=1||substr($name,0,3)!="set"){#如果没有配置中的类的方法的参数个数不为1,或者方法名前3个字母不为set,返回false returnfalse; } $property=strtolower(substr($name,3)); if(!isset($params[$property])){#如果方法名后三个字母与配置中的参数名不同,返回false returnfalse; } $argClass=$args[0]->getClass();#获取参数的类型 if(empty($argClass)){ $method->invoke($module,$params[$property]);#参数无类型限制则直接调用set方法 }else{ $method->invoke($module,$argClass->newInstance($params[$property]));#有类型限制则新建一个实例并调用set方法 } } publicfunctiongetModules(){ return$this->modules; } } classPerson{#第三方类 public$name; function__construct($name){ $this->name=$name; } } classFtpModuleextendsModule{#用户自定义第三方Module private$host="defaulthost"; private$user="defaultuser"; functionsetHost($host){ $this->host=$host; } functionsetUser($user){ $this->user=$user; } functionexecute(){ echo"{$this->user}user{$this->host}"; } } classPersonModuleextendsModule{#用户自定义第三方Module private$person; functionsetPerson(Person$person){ $this->person=$person; } functionexecute(){ if(isset($person)){ echo"Iam{$this->person->name}"; }else{ echo"Iamnouser"; } } } $modRunner=newModuleRunner(); $modRunner->init(); var_dump($modRunner); ?>
输出
object(ModuleRunner)#1(2){["configData":"ModuleRunner":private]=>array(2){["PersonModule"]=>array(1){["person"]=>string(3)"bob"}["FtpModule"]=>array(2){["host"]=>string(11)"example.com"["user"]=>string(4)"anon"}}["modules":"ModuleRunner":private]=>array(2){[0]=>object(PersonModule)#4(1){["person":"PersonModule":private]=>object(Person)#10(1){["name"]=>string(3)"bob"}}[1]=>object(FtpModule)#3(2){["host":"FtpModule":private]=>string(11)"example.com"["user":"FtpModule":private]=>string(4)"anon"}}}
通过反射获得类源码
<?php functiongetSource(ReflectionClass$ref){ $path=$ref->getFileName();#获取脚本文件文件名 $file=file($path);#file()方法获取文件内容,并将内容保存在一个数组中,数组每个元素保存一行内容 $start=$ref->getStartLine();#获取类在脚本中的第一行行号 $end=$ref->getEndLine();#获取类在脚本中最后一行的行号 $source=implode(array_slice($file,$start-1,$end-$start+1));#拼装类源码 var_dump($source); } classPerson{ public$age; private$name; functionsay(){ echo"yes"; } } $ref=newReflectionClass("Person"); getSource($ref); ?>