反射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();
原文地址:https://www.cnblogs.com/cshaptx4869/p/10332285.html