CodeIgniter框架源码笔记(3)——每次请求的总调度师傅:引导文件CodeIgniter.php
2016-07-08 10:42
766 查看
现在我们进入CI框架最重要的一环,引导文件
defined('BASEPATH') OR exit('No direct script access allowed');
此行在以后的每个系统文件中都会出现,防止客户端不通过入口,直接访问这些文件
我理解的CI工作流程如下:
一、设置版本号
define('CI_VERSION', '3.0.4');
二、加载常量
这样做主要为了快速设置特定环境下的特定常量。
三、加载全局函数库
require_once(BASEPATH.'core/Common.php');
四、如果低于php5.4版本,将进行全局变量安全处理
知识点:
1、PHP变量解析顺序:ini_get('variables_order'),同时也声明了接收哪种类型发送过来的变量;
当程序中使用了$_REQUEST接收变量,设置顺序EGPCS(Environment,GET,POST,Cookie,Server)就很重要,注意是从右向左覆盖。
php配置文件给出了配置提示
//Default Value: "EGPCS";
//Development Value: "GPCS";
//Production Value: "GPCS";
2、PHP 5.4.0 废除了register_globals,magic_quotes以及安全模式。因此这一段是专门针对PHP5.4之前的版本的。
3、当开启了register_globals,这就意味着EGPCS中的变量可以直接用变量名访问,这些全局变量是存储在$GLOBALS数组中的,这是个隐患,虽然5.4及之后消除了,但考虑兼容以前,需要手工清除这些全局变量。那么挑选了最重要的需要特别保护的一些变量名,也就是$_protected数组的值。凡是EGPCS中涉及到变量名称在$_protected数组中的,一律清空。
五、自定义错误、异常和程序完成的函数
1、设置错误处理:set_error_handler('_error_handler')。处理函数原型:function _error_handler($severity, $message, $filepath, $line)。程序本身原因或手工触发trigger_error("A custom error has been triggered");
2、设置异常处理:set_exception_handler('_exception_handler')。处理函数原型:function _exception_handler($exception)。当用户抛出异常时触发throw new Exception('Exception occurred');
3、千万不要被shutdown迷惑:register_shutdown_function('_shutdown_handler')
可以这样理解调用条件:当页面被用户强制停止时、当程序代码运行超时时、当php代码执行完成时。
六、如果index.php有硬编码的话,重新设置子类前缀
七、加载composer(单独开篇)
八、基准时间记录
$BM =& load_class('Benchmark', 'core');
$BM->mark('total_execution_time_start');
$BM->mark('loading_time:_base_classes_start');
九、加载核心类并实例化:这些都是核心类core里的文件
钩子类 $EXT =& load_class('Hooks', 'core');
配置类:$CFG =& load_class('Config', 'core'); 如果在index.php有手工设置的配置选项,也加载进来
utf8类:$UNI =& load_class('Utf8', 'core');
URL类:$URI =& load_class('URI', 'core');
路由类:$RTR =& load_class('Router', 'core', isset($routing) ? $routing : NULL);//$routing变量index.php可设置
重点说明:Router在实例化时,构造函数调用$this->_set_routing()进行路由设置[u]。实际上在这里生成$RTR时已经完成路由解析。[/u]
OUTPUT类:$OUT =& load_class('Output', 'core');
安全类:$SEC =& load_class('Security', 'core');
输入及过滤类:$IN =& load_class('Input', 'core');
语言类:$LANG =& load_class('Lang', 'core');
八、多字节字符支持常量设置
根据php扩展启用情况设置了MB_ENABLED,ICONV_ENABLED两个常量
多字节支持也是一个重要的话题,详见[KTOPIC]
九、重写系统组件的一些方法,包括: mbstring/ hash/password/ standard
十、缓存调用:
$EXT->call_hook('cache_override') === FALSE && $OUT->_display_cache($CFG, $URI) === TRUE
正常没有写cache_override这个构子方法,所以会去执行$OUT->_display_cache($CFG, $URI)。如果缓存命中则输出,并结束整个CI的单次生命周期。如果没有命中缓存,或没有启用缓存,那么将继续向下执行。
$OUT类是一个重要的核心类,负责了整个系统向浏览器终端呈现的内容输出,包括缓存的创建和过期删除
详细解析:[KTOPIC]
十一、加载Controller类:
require_once BASEPATH.'core/Controller.php';
function &get_instance();//创建实例化controller函数
require_once APPPATH.'core/'.$CFG->config['subclass_prefix'].'Controller.php'; //引入自定义扩展controller
十二、路由判断
1) 请求的class不存在:! class_exists($class)
2) 请求私有方法:!$method[0] === '_'
3) 请求基类方法:method_exists('CI_Controller', $method)
4)请求的方法不存在:! in_array(strtolower($method), array_map('strtolower', get_class_methods($class)), TRUE)
如果你的控制器中包含一个名为 _remap() 的方法,那么不管你的 URI 中包含什么,它总会被忽略掉。这个方法会废除掉由 URI片段来决定哪个方法被调用的规则,允许你重新定义调用方法的规则(方法的路由规则)。这个会有什么用处呢?其实用处有两个:
1,改变URL,隐藏方法,比如你的应用中,原来的URL方法是:
http://xxx.com/mall/display_successful_message
现在想改变显示的方法名为:
http://xxx.com/mall/successful
但显示虽然是successful,但实际上是调用存在的display_successful_message
方法,这就要用到_remap方法了。
2 还可以借这个函数做简单的函数方法控制,比如:
十三、404处理
这段主要看代码了:
十四、解析请求的类,并调用请求的方法
调用回调函数,并把一个数组参数作为回调函数的参数,call_user_func_array 函数和 call_user_func 很相似,只是 使 用了数组 的传递参数形式,让参数的结构更清晰。
十五、输出
if ($EXT->call_hook('display_override') === FALSE)
{
$OUT->_display();
}
至此,终于可以松一口气了。接下来放一幅粒度较小的流程图,并在随后开始分析这个负责呈现输出的Output类
defined('BASEPATH') OR exit('No direct script access allowed');
此行在以后的每个系统文件中都会出现,防止客户端不通过入口,直接访问这些文件
我理解的CI工作流程如下:
一、设置版本号
define('CI_VERSION', '3.0.4');
二、加载常量
if (file_exists(APPPATH.'config/'.ENVIRONMENT.'/constants.php')) { require_once(APPPATH.'config/'.ENVIRONMENT.'/constants.php'); } require_once(APPPATH.'config/constants.php');根据定义的环境,加载对应的环境目录下的常量,如果与系统常量冲突,最终以系统常量为准,所以环境常量无法覆盖系统常量。
这样做主要为了快速设置特定环境下的特定常量。
三、加载全局函数库
require_once(BASEPATH.'core/Common.php');
四、如果低于php5.4版本,将进行全局变量安全处理
知识点:
1、PHP变量解析顺序:ini_get('variables_order'),同时也声明了接收哪种类型发送过来的变量;
当程序中使用了$_REQUEST接收变量,设置顺序EGPCS(Environment,GET,POST,Cookie,Server)就很重要,注意是从右向左覆盖。
php配置文件给出了配置提示
//Default Value: "EGPCS";
//Development Value: "GPCS";
//Production Value: "GPCS";
2、PHP 5.4.0 废除了register_globals,magic_quotes以及安全模式。因此这一段是专门针对PHP5.4之前的版本的。
3、当开启了register_globals,这就意味着EGPCS中的变量可以直接用变量名访问,这些全局变量是存储在$GLOBALS数组中的,这是个隐患,虽然5.4及之后消除了,但考虑兼容以前,需要手工清除这些全局变量。那么挑选了最重要的需要特别保护的一些变量名,也就是$_protected数组的值。凡是EGPCS中涉及到变量名称在$_protected数组中的,一律清空。
$_protected = array('_SERVER','_GET','_POST','_FILES','_REQUEST', '_SESSION','_ENV','_COOKIE','GLOBALS','HTTP_RAW_POST_DATA','system_path', 'application_folder','view_folder','_protected','_registered' ); $_registered = ini_get('variables_order'); foreach (array('E' => '_ENV', 'G' => '_GET', 'P' => '_POST', 'C' => '_COOKIE', 'S' => '_SERVER') as $key => $superglobal) { if (strpos($_registered, $key) === FALSE) { continue; } foreach (array_keys($$superglobal) as $var) { if (isset($GLOBALS[$var]) && ! in_array($var, $_protected, TRUE)) { $globals[$var] = NULL; } } }
五、自定义错误、异常和程序完成的函数
set_error_handler('_error_handler'); set_exception_handler('_exception_handler'); register_shutdown_function('_shutdown_handler');知识点:
1、设置错误处理:set_error_handler('_error_handler')。处理函数原型:function _error_handler($severity, $message, $filepath, $line)。程序本身原因或手工触发trigger_error("A custom error has been triggered");
2、设置异常处理:set_exception_handler('_exception_handler')。处理函数原型:function _exception_handler($exception)。当用户抛出异常时触发throw new Exception('Exception occurred');
3、千万不要被shutdown迷惑:register_shutdown_function('_shutdown_handler')
可以这样理解调用条件:当页面被用户强制停止时、当程序代码运行超时时、当php代码执行完成时。
六、如果index.php有硬编码的话,重新设置子类前缀
七、加载composer(单独开篇)
八、基准时间记录
$BM =& load_class('Benchmark', 'core');
$BM->mark('total_execution_time_start');
$BM->mark('loading_time:_base_classes_start');
九、加载核心类并实例化:这些都是核心类core里的文件
钩子类 $EXT =& load_class('Hooks', 'core');
配置类:$CFG =& load_class('Config', 'core'); 如果在index.php有手工设置的配置选项,也加载进来
utf8类:$UNI =& load_class('Utf8', 'core');
URL类:$URI =& load_class('URI', 'core');
路由类:$RTR =& load_class('Router', 'core', isset($routing) ? $routing : NULL);//$routing变量index.php可设置
重点说明:Router在实例化时,构造函数调用$this->_set_routing()进行路由设置[u]。实际上在这里生成$RTR时已经完成路由解析。[/u]
OUTPUT类:$OUT =& load_class('Output', 'core');
安全类:$SEC =& load_class('Security', 'core');
输入及过滤类:$IN =& load_class('Input', 'core');
语言类:$LANG =& load_class('Lang', 'core');
八、多字节字符支持常量设置
根据php扩展启用情况设置了MB_ENABLED,ICONV_ENABLED两个常量
多字节支持也是一个重要的话题,详见[KTOPIC]
九、重写系统组件的一些方法,包括: mbstring/ hash/password/ standard
十、缓存调用:
$EXT->call_hook('cache_override') === FALSE && $OUT->_display_cache($CFG, $URI) === TRUE
正常没有写cache_override这个构子方法,所以会去执行$OUT->_display_cache($CFG, $URI)。如果缓存命中则输出,并结束整个CI的单次生命周期。如果没有命中缓存,或没有启用缓存,那么将继续向下执行。
$OUT类是一个重要的核心类,负责了整个系统向浏览器终端呈现的内容输出,包括缓存的创建和过期删除
详细解析:[KTOPIC]
十一、加载Controller类:
require_once BASEPATH.'core/Controller.php';
function &get_instance();//创建实例化controller函数
require_once APPPATH.'core/'.$CFG->config['subclass_prefix'].'Controller.php'; //引入自定义扩展controller
十二、路由判断
$e404 = FALSE; $class = ucfirst($RTR->class); $method = $RTR->method;CI认为下面这几种情况认为是404,如果找不到就调用show_404()函数:
1) 请求的class不存在:! class_exists($class)
2) 请求私有方法:!$method[0] === '_'
3) 请求基类方法:method_exists('CI_Controller', $method)
4)请求的方法不存在:! in_array(strtolower($method), array_map('strtolower', get_class_methods($class)), TRUE)
如果你的控制器中包含一个名为 _remap() 的方法,那么不管你的 URI 中包含什么,它总会被忽略掉。这个方法会废除掉由 URI片段来决定哪个方法被调用的规则,允许你重新定义调用方法的规则(方法的路由规则)。这个会有什么用处呢?其实用处有两个:
1,改变URL,隐藏方法,比如你的应用中,原来的URL方法是:
http://xxx.com/mall/display_successful_message
现在想改变显示的方法名为:
http://xxx.com/mall/successful
但显示虽然是successful,但实际上是调用存在的display_successful_message
方法,这就要用到_remap方法了。
2 还可以借这个函数做简单的函数方法控制,比如:
public function _remap($method, $params = array()){ $user_type = $_SESSION['user_type']; $access_control = $this->validate_access($user_type,$method); if ($access_control){ $this->$method(); } else{ $this->show_message(); } }
十三、404处理
这段主要看代码了:
if ($e404) { if ( ! empty($RTR->routes['404_override']))//如果在application/config/routes.php配置文件中设置了$route['404_override'],就按设置加载404页面 { if (sscanf($RTR->routes['404_override'], '%[^/]/%s', $error_class, $error_method) !== 2) { $error_method = 'index'; } $error_class = ucfirst($error_class); if ( ! class_exists($error_class, FALSE)) { if (file_exists(APPPATH.'controllers/'.$RTR->directory.$error_class.'.php')) { require_once(APPPATH.'controllers/'.$RTR->directory.$error_class.'.php'); $e404 = ! class_exists($error_class, FALSE); } // Were we in a directory? If so, check for a global override elseif ( ! empty($RTR->directory) && file_exists(APPPATH.'controllers/'.$error_class.'.php')) { require_once(APPPATH.'controllers/'.$error_class.'.php'); if (($e404 = ! class_exists($error_class, FALSE)) === FALSE) { $RTR->directory = ''; } } } else { $e404 = FALSE; } } // Did we reset the $e404 flag? If so, set the rsegments, starting from index 1 if ( ! $e404) { $class = $error_class; $method = $error_method; $URI->rsegments = array( 1 => $class, 2 => $method ); } else { show_404($RTR->directory.$class.'/'.$method);//默认情况下调用系统show_404函数进行显示 } }
十四、解析请求的类,并调用请求的方法
$CI = new $class(); call_user_func_array(array(&$CI, $method), $params);call_user_func_array
调用回调函数,并把一个数组参数作为回调函数的参数,call_user_func_array 函数和 call_user_func 很相似,只是 使 用了数组 的传递参数形式,让参数的结构更清晰。
十五、输出
if ($EXT->call_hook('display_override') === FALSE)
{
$OUT->_display();
}
至此,终于可以松一口气了。接下来放一幅粒度较小的流程图,并在随后开始分析这个负责呈现输出的Output类
相关文章推荐
- PHP中SESSION与COOKIE的区别与联系
- RTP协议全解析(H264码流和PS流)
- Parse error: syntax error
- andriod 获取剪贴板管理服务
- php 的aes加密
- laravel资源路由,控制器中的接收方式,详解
- mysql的mysqli异步与php的携程
- php 将网页执行的输出写入到本地文件中
- 使用phpexcel导出 数据
- 辨析php://input与$_POST
- PHP $_GET/$_POST提交
- php 二维数组根据某个字段排序
- php多进程pcntl学习(采集新浪微博)
- php文件上传
- 我的简单PHP框架——LabPHP v1.0.1
- Yii2.0MVC中的view笔记
- Ftp端口详解及修改
- layer2-STP_BPDU特性
- nfs,ftp,telnet区别
- Yii框架开发问题总结