kohana分析之主程序加载流程
本文是要切入kohana的内部,分析其启动过程:
1.index.php
单一入口主文件,基本上是设置模块路径,全局变量等.如错误信息,系统模块路径,网站目录等.
其他工作转给 require SYSPATH.'core/Bootstrap'.EXT;完成。
值得提的是,如果我们想捕获整个程序的异常,那可以把他改成:
try{
require SYSPATH.'core/Bootstrap'.EXT;
}catch($e){
//处理错误,提示有好页面等等
}
2.Bootstrap.php
这个类用来加载一些必须的类库,初始化启动信息后,完成执行过程。并且记录部分流程的执行时间信息。
// Load benchmarking support
//这个类就是用于记录某个历程执行的时间,消耗的内存信息
require SYSPATH.'core/Benchmark'.EXT;
// Start total_execution 记录总执行时间
Benchmark::start(SYSTEM_BENCHMARK.'_total_execution');
// Start kohana_loading 记录加载类的时间
Benchmark::start(SYSTEM_BENCHMARK.'_kohana_loading');
// Load core files
require SYSPATH.'core/utf8'.EXT;
//event是在自己定义的一个事件里注册一些方法,一个事件可以叠加多个不同处理方法,然后通过Event::run来调用定义的事件
require SYSPATH.'core/Event'.EXT;
require SYSPATH.'core/Kohana'.EXT;
// Prepare the environment
Kohana::setup(); //初始化启动
// End kohana_loading //停止记录
Benchmark::stop(SYSTEM_BENCHMARK.'_kohana_loading');
// Start system_initialization
Benchmark::start(SYSTEM_BENCHMARK.'_system_initialization');
// Prepare the system
Event::run('system.ready');//如果有,则执行ready事件
// Determine routing
Event::run('system.routing');//执行路由事件
// End system_initialization
Benchmark::stop(SYSTEM_BENCHMARK.'_system_initialization');
// Make the magic happen!
Event::run('system.execute');//执行主代码过程
// Clean up and exit
Event::run('system.shutdown');//执行完毕后的处理操作
3.konana类,这是核心类,php执行核心操作都在此定义,在此完成初始化
Kohana::setup()
public static function setup()
{
static $run;
// This function can only be run once
if ($run === TRUE)
return;
// Start the environment setup benchmark
Benchmark::start(SYSTEM_BENCHMARK.'_environment_setup');
// Define Kohana error constant
define('E_KOHANA', 42);
// Define 404 error constant
define('E_PAGE_NOT_FOUND', 43);
// Define database error constant
define('E_DATABASE_ERROR', 44);
//缓存内部信息,包括所有配置文件数组(省去每次都要读文件),用到的类的所在路径(省去每次都要查找)
if (self::$cache_lifetime = self::config('core.internal_cache'))
{
// Are we using encryption for caches?
self::$internal_cache_encrypt = self::config('core.internal_cache_encrypt');
if(self::$internal_cache_encrypt===TRUE)
{
self::$internal_cache_key = self::config('core.internal_cache_key');
// Be sure the key is of acceptable length for the mcrypt algorithm used
self::$internal_cache_key = substr(self::$internal_cache_key, 0, 24);
}
// Set the directory to be used for the internal cache
if ( ! self::$internal_cache_path = self::config('core.internal_cache_path'))
{
self::$internal_cache_path = APPPATH.'cache/';
}
// Load cached configuration and language files
self::$internal_cache['configuration'] = self::cache('configuration', self::$cache_lifetime);
self::$internal_cache['language'] = self::cache('language', self::$cache_lifetime);
// Load cached file paths
self::$internal_cache['find_file_paths'] = self::cache('find_file_paths', self::$cache_lifetime);
// Enable cache saving
Event::add('system.shutdown', array(__CLASS__, 'internal_cache_save'));
}
// Disable notices and "strict" errors
$ER = error_reporting(~E_NOTICE & ~E_STRICT);
// Set the user agent
self::$user_agent = ( ! empty($_SERVER['HTTP_USER_AGENT']) ? trim($_SERVER['HTTP_USER_AGENT']) : '');
if (function_exists('date_default_timezone_set'))
{
$timezone = self::config('locale.timezone');
// Set default timezone, due to increased validation of date settings
// which cause massive amounts of E_NOTICEs to be generated in PHP 5.2+
date_default_timezone_set(empty($timezone) ? date_default_timezone_get() : $timezone);
}
// Restore error reporting
error_reporting($ER);//指定错误级别
// Start output buffering
//设置缓冲输出,加速总输出速度
ob_start(array(__CLASS__, 'output_buffer'));
// Save buffering level
//记录缓冲等级,便于控制缓存,清除的时候可以定位到哪个级别
self::$buffer_level = ob_get_level();
// Set autoloader
//自动加载类的方法,在include不存在的类的时候,调用这个方法查找,找不到则抛出异常
spl_autoload_register(array('Kohana', 'auto_load'));
// Set error handler
//自定义错误函数
set_error_handler(array('Kohana', 'exception_handler'));
// Set exception handler
//自定义异常处理函数
set_exception_handler(array('Kohana', 'exception_handler'));
// Send default text/html UTF-8 header
header('Content-Type: text/html; charset=UTF-8');
// Load locales
//获取设置的语言种类,array类型
$locales = self::config('locale.language');
// Make first locale UTF-8
$locales[0] .= '.UTF-8';
// Set locale information
//设置默认为第一种
self::$locale = setlocale(LC_ALL, $locales);
//日志记录级别如果>0则表示记录日志,1,2,3等级分别会记录不同范围的日志
if (self::$configuration['core']['log_threshold'] > 0)
{
// Set the log directory
self::log_directory(self::$configuration['core']['log_directory']);
// Enable log writing at shutdown
//在程序结束的时候,把内存中的$log一次性保存
register_shutdown_function(array(__CLASS__, 'log_save'));
}
//下面均是注册事件处理函数
// Enable Kohana routing
//分析出请求字符串如http://localhost:82/index.php/sy/pdtdetail/id/5/c/1
//则得到sy/pdtdetail/id/5/c/1
//find_uri 分不同模式下的处理操作
Event::add('system.routing', array('Router', 'find_uri'));
//此方法主要是获取controll和method,并调用System.post_routing 钩子,此钩子在用户类实例化前被执行
Event::add('system.routing', array('Router', 'setup'));
// Enable Kohana controller initialization
Event::add('system.execute', array('Kohana', 'instance'));
// Enable Kohana 404 pages
Event::add('system.404', array('Kohana', 'show_404'));
// Enable Kohana output handling
Event::add('system.shutdown', array('Kohana', 'shutdown'));
//如果开启,那加载自定义事件处理函数
if (self::config('core.enable_hooks') === TRUE)
{
// Find all the hook files
//找到所有定义事件的文件
$hooks = self::list_files('hooks', TRUE);
foreach ($hooks as $file)
{
// Load the hook
//直接把内容包含进来
include $file;
}
}
// Setup is complete, prevent it from being run again
$run = TRUE;//确保只执行一次
// Stop the environment setup routine
Benchmark::stop(SYSTEM_BENCHMARK.'_environment_setup');
}
回到Bootstap.php
剩下的就是Event.run了,调用各个处理程序,这些函数的注册过程参见kohana::setup();
// Prepare the system
// 如果有,则执行ready事件,默认为空,我们可以同过hook来注册函数
Event::run('system.ready');
// Determine routing
Event::run('system.routing');//执行路由事件
// End system_initialization
Benchmark::stop(SYSTEM_BENCHMARK.'_system_initialization');
// Make the magic happen!
Event::run('system.execute');//执行主代码过程
// Clean up and exit
Event::run('system.shutdown');//执行完毕后的处理操作
'system.routing'对应的注册方法有2个:Router.find_uri,Router.setup,作用在Kohana.setup里已经介绍过了,这里重点介绍
system.execute对应的函数是Kohana.instance,此方法的任务是创建唯一的控制器对象,调用控制器的方法,中间会调用一些钩子时间,方便我们想在某个环节做一些处理,还做了方法的私有化判断。
public static function & instance()
{
//确保只实例化一次controller
if (self::$instance === NULL)
{
Benchmark::start(SYSTEM_BENCHMARK.'_controller_setup');
// Include the Controller file
require Router::$controller_path;
//包含contrller的源文件
try
{
// Start validation of the controller
//用此类来初始化controller的好处是可以知道该类定义的方法和属性等信息
$class = new ReflectionClass(ucfirst(Router::$controller).'_Controller');
}
catch (ReflectionException $e)
{
// Controller does not exist
Event::run('system.404');
}
if ($class->isAbstract() OR (IN_PRODUCTION AND $class->getConstant('ALLOW_PRODUCTION') == FALSE))
{
// Controller is not allowed to run in production
Event::run('system.404');
}
// Run system.pre_controller
//创建构造函数前的钩子
Event::run('system.pre_controller');
// Create a new controller instance
//实例化controller
$controller = $class->newInstance();
// Controller constructor has been executed
//实例建立完毕后,但未调用方法状态,调用钩子
Event::run('system.post_controller_constructor');
try
{
// Load the controller method
//判断是否有该方法
$method = $class->getMethod(Router::$method);
// Method exists
//这里Konhan把 _ 开头的方法视为私有方法
if (Router::$method[0] === '_')
{
// Do not allow access to hidden methods
Event::run('system.404');
}
//判断方法本身是否有限制
if ($method->isProtected() or $method->isPrivate())
{
// Do not attempt to invoke protected methods
throw new ReflectionException('protected controller method');
}
// Default arguments
$arguments = Router::$arguments;
}
catch (ReflectionException $e)
{
// Use __call instead
$method = $class->getMethod('__call');
// Use arguments in __call format
$arguments = array(Router::$method, Router::$arguments);
}
// Stop the controller setup benchmark
Benchmark::stop(SYSTEM_BENCHMARK.'_controller_setup');
// Start the controller execution benchmark
Benchmark::start(SYSTEM_BENCHMARK.'_controller_execution');
// Execute the controller method
//这里开始执行控制器的方法了
$method->invokeArgs($controller, $arguments);
// Controller method has been executed
//执行后的事件钩子
Event::run('system.post_controller');
// Stop the controller execution benchmark
Benchmark::stop(SYSTEM_BENCHMARK.'_controller_execution');
}
//返回唯一的实例
return self::$instance;
}
回到Bootsarp.php,之后执行的是Event::run('system.shutdown');调用的是Kohana.shutdown,做一些清理工作:刷新缓冲,再把缓冲里面的数据进行全局替换.
public static function shutdown()
{
// Close output buffers
//把缓冲里的数据写到self::$output里面
self::close_buffers(TRUE);
// Run the output event
//调用处理输出缓冲的事件
Event::run('system.display', self::$output);
// Render the final output
//全部变量替换,压缩处理
self::render(self::$output);
}
ob函数是php内部缓冲处理模块:
function out($a){
global $html;
$html = '<div style="color:red">'.$a.'</div>';//file_put_contents('c:/2.txt',$a);die;
return $html;
}
//开启缓冲,并且设置缓冲函数为out
ob_start('out');
未完待续