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

[中级] CodeIgniter2.1.0源码阅读(20120427更新)

    [复制链接]
发表于 2012-3-29 17:47:02 | 显示全部楼层 |阅读模式
本帖最后由 actionbi 于 2012-4-27 18:26 编辑

初读Codeigniter代码,想探探高效框架的究竟。

感谢Hex给了个精华。

文章的结构修改为全部按照程序的执行顺序,按行读取。差不多相当于是给代码加注吧。
初读代码可能有很大的出入或者想不到的地方,这也是我发到论坛来的目的。希望大家给我指正。
mailto: actionbi2010@gmail.com 我会及时修正!

文件已楼层的形式发布,顶楼不写内容,只加链接。期待和大家交流。

评分

参与人数 6威望 +28 收起 理由
恶魔的果实 + 5 很给力,感谢!
dllhb + 5 很给力!
E.TAXI + 3 感谢奉献
东城︶ㄣLee + 5
屠城 + 5 很给力!真是需要,社区需要这种无私奉献的.

查看全部评分

 楼主| 发表于 2012-3-29 17:47:58 | 显示全部楼层

CodeIgniter2.1.0源码阅读(5)URL.php url处理类

本帖最后由 actionbi 于 2012-3-30 02:33 编辑

在CodeIgniter.php中,第165行加载了URL类。目的是为了进行url的处理,类CI_URL也是个全局加载的类库,可以直接使用。

参数介绍:
        $keyval = array();             //缓存的uri片段
       
        var $uri_string;         
        /*
         * 获取到的当前的URI的字符串     
         * 当你的URl为localhost/CodeIgniter/index.php?/welcome/index/var/4时
         * $uri_string = welcome/index/var/4
         */                        
        var $segments                = array();  //URI片段数组 数组键值从0开始

        var $rsegments                = array(); //重建索引的片段数组  数组键值从1开始


   附录:
                   url类中ci判断php的运行环境
       CodeIgniter源码阅读URI.php中_fetch_uri_string()函数的解析
         
PHP复制代码
 
<?php
               
class CI_URI {
 
        var $keyval             = array();
       
        var $uri_string;        
        /*
         * 获取到的当前的URI的字符串    
         * 当你的URl为localhost/CodeIgniter/index.php?/welcome/index/var/4时
         * $uri_string = welcome/index/var/4
         */
                       
        var $segments           = array();  //URI片段数组 数组键值从0开始
 
        var $rsegments          = array(); //重建索引的片段数组  数组键值从1开始
       
        function __construct(){
                        $this->config =& load_class('Config', 'core');
                        log_message('debug', "URI Class Initialized");              
         //加载了core/Config.php 也就是Config类,需要获取config文件中的设置
                }
 
 
        function _fetch_uri_string(){}//获取uri_sting  详细见附录
 
 
        function _set_uri_string($str){
                        //过滤url中的不可见的字符
                        $str = remove_invisible_characters($str, FALSE);
       
                        // If the URI contains only a slash we'll kill it
                        $this->uri_string = ($str == '/') ? '' : $str;
                }
        private function _detect_uri(){
                        //检测uri,经过此函数检测的uri将传送到_set_uri_string($str)
                }
        private function _parse_cli_args(){
                        $args = array_slice($_SERVER['argv'], 1);
                        return $args ? '/' . implode('/', $args) : '';
                }
        function _filter_uri($str){
                        //过滤url的参数
                        //过滤规则为 |^[a-z 0-9~%\.\:_\-]+$|i  当uri的参数不符合条件时会报错
                        $bad    = array('$',            '(',            ')',            '%28',          '%29');
                    $good       = array('&#36;',        '&#40;',        '&#41;',        '&#40;',        '&#41;');
                }
        function _remove_url_suffix(){
                        //取出uri的后缀
                }
        function _explode_segments(){
                        //将$this->uri_string 分割到数组中
                        //期间分割字符串要使用到_filter_uri($str)
                }
        function _reindex_segments(){
                        //为segements 重建索引
                }
        function segment($n, $no_result = FALSE){
                        //获取uri的一个 片段
                        return ( ! isset($this->segments[$n])) ? $no_result : $this->segments[$n];
                }
        function rsegment($n, $no_result = FALSE){
                        //获取uri的一个片段
                        return ( ! isset($this->rsegments[$n])) ? $no_result : $this->rsegments[$n];
                }
        function uri_to_assoc($n = 3, $default = array()){
                        return $this->_uri_to_assoc($n, $default, 'segment');
                }
        function ruri_to_assoc($n = 3, $default = array()){
                        return $this->_uri_to_assoc($n, $default, 'rsegment');
                }
        function _uri_to_assoc($n = 3, $default = array(), $which = 'segment'){
                 //uri片段转换成一个关联数组,据说是做cache,但是有点苦,函数懂了,但是用法不知
                }
        function assoc_to_uri($array){
                //将uri片段的关联数组转换成uri
                }
        function slash_segment($n, $where = 'trailing'){
                        return $this->_slash_segment($n, $where, 'segment');
                }
        function slash_rsegment($n, $where = 'trailing'){
                        return $this->_slash_segment($n, $where, 'rsegment');
                }
        function _slash_segment($n, $where = 'trailing', $which = 'segment'){
                       
                }
        function segment_array(){
                        return $this->segments;
                        //返回uri片段数组
                }
        function rsegment_array(){
                        return $this->rsegments;
                        //返回中间索引后uri片段数组
                }
        function total_segments(){
                        return count($this->segments);
                        //返回uri片段数
                }
        function total_rsegments(){
                        return count($this->rsegments);
                }
        function uri_string(){
                        return $this->uri_string;
                        //获取当前的uri字符串
                }
        function ruri_string(){
                        return '/'.implode('/', $this->rsegment_array());
                }
}
 
