/**
* 需求:
* 创建一个类来动态调用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;
}
}
}
$test = new ModuelRunner();
$test->init();
echo ‘
调用execute()
‘;
$module_obj = $test->modules;
$module_obj[‘FtpModule‘]->execute();
$module_obj[‘PersonModule‘]->execute();