解析CI源码
先上图
用户发起请求,当请求触达index.php时,开始初始化;
1. 设置环境常量
define('ENVIRONMENT', isset($_SERVER['CI_ENV']) ? $_SERVER['CI_ENV'] : 'development');
// 根据该常量,加载不同的配,设置不同的报错级别
// 先判断$_SERVER['CI_ENV'](可以在php.ini中指定)是否存在。
// 如果存在ENVIRONMENT就是$_SERVER['CI_ENV']的值;
// 如果不存在ENVIRONMENT就是'development'。
2. 设置报错级别
php提供了16种报错级别,我们先来复习一下,报错级别吧
E_ERROR 1 致命运行错误,比如调用了未定义的函数,脚本停止运行
E_WARNING 2 警告运行错误,脚本不停止运行
E_PARSE 4 脚本解析错误,比如少个分号,逗号之类,脚本停止运行
E_NOTICE 8 通知运行错误,比如echo一个未定义的变量,脚本不停止运行
E_CORE_ERROR 16 致命初始化错误,由PHP引擎核心抛出
E_CORE_WARNING 32 警告初始化错误,由PHP引擎核心抛出
E_COMPILE_ERROR 64 致命编译时错误,由zend脚本抛出
E_COMPILE_WARNING 128 警告编译时错误,由zend脚本抛出
E_USER_ERROR 256 致命用户产生错误,用户自己使用trigger_error()产生
E_USER_WARNING 512 警告用户产生错误,用户自己使用trigger_error()产生
E_USER_NOTICE 1024 通知用户产生错误,用户自己使用trigger_error()产生
E_STRICT 2048 启用严格模式,对代码会有修改建议
E_RECOVERABLE_ERROR 4096 可被捕捉的致命错误,可以被set_error_hander定义的句柄捕获,如果没有定义该句柄,则升级为E_ERROR
E_DEPRECATED 8192 一种特殊的E_NOTICE,专门用来提示预备启用的函数
E_USER_DEPRECATED 16384 用户自己产生的E_DEPRECATED,用户自己使用trigger_error()产生
E_ALL 30719 会抛出,除 E_STRICT之外的所有错误和警告信息
源码:
switch (ENVIRONMENT)
{
case 'development':
error_reporting(-1); // -1等同于 E_ALL | 0表示关闭所有报错
// error_reporting(7); 表示显示 E_ERROR(1) | E_WARING(2) | E_PARSE(4) == (1+2+4)
ini_set('display_errors', 1); // ini_set运行时改变 php.ini配置。display_errors 配置为1表示显示博按错,为0表示不显示报错
break;
case 'testing':
case 'production':
ini_set('display_errors', 0); // 0表示不显示报错
if (version_compare(PHP_VERSION, '5.3', '>=')) // PHP_VERSION是php的一个宏定义,存储了当前运行的php版本。version_compare用来比对版本,返回true或false
{
error_reporting(E_ALL & ~E_NOTICE & ~E_DEPRECATED & ~E_STRICT & ~E_USER_NOTICE & ~E_USER_DEPRECATED);
// 表示 E_ALL 但除E_NOTICE、E_DEPRECATED、E_STRICT、E_USER_NOTICE、E_USER_DEPRECATED 之外的报错
}
else
{
error_reporting(E_ALL & ~E_NOTICE & ~E_STRICT & ~E_USER_NOTICE);
// 表示 E_ALL 但除E_NOTICE、E_STRICT 、E_USER_NOTICE 之外的报错
}
break;
default:
// 503报错,环境必须配置为development、testing、production中的一种,否则报错
header('HTTP/1.1 503 Service Unavailable.', TRUE, 503);
echo 'The application environment is not set correctly.';
exit(1); // EXIT_ERROR
}
3. 设置系统目录
$system_path = 'system'; // 设置ci核心源码存放目录
$application_folder = 'application'; // 设置用户自定义应用存放目录
$view_folder = ''; // 用户特殊指定的view目录,未指定则默认是 application/views
// 兼容命令行模式
if (defined('STDIN')) // 是否定义了PHP CLI模式下的标准输入 STDIN、STDOUT、STDERR 分别是PHP CLI模式下的标准输入、标准输出和标准错误流
{
chdir(dirname(__FILE__)); // 把php CLI脚本的运行目录,指定为当前目录
}
if (($_temp = realpath($system_path)) !== FALSE) // realpath返回变量的绝对路径
{
$system_path = $_temp.DIRECTORY_SEPARATOR;
// DIRECTORY_SEPARATOR为目录分隔符及'/'
// 将system_path设置为绝对路径
}
else
{
// 确保绝对路径正确
// 假设当前为linux环境,这里的'/\\'表示 linux文件分隔符(/) windows文件分隔符(\)
$system_path = strtr(
rtrim($system_path, '/\\'),// 代码的意思是$system_path 从右往左看,将所有出现的/或\删除,直到遇见不为/或\的字符时停止。
'/\\', // strtr 会同时匹配 /\ 、 / 、 \ 三种情况
DIRECTORY_SEPARATOR.DIRECTORY_SEPARATOR // 不仅会替换 /\为 //,还会替换\为/
).DIRECTORY_SEPARATOR; // 最后连接字符 '/'
}
// Is the system path correct?
if ( ! is_dir($system_path))
{
// 报503,路径不存在
header('HTTP/1.1 503 Service Unavailable.', TRUE, 503);
echo 'Your system folder path does not appear to be set correctly. Please open the following file and correct this: '.pathinfo(__FILE__, PATHINFO_BASENAME);
exit(3); // EXIT_CONFIG
}
4.设置应用文件目录
// 定义SELF常量为,当前文件名
define('SELF', pathinfo(__FILE__, PATHINFO_BASENAME));
// 定义BASEPATH常量为,系统文件的目录
define('BASEPATH', $system_path);
// Path to the front controller (this file) directory
define('FCPATH', dirname(__FILE__).DIRECTORY_SEPARATOR); // 定义FCPATH常量为,这个当前文件的目录
// 定义SYSDIR常量为,系统文件的名字
define('SYSDIR', basename(BASEPATH));
// 指定application的目录
if (is_dir($application_folder))
// 还记得前面定义的$application_folder吗? 这里是检查$application_folder变量,是否符合目录格式
{
if (($_temp = realpath($application_folder)) !== FALSE) // 与system相同
{
$application_folder = $_temp;
}
else
{
$application_folder = strtr(
rtrim($application_folder, '/\\'),
'/\\',
DIRECTORY_SEPARATOR.DIRECTORY_SEPARATOR
);
}
}
elseif (is_dir(BASEPATH.$application_folder.DIRECTORY_SEPARATOR))
// 如果$application_folder不符合目录格式,则判断 $system_path.$application_folder.DIRECTORY_SEPARATOR 是否符合目录格式
{
$application_folder = BASEPATH.strtr( // 取$system_path作为application的目录
trim($application_folder, '/\\'),
'/\\',
DIRECTORY_SEPARATOR.DIRECTORY_SEPARATOR
);
}
else
{
// 文件不存在
header('HTTP/1.1 503 Service Unavailable.', TRUE, 503);
echo 'Your application folder path does not appear to be set correctly. Please open the following file and correct this: '.SELF;
exit(3); // EXIT_CONFIG
}
define('APPPATH', $application_folder.DIRECTORY_SEPARATOR); // 定义常量APPPATH为,应用目录
4.设置视图层目录
// The path to the "views" directory
if ( ! isset($view_folder[0]) && is_dir(APPPATH.'views'.DIRECTORY_SEPARATOR))
// view_folder是否不为数组
{
$view_folder = APPPATH.'views';
}
elseif (is_dir($view_folder)) //$view_folder也可以配置为一个相对目录
{
if (($_temp = realpath($view_folder)) !== FALSE)
{
$view_folder = $_temp;
}
else
{
$view_folder = strtr(
rtrim($view_folder, '/\\'),
'/\\',
DIRECTORY_SEPARATOR.DIRECTORY_SEPARATOR
);
}
}
elseif (is_dir(APPPATH.$view_folder.DIRECTORY_SEPARATOR))
{
$view_folder = APPPATH.strtr(
trim($view_folder, '/\\'),
'/\\',
DIRECTORY_SEPARATOR.DIRECTORY_SEPARATOR
);
}
else
{
header('HTTP/1.1 503 Service Unavailable.', TRUE, 503);
echo 'Your view folder path does not appear to be set correctly. Please open the following file and correct this: '.SELF;
exit(3); // EXIT_CONFIG
}
define('VIEWPATH', $view_folder.DIRECTORY_SEPARATOR); // 定义视图文件常量
5.执行引导程序
require_once BASEPATH.'core/CodeIgniter.php'; // 运行system文件中的引导程序