用户
 找回密码
 入住 CI 中国社区
搜索
查看: 2477|回复: 2
收起左侧

[HMVC] HMVC里module代码求解释(Hex版本)

[复制链接]
发表于 2013-7-3 14:22:59 | 显示全部楼层 |阅读模式
本帖最后由 kinwyb 于 2013-7-4 08:48 编辑

原始代码是
PHP复制代码
class CI_Module {
 
    /**
     * Constructor
     *
     * @access public
     */

    function __construct()
    {
        // 实例化自己的 Loader 类
        $CI =& get_instance();
        $this->load = clone $CI->load;
 
        // CI 系统对象采用引用传递的方式,直接赋值给 Module。
        // 当然也可以采用 clone 的方式,可能需要根据不同项目做权衡。
        foreach ($CI->load->get_base_classes() as $var => $class)
        {
            // 排除 Loader 类,因为已经 clone 过了
            if ($var == 'loader')
            {
                continue;
            }
            // 赋值给 Module
            $this->$var =& load_class($class);
        }
        // 处理自动装载的类库和模型
        $autoload = array_merge($CI->load->_ci_autoload_libraries, $CI->load->_ci_autoload_models);
        foreach ($autoload as $item)
        {
            if (!empty($item) and isset($CI->$item))
            {
                $this->$item =& $CI->$item;
            }
        }
        // 处理数据库对象
        if (isset($CI->db))
        {
            $this->db =& $CI->db;
        }
 
        // 利用 PHP5 的反射机制,动态确定 Module 类名和路径
        $reflector = new ReflectionClass($this);
 
        $path = substr(dirname($reflector->getFileName()), strlen(realpath(APPPATH.'modules').DIRECTORY_SEPARATOR));
        $class_path = implode('/', array_slice(explode(DIRECTORY_SEPARATOR, $path), 0, -1));
        $class_name = $reflector->getName();
 
        // 通知 Loader 类,Module 就绪
        $this->load->_ci_module_ready($class_path, $class_name);
 
        // 把自己放到全局超级对象中
        $CI->$class_name = $this;
 
        log_message('debug', "$class_name Module Class Initialized");
    }
}
复制代码


// 把自己放到全局超级对象中
$CI->$class_name = $this;
这句代码有什么用处?难道module能像model一样引用一次然后重复使用么?

还有就是发现原来的很多都是从CI里引用(复制)方法到$this
$this->$item =& $CI->$item;
那为什么不直接改成直接从CI里取
PHP复制代码
 
class CI_Module
{
    /**
     * Constructor
     *
     * @access public
     */

    function __construct()
    {
        // 实例化自己的 Loader 类
        $CI =& get_instance();
        $this->load =clone $CI->load;
 
        // 利用 PHP5 的反射机制,动态确定 Module 类名和路径
        $reflector = new ReflectionClass($this);
   
        $path = substr(dirname($reflector->getFileName()), strlen(realpath(APPPATH.'modules').DIRECTORY_SEPARATOR));
        $class_path = implode('/', array_slice(explode(DIRECTORY_SEPARATOR, $path), 0, -1));
        $class_name = $reflector->getName();
   
        // 通知 Loader 类,Module 就绪
        $this->load->_ci_module_ready($class_path, $class_name);
       
        log_message('debug', "$class_name Module Class Initialized");
    }
   
    function __get($key)
    {
        $CI =& get_instance();
        return $CI->$key;
    }
}
 
复制代码

这样貌似也没出现什么错误,但是为什么不这么写?这么写是不是会出现问题
小白求解释

发表于 2013-7-4 18:19:07 | 显示全部楼层
首先感谢对代码的分析。

第一个问题,把自己放到全局超级变量中,我的考虑是这样符合CI自己的设计原则,因为CI的所有对象都会存在超级对象中,另外,放到超级对象中,系统才能在需要的地方去控制某个module实例,否则这个module实例想引用的时候怎么办呢?如果不放到超级对象中,那就只能弄个全局变量了,显然是不合适的。

第二个问题,我的考虑是,只共享autoload的类库实例,而非autoload的类库实例是隔离的;当然,你的写法也是很棒的,这样就会让module与控制器有更好的连通性。
我的设计宗旨是解耦,所以选择了隔离。
 楼主| 发表于 2013-7-5 09:37:43 | 显示全部楼层
Hex 发表于 2013-7-4 18:19
首先感谢对代码的分析。

第一个问题,把自己放到全局超级变量中,我的考虑是这样符合CI自己的设计原则,因 ...

多谢指点。

按照我的写法使用中会出现一个问题:
因为在MY_loader里重写了database方法,而里面的设计思路是按照隔离思路写的,从CI复制过来,
而我的是直接引用CI的。这就造成了在module里使用$this->load->database()时会出现类重复的错误(前提是在使用module前的控制器或者模型里载入过database了)。

解决方法:删除MY_loader里的database方法,直接使用原始的loader里的方法。

在此做下标记解释备忘

本版积分规则