假设我们创建一个类要动态调用Module对象,即该类可以自动加载第三方插件并集成到已有的系统,而不需要把第三方插件硬编码进原有的代码。
要达到这个目的,可以在Module接口或抽象类中定义一个execute()方法,强制要求所有子类都要实现这个方法,可以允许用户在外部XML文件中列出所有的Module类,系统可以用XML提供的信息加载一定数目的Module对象,然后每个Module对象调用execute()。XML文件可以为每个Module实现属性和值,Module的创建者可以为每个属性名提供setter方法。
interface Module{
function execute();
}
class FtpModule implements Module{
function setHost($host){
print "FtpModule::setHost(): $host<br>";
}
function setUser($user){
print "FtpModule::setUser(): $user<br>";
}
function execute(){
}
}
class PresonModule implements Module{
function setPerson(Person $person){
print "PresonModule::setPerson(): $person->name<br>";
}
function execute(){
}
}
class ModuleRunner{
private $configData = array(
"PresonModule" => array('person'=>'bob'),
"FtpModule" => array(
'host' => 'example.com',
'user' => 'anon',
),
);
private $modules = array();
function init(){
$interface = new ReflectionClass('Module');
foreach ($this->configData as $modulename => $params) {
$medule_class = new ReflectionClass($modulename);
if(!$medule_class->isSubclassOf($interface)){
throw new Exception("unknown medule type: $medulename");
}
$medule = $medule_class->newInstance();
foreach ($medule_class->getMethods() as $method) {
$this->handleMethod($medule, $method, $params);
array_push($this->modules, $method);
}
}
}
function handleMethod(Module $module, ReflectionMethod $method, $params){
$name = $method->getName();
$args = $method->getParameters();
if(count($args) != 1 || substr($name, 0, 3)!="set"){
return false;
}
$property = strtolower(substr($name, 3));
if(!isset($params[$property])){
return false;
}
$arg_class = $args[0]->getClass();
if(empty($arg_class)){
$method->invoke($module, $params[$property]);
}else{
$method->invoke($module, $arg_class->newInstance($params[$property]));
}
}
}
$test = new ModuleRunner();
$test->init();