反射API(二)

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