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');

 

 

未完待续

 

 

posted @ 2012-03-13 15:32  you_yang  阅读(1691)  评论(0编辑  收藏  举报