?>
 
复制代码
 楼主| 发表于 2012-3-29 17:48:13 | 显示全部楼层

url类中ci判断php的运行环境

本帖最后由 actionbi 于 2012-3-30 02:27 编辑

    阅读ci代码过程中发现,处理URI会根据php的运行环境进行不同处理。

    那么如何判断php的运行环境呢?

     我们一般情况下,都是在apache下面运行我们的php程序,当然也有些人是用IIS环境的
我们要是想知道我们目前运行的环境是什么的话,那我们可以用函数php_sapi_name()来测试
代码:


PHP复制代码
 
<?php
 
echo php_sapi_name();
 
?>
 
复制代码


在apache环境下面输出的结果是“apache2handler”;
在cgi模式下输出的结果是“cgi-fcgi”
要是在命令行模式下面运行的话,那么输出的结果是:”cli”
依据这个内容我们可以判断当前运行的环境是什么!
那么在命令行下怎么运行呢?
如下:
进入DOS 进入php.exe文件的地址 如我的是:d:/wamp/bin/php/php5.3.3/
然后输入php.exe “文件的绝对路径” 如:>php.exe d:/wamp/www/info.php
既可以了。
发表于 2012-3-29 21:57:42 | 显示全部楼层
CI的分页不好用,么有thinkPHP的引用起来容易。而且到2.1了貌似还没有总页数的设计,要自己扩展吗?
 楼主| 发表于 2012-3-30 02:32:55 | 显示全部楼层

CodeIgniter源码阅读URI.php中_fetch_uri_string()函数的解析

本帖最后由 actionbi 于 2012-3-30 13:36 编辑

APPPATH/config/config.php中对于url 格式的拟定。
$config['uri_protocol'] = 'AUTO';

这个配置项目定义了你使用哪个服务器全局变量来拟定URL。
默认的设置是auto,会把下列四个方式轮询一遍。当你的链接不能工作的时候,试着用用auto外的选项。

'AUTO'                         Default -   auto detects
'PATH_INFO'                Uses the PATH_INFO
'QUERY_STRING'         Uses the QUERY_STRING
'REQUEST_URI'           Uses the REQUEST_URI
'ORIG_PATH_INFO'      Uses the ORIG_PATH_INFO

CI_URI中的几个成员变量
PHP复制代码
 
$keyval = array();            //List of cached uri segments
$uri_string;                      //Current uri string
$segments                      //List of uri segments
$rsegments = array()       //Re-indexed list of uri segments
复制代码


获取到的current uri string 赋值到 $uri_string ,通过function _set_uri_string($str)。


获取到$str有几个选项,也就是_fetch_uri_string()的业务流程部分了

一、默认$config['uri_protocol'] = 'AUTO'时,程序会一次轮询下列方式来获取URI

(1)当程序在CLI下运行时,也就是在命令行下php文件时候。ci会这么获取URI

private function _parse_cli_args()
        {
            $args = array_slice($_SERVER['argv'], 1);
            return $args ? '/' . implode('/', $args) : '';
        }

//$_SERVER['argv'] 包含了传递给脚本的参数 当脚本运行在CLI时候,会给出c格式的命令行参数
截取到$_SERVER['argv']中除了第一个之外的所有参数

如果你在命令行中这么操作

php d:/wamp/www/CodeIgniter/index.php welcome index

_parse_cli_args() 返回一个 /welcome/index的字符串


(2)默认使用REQUEST_URI来探测url时候会调用 私有函数 _detect_uri()

(3)如果上面的两种方式都不能获取到uri那么会采用$_SERVER[‘PATH_INFO’]来获取
PHP复制代码
 
$path = (isset($_SERVER['PATH_INFO'])) ? $_SERVER['PATH_INFO'] : @getenv('PATH_INFO');                        if (trim($path, '/') != '' && $path != "/".SELF)                        {                                $this->_set_uri_string($path);                                return;                        }
复制代码

(4)如果上面三种方式都不能获取到,那么就使用$_SERVER[‘QUERY_STRING’]或者getenv[‘QUERY_STRING’]
PHP复制代码
 
$path =  (isset($_SERVER['QUERY_STRING'])) ? $_SERVER['QUERY_STRING'] : @getenv('QUERY_STRING');   if (trim($path, '/') != '')   {    $this->_set_uri_string($path);    return;   }
复制代码

  (5)上面四种方法都不能获取到URI,那么就要使用$_GET数组了,没招了
PHP复制代码
 
