• 一步一步重写 CodeIgniter 框架 (9) —— 使用 CodeIgniter 类库


    通过前面几节的内容,我们从零开始搭建了一个非常方便的MVC框架,理解了 CodeIgniter 框架最核心的部分。然而一个框架的便利不仅仅在于提供一个MVC就可以了,它还必须具有较高的扩展性。下面将从 CodeIgniter 的官方文档中的顺序一步一步充实我们这个“丑陋” 的框架。

    本课将实现 CodeIgniter 类库加载的模式,对应于http://codeigniter.org.cn/user_guide/general/libraries.html

    1. library 函数

    首先类库加载设计在 Loader 类中,函数命名为 library,如下所示

    public function library($library = '', $params = NULL, $object_name = NULL) {
    
            if (is_array($library)) {
    
                foreach ($library as $class) {
                    $this->library($class, $params);
                }
    
                return;
            }
    
            if ($library == '' OR isset($this->_base_classes[$library])) {
                return FALSE;
            }
    
            if ( ! is_null($params) && ! is_array($params)) {
                $params = NULL;
            }
    
            $this->_ci_load_class($library, $params, $object_name);
        }

    与 model 类似,它首先判断传入的第一个参数是否为数组,如果是的话,就递归调用一次。

    它通过调用 _ci_load_class 函数来实际加载具体的类。

     2. _ci_load_class 函数实际加载

    protected function _ci_load_class($class, $params = NULL, $object_name = NULL) {
    
            $class = str_replace('.php', '', trim($class, '/'));
    
            $subdir = '';
            if (($last_slash = strrpos($class, '/')) !== FALSE) {
    
                // 提取出路径
                $subdir = substr($class, 0, $last_slash + 1);
    
                // 提取出 class
                $class = substr($class, $last_slash + 1);
            }
    
            foreach (array(ucfirst($class), strtolower($class)) as $class) {
                $subclass = APPPATH.'libraries/'.$subdir.config_item('subclass_prefix').$class.'.php';
    
                // class 扩展
                if (file_exists($subclass)) {
                    $baseclass = BASEPATH.'libraries/'.ucfirst($class).'.php';
    
                    if ( ! file_exists($baseclass)) {
                        log_message('error', 'Unable to load the requested class: '.$class);
                        show_error('Unable to load the requested class: '.$class);
                    }
    
                    // 检查 class 是否加载过
                    if (in_array($subclass, $this->_ci_loaded_files)) {
                        if (! is_null($object_name)) {
                            $CI =& get_instance();
                            if ( ! isset($CI->$object_name)) {
                                return $this->_ci_init_class($class, config_item('subclass_prefix'), $params, $object_name);
                            }
                        }
    
                        $is_duplicate = TRUE;
                        log_message('debug', $class." class already loaded. Second attempt ignored.");
                        return;
    
                    }
    
                    include_once($baseclass);
                    include_once($subclass);
    
                    $this->_ci_loaded_files[] = $subclass;
    
                    return $this->_ci_init_class($class, config_item('subclass_prefix'), $params, $object_name);
                }
            }
    
            if ($is_duplicate == FALSE) {
                log_message('error', 'Unable to load the requested class: '.$class);
                show_error("Unable to load the requested class: ".$class);
            }
        }

    按照 CodeIgniter 的思路,首先会对加载函数的第一个参数路径进行拆分,得到具体的路径和文件名,因为文件名会有一些特殊的约定。

    CodeIgniter 在设计的时候有个很重要的思想,就是区分 system 和 application 两种类型的代码,从而设计出灵活性很高的框架,那么针对 类库 而言,就是在 system 中提供一些常用的类库,然后给用户在这个基础上扩展或覆盖的权利,另外,也可以直接在 

    application 文件夹下设计出完全自定义的类。

    本节主要实现 在原有类上进行扩展 的代码

    1) 首先判断 application 文件夹下是否存在按照约定命名的扩展类库文件,即 subclass_prefix = 'MY_', 就判断是否存在 MY_类库名.php 文件

    2)如果存在,则加载基类库文件,全部 include 之后,就可以 _ci_init_class 了

    3. _ci_init_class 实例化 class

    public function _ci_init_class($class, $prefix = '', $config = FALSE, $object_name = NULL) {
    
            if ($prefix == '') {
                $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);
    
            $classvar = $class;
    
            $CI =& get_instance();
            if ($config !== NULL) {
                $CI->$classvar = new $name($config);
            } else {
                $CI->$classvar = new $name;
            }
        }

    然后通过  

    $CI->$classvar = new $name($config);

    成为 CI 核心对象的成员,从而就可以很方便的访问了~ $this->email->函数名();
  • 相关阅读:
    20199106 2019-2020-2 《网络攻防实践》第三周作业
    Vulnhub
    NEEPU-CTF 2021 Web后四题Writeup
    Vulnhub
    [VNCTF 2021]naive题解
    F5杯 Web部分题目Writeup by atao
    CTFSHOW SSTI 刷题
    C语言文件
    函数+进制转换器
    C语言知识点小结
  • 原文地址:https://www.cnblogs.com/zhenyu-whu/p/3273670.html
Copyright © 2020-2023  润新知