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);
?>