if (is_array($_GET) && count($_GET) == 1 && trim(key($_GET), '/') != '')                        {                                $this->_set_uri_string(key($_GET));                                return;                        }
复制代码

二、在config.php中设定了$config['uri_protocol'] ,那么 程序会自动执行相应的操作来获取uri

发表于 2012-3-30 13:27:03 | 显示全部楼层
_parse_cli_args() 返回一个 /index.php/start/index的字符串

实际返回的是
/start/index
 楼主| 发表于 2012-3-30 13:38:04 | 显示全部楼层
大道达人 发表于 2012-3-30 13:27
_parse_cli_args() 返回一个 /index.php/start/index的字符串

实际返回的是

嗯,是的,我修正了。谢谢您指正
 楼主| 发表于 2012-3-30 15:15:42 | 显示全部楼层

CodeIgniter源码阅读(6)Hook.php 钩子-扩展框架的核心

看了hook.php的源码,就知道CI使用hook来进行扩展的原理了。

hook的基本知识http://codeigniter.org.cn/user_guide/general/hooks.html

CI中hook的使用经历了一个:开启hook,定义hook,调用hook,执行hook的过程。

手册中已经告知了开启、定义、调用的方法。那么hook的实现原理是啥呢。
PHP复制代码
 
<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');
class CI_Hooks {
        var $enabled            = FALSE;
 //开启hook的标志,默认是关闭的。APPPATH/config/config.php中的配置也是默认关闭的,如果想使用hook,要在config.php中开启。
        var $hooks                      = array();
//在_initialize()函数初始化的过程中将APPPATH/config/hook.php中定义的hook数组,引用到$this->hooks;
        var $in_progress        = FALSE;
//当一个hook执行的时候,会给标记 $in_process = TRUE ,是为了防止同一个hook被同时调用。
        function __construct()
        {
                $this->_initialize();
                log_message('debug', "Hooks Class Initialized");
        }
        function _initialize()
        {
                //初始化hook
                //判断config.php中是否开启hook
                //include(hook.php),将文件里定义的hook数组引用到$this->hooks
                //$this->enable = TRUE
        }
 
        function _call_hook($which = '')//pre_system
        {
                //以pre_system挂钩点为例,当调用_call_hook('pre_system')时
                //确保$this->enable = TRUE && 定义了$this->hooks['pre_system']
                //如果是二维数组就遍历,依次_run_hook($this->hooks['pre_system'][$val])
                //如果是一维数组,那么直接_run_hook($this->hooks['pre_system'])
        }
 
        function _run_hook($data) //$data 是传递过来的hook数组
        {
                //$data 就是我们在APPPATH/config/hook.php 定义的hook数组
                //$hook['pre_controller'] = array(
                //               'class'    => 'MyClass',
                //                'function' => 'Myfunction',
                //               'filename' => 'Myclass.php',
                //                'filepath' => 'hooks',
                //                'params'   => array('beer', 'wine', 'snacks')
                //                );
               
                取出data里面的数据,加载  APPPATH.$data['filepath'].$data['filename'];
                实例化钩子类,调用function。应用到示例中就是
                $this->in_process = TRUE;
                $Hook = new  MyClass();
                $Hook->Myfunction($params);
                $this->in_process = FALSE;
        }
 
}
?>
 
复制代码

挂钩点可以挂多个hook,所以,当我们想扩展ci的时候,只需要将hook文件放到APPPATH文件夹下,然后
到APPPATH/config/hook.php中声明定义的hook的信息即可。那么系统运行到挂钩点的时候,会自动调用声明的hook。
如此一来便实现了可扩展性

评分

参与人数 1威望 +5 收起 理由
justdoit + 5 赞一个!

查看全部评分

发表于 2012-3-30 17:00:05 | 显示全部楼层
顶一个!
 楼主| 发表于 2012-3-31 18:51:09 | 显示全部楼层

CodeIgniter.php第51-66行 加载constans.php系统常量

本帖最后由 actionbi 于 2012-3-31 19:05 编辑

代码用于处理加载系统define的常量。主要是一些预定义的权限。程序中可以直接使用。

命名很直观,所以不解释。
PHP复制代码
 
define('FILE_READ_MODE', 0644);
define('FILE_WRITE_MODE', 0666);
define('DIR_READ_MODE', 0755);
define('DIR_WRITE_MODE', 0777);
define('FOPEN_READ',                                                        'rb');
define('FOPEN_READ_WRITE',                                                'r+b');
define('FOPEN_WRITE_CREATE_DESTRUCTIVE',                'wb'); // truncates existing file data, use with care
define('FOPEN_READ_WRITE_CREATE_DESTRUCTIVE',        'w+b'); // truncates existing file data, use with care
define('FOPEN_WRITE_CREATE',                                        'ab');
define('FOPEN_READ_WRITE_CREATE',                                'a+b');
define('FOPEN_WRITE_CREATE_STRICT',                                'xb');
define('FOPEN_READ_WRITE_CREATE_STRICT',                'x+b');
 
复制代码

评分

参与人数 1威望 +2 收起 理由
cowa + 2 很给力!

查看全部评分

本版积分规则