<?php /** * 需求: * 创建一个类来动态调用Module对象, * 即该类可以自由加载第三方插件并集成进已有的系统,而不需要把第三方的代码硬编码进原有的代码。 */ class Person { public $name; function __construct($name) { $this->name = $name; } } interface Module { public function execute(); } class PersonModule implements Module { public function setPerson(Person $person) { echo 'PersonModule::setPerson():'.$person->name.PHP_EOL; } public function execute() { echo __METHOD__.PHP_EOL; } } class FtpModule implements Module { public function setHost($host) { echo 'FtpModule::setHost():'.$host.PHP_EOL; } public function setUser($user) { echo 'FtpModule::setUser():'.$user.PHP_EOL; } public function execute() { echo __METHOD__.PHP_EOL; } } class ModuelRunner { // 定义配置 要加载的模型名和要调用的setXxx()函数 private $configData = [ 'PersonModule' => ['person' => 'bob'], 'FtpModule' => ['host' => 'example', 'user' => 'anon'] ]; // 保存实例化的模型对象 private $modules = []; // 初始化 创建正确的Module对象 public function init() { $interface = new ReflectionClass('Module'); foreach ($this->configData as $moduleName => $params) { $module_class = new ReflectionClass($moduleName); // 确保模块类属于Module类型 if (!$module_class->isSubclassOf($interface)) { throw new Exception('unkonwn module type:'.$moduleName); } // 从指定的参数创建一个新的类实例 $module = $module_class->newInstance(); // 获得类中的所有方法 foreach ($module_class->getMethods() as $method) { $this->handleMethod($module, $method, $params); } // 保存模型对象 $this->modules[$moduleName] = $module; } } // 检验并调用setXxx()方法 public function handleMethod(Module $module,ReflectionMethod $method, $params) { // 获取方法名字 $name = $method->getName(); // 获取 ReflectionParmeter 对象组成的数组 $args = $method->getParameters(); // 规定所有的setter方法必须带有单个参数:字符串或者对象 if (count($args)!=1 || substr($name, 0, 3) != 'set') { return false; } // 获取setXxx方法的参数值 $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])); } } public function __get($name) { if ($name == 'modules') { return $this->modules; } } } echo '<pre>'; $test = new ModuelRunner(); $test->init(); echo '<hr>调用execute()<br>'; $module_obj = $test->modules; $module_obj['FtpModule']->execute(); $module_obj['PersonModule']->execute();