zoukankan      html  css  js  c++  java
  • 一步一步重写 CodeIgniter 框架 (10) —— 使用 CodeIgniter 类库(续)

    上一节简单实现了 CI 的类库扩展模型,所以 _ci_load_class 和 _ci_init_class 写的不是很完备。根据上节课的分析,当 system/libraries 目录下存在 Email.php, 然后在 application/libraies 目录下存在 My_Email.php 时就可以实现扩展类库的功能。除了扩展之外,我们还需要:

    1)直接覆盖原始类

    2)完全自定义类

    很简单,按照约定,当不存在MY_开头的类库文件,加载类库的情况必定属于以上两种,如下所示

    // 直接加载代码
                $is_duplicate = FALSE;
                foreach ($this->_ci_library_paths as $path) {
                    $filepath = $path.'libraries/'.$subdir.$class.'.php';
    
                    if ( ! file_exists($filepath)) {
                        continue;
                    }
    
                    if (in_array($filepath, $this->_ci_loaded_files)) {
    
                        if ( ! is_null($object_name)) {
                            $CI =& get_instance();
                            if ( ! isset($CI->$object_name)) {
                                return $this->_ci_init_class($class, '', $params, $object_name);
                            }
                        }
    
                        $is_duplicate = TRUE;
                        log_message('debug', $class." class already loaded. Second attempt ignored.");
                        return;
                    }
    
                    include_once($filepath);
                    $this->_ci_loaded_files[] = $filepath;
                    return $this->_ci_init_class($class, '', $params, $object_name);
                }

    其中 _ci_libraries_path 在初始构造函数中初始化如下:

    $this->_ci_library_paths = array(APPPATH, BASEPATH);

    注意顺序,先是 APPPATH, 然后再是 BASEPATH, 保证加载的顺序先是 application ,再是 system。

    再来看一下 _ci_init_class 函数

    public function _ci_init_class($class, $prefix = '', $config = FALSE, $object_name = NULL) {
    
            if ($prefix == '') {
                if (class_exists('CI_'.$class)) {
                    $name = 'CI_'.$class;
                } elseif (class_exists(config_item('subclass_prefix').$class)) {
                    $name = config_item('subclass_prefix');
                } else {
                    $name = $class;
                }
            } else {
                $name = $prefix.$class;
            }
    
            if ( ! class_exists($name)) {
                log_message('error', "Non-existent class: ".$name);
                show_error("Non-existent class: ".$class);
            }
    
            $class = strtolower($class);
    
            // 这里对名字做了一个特殊的映射,针对 unit_test 就可以直接用 unit, 而非 unit_test
            if (is_null($object_name)) {
                $classvar = ( ! isset($this->_ci_varmap[$class])) ? $class : $this->_ci_varmap[$class];
            } else {
                $classvar = $object_name;
            }
    
            // 保存 class 名和对象名, 以供判断某个类库是否加载
            $this->_ci_classes[$class] = $classvar;
    
            $CI =& get_instance();
            if ($config !== NULL) {
                $CI->$classvar = new $name($config);
            } else {
                $CI->$classvar = new $name;
            }

    分析以上代码可以发现,为了直接覆盖原始的类库文件,对 $prefix ==‘’ 的情况作了进一步处理,判断是否存在 CI 或自定义MY_前缀的类,从而保证获得正确的类名。

    实例名也考虑到了一种特殊的情况,比如加载 unit_test 类的时候,直接使用 unit 作为变量,这也值得我们借鉴和考虑!!!也就是说,在考虑到一般的情况下,还可以做更灵活的处理,对类名较长的类直接通过配置的方式指定实例名,非常简洁~

    总结: 整个过程加载类库的设计就完成了,特别灵活和方便。

  • 相关阅读:
    iOS开发之直接使用UISearchBar
    iOS开发之cell多按钮
    Cocoapods报错xcrun: error: active developer path ("/Users/wangwei/Downloads/Xcode.app/Contents/Developer") does not exist
    lyl
    最全ASCLL码
    在子线程中使用runloop,正确操作NSTimer计时的注意点 三种可选方法
    ANSI escape code
    cocoa
    boundingRectWithSize:options:attributes:context:
    iOS 9 storyboard自动布局
  • 原文地址:https://www.cnblogs.com/zhenyu-whu/p/3284026.html
Copyright © 2011-2022 走看看