反射API的一個簡單實例

    假設我們創建一個類要動態調用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();


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章