ThinkPHP3.2.3源码分析一之系统流程

ThinkPHP3.2.3源码分析一之系统流程

整体流程

红色的时钩子,蓝色为配置文件或函数定义文件

这里写图片描述

一 初始化

主要文件加载

\thinkphp_3.2.3\index.php 
\thinkphp_3.2.3\ThinkPHP\ThinkPHP.php 
\thinkphp_3.2.3\ThinkPHP\Library\Think\Think.class.php 
\thinkphp_3.2.3\ThinkPHP\Library\Think\Storage.class.php 
\thinkphp_3.2.3\ThinkPHP\Library\Think\Storage\Driver\File.class.php

简单流程

\index.php
// 检测PHP环境
if(version_compare(PHP_VERSION,'5.3.0','<'))  die('require PHP > 5.3.0 !');

// 开启调试模式 建议开发阶段开启 部署阶段注释或者设为falseW
define('APP_DEBUG',True);

// 定义应用目录
define('APP_PATH','./Application/');

// 引入ThinkPHP入口文件
require './ThinkPHP/ThinkPHP.php';
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
\ThinkPHP\ThinkPHP.php
// 记录开始运行时间
$GLOBALS['_beginTime'] = microtime(TRUE);

// 记录内存初始使用
define('MEMORY_LIMIT_ON',function_exists('memory_get_usage'));
if(MEMORY_LIMIT_ON) $GLOBALS['_startUseMems'] = memory_get_usage();

// 系统常量定义
defined('THINK_PATH')   or define('THINK_PATH',     __DIR__.'/');
defined('APP_PATH')     or define('APP_PATH',       dirname($_SERVER['SCRIPT_FILENAME']).'/');
defined('APP_STATUS')   or define('APP_STATUS',     ''); // 应用状态 加载对应的配置文件
defined('APP_DEBUG')    or define('APP_DEBUG',      false); // 是否调试模式

///  用宏定义define定义大量的系统状态和系统路径
/// 判断操作系统,php版本,运行方式(cgi,sapi)来特殊处理常量定义

// 加载核心Think类
require CORE_PATH.'Think'.EXT;
// 应用初始化 
Think\Think::start();
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
\ThinkPHP\Library\Think\Think.class.php
static public function start() {
      // 注册AUTOLOAD方法
      // 主要时去系统目录找类文件,或从应用配置文件注册的命名空间路径找
      // array('Think','Org','Behavior','Com','Vendor')
      // C('AUTOLOAD_NAMESPACE');
      // 兼容处理不开命名空间的项目
      spl_autoload_register('Think\Think::autoload');

      // 设定系统错误和异常处理函数注册

      // 脚本正常结束或者手动或异常终结处理
      // 处理: 1.内存中的日志落地到文件 2.如果是异常终止,则输出错误
      register_shutdown_function('Think\Think::fatalError');

      //系统致命错误处理
      //级别_USER_ERROR的写日志,页面输出提示
      //低级别WARN NOTICE 等输出PageTrace,不影响脚本
      set_error_handler('Think\Think::appError');

      //系统抛出异常处理
      //写日志,页面输出
      set_exception_handler('Think\Think::appException');

      // 初始化文件存储方式
      Storage::connect(STORAGE_TYPE);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
\ThinkPHP\Library\Think\Storage.class.php
\ThinkPHP\Library\Think\Storage\Driver\File.class.php (or Sae)
//此处文件缓存类,兼容本地缓存和sae的分布式文件环境。

class Storage {

    /**
     * 操作句柄
     * @var string
     * @access protected
     */
    static protected $handler    ;

    /**
     * 连接分布式文件系统
     * @access public
     * @param string $type 文件类型
     * @param array $options  配置数组
     * @return void
     */
    static public function connect($type='File',$options=array()) {
        $class  =   'Think\\Storage\\Driver\\'.ucwords($type);
        self::$handler = new $class($options);
    }

    static public function __callstatic($method,$args){
        / 魔术方法 调用文件缓存驱动类的方法
        //调用缓存驱动的方法
        if(method_exists(self::$handler, $method)){
           return call_user_func_array(array(self::$handler,$method), $args);
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31

二 应用模式的编译缓存和配置文件加载

主要文件加载

\thinkphp_3.2.3\ThinkPHP\Mode\common.php 
\thinkphp_3.2.3\ThinkPHP\Common\functions.php 
\thinkphp_3.2.3\ThinkPHP\Library\Think\Hook.class.php

简单流程

\ThinkPHP\Library\Think\Think.class.php
$runtimefile  = RUNTIME_PATH.APP_MODE.'~runtime.php';
        // 部署模式并且已缓存的情况下,直接load编译缓存文件,此处的load实质是include文件
      if(!APP_DEBUG && Storage::has($runtimefile)){
          Storage::load($runtimefile);
      }else{
          // debug模式或无缓存文件时
          // 1.清理可能存在的过期缓存文件
          // 2. 加载一堆配置文件,语言包(这里的配置加载到内寸中,一般是存在全局函数作用域的静态变量,或者在类的静态成员变量中)
          // 3. 部署模式下,缓存起应用编译文件(编译过程,去掉注释空白,替换预编译的字符串, 写入导入配置的代码段)
          // 4 debug模式下,导入debug对应的系统配置,应用配置

          if(Storage::has($runtimefile))
              Storage::unlink($runtimefile);
          $content =  '';
          // 读取应用模式
          $mode   =   include is_file(CONF_PATH.'core.php')?CONF_PATH.'core.php':MODE_PATH.APP_MODE.'.php';
          // 加载核心文件
          foreach ($mode['core'] as $file){
              if(is_file($file)) {
                include $file;
                if(!APP_DEBUG) $content   .= compile($file);
              }
          }

          // 加载应用模式配置文件
          foreach ($mode['config'] as $key=>$file){
              is_numeric($key)?C(load_config($file)):C($key,load_config($file));
          }

          // 读取当前应用模式对应的配置文件
          if('common' != APP_MODE && is_file(CONF_PATH.'config_'.APP_MODE.CONF_EXT))
              C(load_config(CONF_PATH.'config_'.APP_MODE.CONF_EXT));  

          // 加载模式别名定义
          if(isset($mode['alias'])){
              self::addMap(is_array($mode['alias'])?$mode['alias']:include $mode['alias']);
          }

          // 加载应用别名定义文件
          if(is_file(CONF_PATH.'alias.php'))
              self::addMap(include CONF_PATH.'alias.php');

          // 加载模式行为定义
          if(isset($mode['tags'])) {
              Hook::import(is_array($mode['tags'])?$mode['tags']:include $mode['tags']);
          }

          // 加载应用行为定义
          if(is_file(CONF_PATH.'tags.php'))
              // 允许应用增加开发模式配置定义
              Hook::import(include CONF_PATH.'tags.php');   

          // 加载框架底层语言包
          L(include THINK_PATH.'Lang/'.strtolower(C('DEFAULT_LANG')).'.php');

          if(!APP_DEBUG){
              $content  .=  "\nnamespace { Think\\Think::addMap(".var_export(self::$_map,true).");";
              $content  .=  "\nL(".var_export(L(),true).");\nC(".var_export(C(),true).');Think\Hook::import('.var_export(Hook::get(),true).');}';
              Storage::put($runtimefile,strip_whitespace('<?php '.$content));
          }else{
            // 调试模式加载系统默认的配置文件
            C(include THINK_PATH.'Conf/debug.php');
            // 读取应用调试配置文件
            if(is_file(CONF_PATH.'debug'.CONF_EXT))
                C(include CONF_PATH.'debug'.CONF_EXT);           
          }
      }


      // 读取当前应用状态对应的配置文件
      if(APP_STATUS && is_file(CONF_PATH.APP_STATUS.CONF_EXT))
          C(include CONF_PATH.APP_STATUS.CONF_EXT);   

      // 设置系统时区
      date_default_timezone_set(C('DEFAULT_TIMEZONE'));


      // 检查应用目录结构 如果不存在则自动创建  
        //  生成模块目录和Runtime目录
      if(C('CHECK_APP_DIR')) {
          $module     =   defined('BIND_MODULE') ? BIND_MODULE : C('DEFAULT_MODULE');
          if(!is_dir(APP_PATH.$module) || !is_dir(LOG_PATH)){
              // 检测应用目录结构
              Build::checkDir($module);
          }
      }

      // 记录加载文件时间
      G('loadTime');
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89

三 App初始化和URL解析,定位模块控制器和操作

主要文件加载

\thinkphp_3.2.3\ThinkPHP\Library\Think\App.class.php 
\thinkphp_3.2.3\ThinkPHP\Library\Think\Dispatcher.class.php 
\thinkphp_3.2.3\ThinkPHP\Library\Think\Route.class.php

简单流程

\ThinkPHP\Library\Think\Think.class.php
 // 运行应用
      App::run();
  • 1
  • 2
\ThinkPHP\Library\Think\App.class.php
 /**
     * 运行应用实例 入口文件使用的快捷方法
     * @access public
     * @return void
     */
    static public function run()
    {
        // 应用初始化标签
        /**
                'app_init'     =>  array(
                    'Behavior\BuildLiteBehavior', // 生成运行Lite文件
                ),
         *      生成lite文件,用于替换入口文件
         */
        Hook::listen('app_init');


        // app初始化,见init()
        App::init();

        // 应用开始标签
        /**
         *           'app_begin'     =>  array(
                             'Behavior\ReadHtmlCacheBehavior', // 读取静态缓存
                      ),
         *           若打开静态缓存开关,则直接获取缓存文件,输出,终止脚本。
         */
        Hook::listen('app_begin');

        // Session初始化
        if (!IS_CLI) {
            session(C('SESSION_OPTIONS'));
        }

        // 记录应用初始化时间
        G('initTime');

        /**app执行 :定位到controller action,并实例化执行之
         *
         *  //创建控制器实例
              $module = controller(CONTROLLER_NAME, CONTROLLER_PATH);
         *   $action = ACTION_NAME . C('ACTION_SUFFIX');
         *
         * //反射类,此处不展开说明
         *    $method = new \ReflectionMethod($module, $action);
         *    $class = new \ReflectionClass($module);
         *
         *    self::invokeAction($module, $action);
         *   用到反射类API,作用:
         *     判断方法公共,静态等
         *    前置方法,后置方法,空方法捕获并调用
         *     实现控制器方法的参数绑定
         *     调用action方法及上述方法
         */
        App::exec();
        ///  ...
        }

/**
     * 应用程序初始化
     * @access public
     * @return void
     */
    static public function init()
    {
        // 加载动态应用公共文件和配置
        // 加载应用配置文件下非系统定义的配置文件名,   C('LOAD_EXT_FILE')) C('LOAD_EXT_CONFIG'))
        load_ext_file(COMMON_PATH);

        // 日志目录转换为绝对路径 默认情况下存储到公共模块下面
        C('LOG_PATH', realpath(LOG_PATH) . '/Common/');

        // 定义当前请求的系统常量
        define('NOW_TIME', $_SERVER['REQUEST_TIME']);
        define('REQUEST_METHOD', $_SERVER['REQUEST_METHOD']);
        define('IS_GET', REQUEST_METHOD == 'GET' ? true : false);
        define('IS_POST', REQUEST_METHOD == 'POST' ? true : false);
        define('IS_PUT', REQUEST_METHOD == 'PUT' ? true : false);
        define('IS_DELETE', REQUEST_METHOD == 'DELETE' ? true : false);

        // URL调度
        // 主要是根据url模式,路由配置,子域名配置等,确认下面3个常量
        // 此处不展开说明
        /**
         * define('MODULE_NAME', defined('BIND_MODULE')? BIND_MODULE : self::getModule($varModule));      
         *  define('CONTROLLER_NAME',   defined('BIND_CONTROLLER')? BIND_CONTROLLER : self::getController($varController,$urlCase));
            define('ACTION_NAME',       defined('BIND_ACTION')? BIND_ACTION : self::getAction($varAction,$urlCase));
         */
        Dispatcher::dispatch();

        if (C('REQUEST_VARS_FILTER')) {
            // 全局安全过滤
            array_walk_recursive($_GET, 'think_filter');
            array_walk_recursive($_POST, 'think_filter');
            array_walk_recursive($_REQUEST, 'think_filter');
        }

        // URL调度结束标签,官方无动作
        Hook::listen('url_dispatch');

        define('IS_AJAX', ((isset($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest') || !empty($_POST[C('VAR_AJAX_SUBMIT')]) || !empty($_GET[C('VAR_AJAX_SUBMIT')])) ? true : false);

        // TMPL_EXCEPTION_FILE 改为绝对地址
        C('TMPL_EXCEPTION_FILE', realpath(C('TMPL_EXCEPTION_FILE')));
        return;
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106

四 Action执行和模板解析

主要文件加载

\thinkphp_3.2.3\ThinkPHP\Library\Think\Controller.class.php 
\thinkphp_3.2.3\ThinkPHP\Library\Think\View.class.php 
\thinkphp_3.2.3\Application\Home\Controller\IndexController.class.php 
\thinkphp_3.2.3\ThinkPHP\Library\Behavior\ParseTemplateBehavior.class.php 
\thinkphp_3.2.3\ThinkPHP\Library\Think\Template.class.php 
\thinkphp_3.2.3\ThinkPHP\Library\Think\Template\TagLib\Cx.class.php 
\thinkphp_3.2.3\ThinkPHP\Library\Think\Template\TagLib.class.php

简单流程

\Application\Home\Controller\IndexController.class.php
namespace Home\Controller;
use Think\Controller;
class IndexController extends Controller {
    public function index(){
        $this->display();
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
\thinkphp_3.2.3\ThinkPHP\Library\Think\Controller.class.php
namespace Think;
abstract class Controller {
    /**
     * 视图实例对象
     * @var view
     * @access protected
     */    
    protected $view     =  null;

    /**
     * 控制器参数
     * @var config
     * @access protected
     */      
    protected $config   =   array();

   /**
     * 架构函数 取得模板对象实例
     * @access public
     */
    public function __construct() {
        // 官方文档此处是输出静态缓存,不过源码是没有绑定行为的,不作处理
        Hook::listen('action_begin',$this->config);

        //实例化视图类
        // Controller类方法display assign fetch show 等都是调用此实例的对应方法
        $this->view     = Think::instance('Think\View');

        //控制器初始化
        if(method_exists($this,'_initialize'))
            $this->_initialize();
    }

/**
     * 模板显示 调用内置的模板引擎显示方法,
     * @access protected
     * @param string $templateFile 指定要调用的模板文件
     * 默认为空 由系统自动定位模板文件
     * @param string $charset 输出编码
     * @param string $contentType 输出类型
     * @param string $content 输出内容
     * @param string $prefix 模板缓存前缀
     * @return void
     */
    protected function display($templateFile='',$charset='',$contentType='',$content='',$prefix='') {
        $this->view->display($templateFile,$charset,$contentType,$content,$prefix);
    }

 // 此外此类还用魔术方法实现空操作的跳转和默认模板的调用
// 也实现了页面的重定向和自动跳转
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
\ThinkPHP\Library\Think\View.class.php
/**
     * 加载模板和页面输出 可以返回输出内容
     * @access public
     * @param string $templateFile 模板文件名
     * @param string $charset 模板输出字符集
     * @param string $contentType 输出类型
     * @param string $content 模板输出内容
     * @param string $prefix 模板缓存前缀
     * @return mixed
     */
    public function display($templateFile='',$charset='',$contentType='',$content='',$prefix='') {
        G('viewStartTime');

        // 视图开始标签,无
        Hook::listen('view_begin',$templateFile);

        // 解析并获取模板内容 见fetch()
        $content = $this->fetch($templateFile,$content,$prefix);

        // 输出模板内容
        // 此时输出的就是最终页面内容  ob_get_clean();(模板编译完, php执行完)
        $this->render($content,$charset,$contentType);

        // 视图结束标签 无
        Hook::listen('view_end');
    }


/**
     * 解析和获取模板内容 用于输出
     * @access public
     * @param string $templateFile 模板文件名
     * @param string $content 模板输出内容
     * @param string $prefix 模板缓存前缀
     * @return string
     */
    public function fetch($templateFile='',$content='',$prefix='') {
        if(empty($content)) {
            //自动定位模板文件
            $templateFile   =   $this->parseTemplate($templateFile);
            // 模板文件不存在直接返回
            if(!is_file($templateFile)) E(L('_TEMPLATE_NOT_EXIST_').':'.$templateFile);
        }else{
            defined('THEME_PATH') or    define('THEME_PATH', $this->getThemePath());
        }

        // 页面缓存
        ob_start();
        ob_implicit_flush(0);

        // 使用PHP原生模板    直接 extract include
        if('php' == strtolower(C('TMPL_ENGINE_TYPE'))) { 
            $_content   =   $content;
            // 模板阵列变量分解成为独立变量
            extract($this->tVar, EXTR_OVERWRITE);
            // 直接载入PHP模板
            empty($_content)?include $templateFile:eval('?>'.$_content);

          非原生,需要模板编译流程,不extract,而是传参
        }else{            
            // 视图解析标签
            $params = array('var'=>$this->tVar,'file'=>$templateFile,'content'=>$content,'prefix'=>$prefix);
            / Behavior\ParseTemplateBehavior 编译模板文件
            Hook::listen('view_parse',$params);
        }
        // 获取并清空缓存
        $content = ob_get_clean();
        // 内容过滤标签
        /**
               'template_filter'=> array(
                'Behavior\ContentReplaceBehavior', // 模板输出替换
                ),
         *      // 系统默认的特殊字符串替换,如js路径 css路径字符串
         */
        Hook::listen('view_filter',$content);
        // 输出模板文件
        return $content;
    }

/**
     * 输出内容文本可以包括Html
     * @access private
     * @param string $content 输出内容
     * @param string $charset 模板输出字符集
     * @param string $contentType 输出类型
     * @return mixed
     */
    private function render($content,$charset='',$contentType=''){
        if(empty($charset))  $charset = C('DEFAULT_CHARSET');
        if(empty($contentType)) $contentType = C('TMPL_CONTENT_TYPE');
        // 网页字符编码
        header('Content-Type:'.$contentType.'; charset='.$charset);
        header('Cache-control: '.C('HTTP_CACHE_CONTROL'));  // 页面缓存控制
        header('X-Powered-By:ThinkPHP');
        // 输出模板文件
        echo $content;
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
\ThinkPHP\Library\Behavior\ParseTemplateBehavior.class.php
/// 编译缓存实质是将模板文件的特定标签替换为php代码,自定义的拓展标签只能用在默认的thinkphp模板引擎。
///此处不展开说明了

class ParseTemplateBehavior {
    // 行为扩展的执行入口必须是run
    public function run(&$_data){
        $engine             =   strtolower(C('TMPL_ENGINE_TYPE'));
        $_content           =   empty($_data['content'])?$_data['file']:$_data['content'];
        $_data['prefix']    =   !empty($_data['prefix'])?$_data['prefix']:C('TMPL_CACHE_PREFIX');
        if('think'==$engine){ // 采用Think模板引擎
            if((!empty($_data['content']) && $this->checkContentCache($_data['content'],$_data['prefix'])) 
                ||  $this->checkCache($_data['file'],$_data['prefix'])) { // 缓存有效
                //载入模版缓存文件
                   =====  直接include file
                Storage::load(C('CACHE_PATH').$_data['prefix'].md5($_content).C('TMPL_CACHFILE_SUFFIX'),$_data['var']);
            }else{
                $tpl = Think::instance('Think\\Template');
                // 编译并加载模板文件
                $tpl->fetch($_content,$_data['var'],$_data['prefix']);
            }
        }else{
            // 调用第三方模板引擎解析和输出
            if(strpos($engine,'\\')){
                $class  =   $engine;
            }else{
                $class   =  'Think\\Template\\Driver\\'.ucwords($engine);                
            }            
            if(class_exists($class)) {
                $tpl   =  new $class;
                $tpl->fetch($_content,$_data['var']);
            }else {  // 类没有定义
                E(L('_NOT_SUPPORT_').': ' . $class);
            }
        }
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36

五 收尾流程

简单流程

\ThinkPHP\Library\Think\App.class.php
// 应用结束标签
        /**
         *     'app_end'       =>  array(
                'Behavior\ShowPageTraceBehavior', // 页面Trace显示
                ),
         */
        Hook::listen('app_end');
        return;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
\ThinkPHP\Library\Think\Think.class.php
 // 脚本正常结束或者手动或异常终结处理
 // 处理: 1.内存中的日志落地到文件 2.如果是异常终止,则输出错误
 register_shutdown_function('Think\Think::fatalError');

// 致命错误捕获
    static public function fatalError() {
        Log::save();
        if ($e = error_get_last()) {
            switch($e['type']){
              case E_ERROR:
              case E_PARSE:
              case E_CORE_ERROR:
              case E_COMPILE_ERROR:
              case E_USER_ERROR:  
                ob_end_clean();
                self::halt($e);
                break;
            }
        }
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

END

以后有机会再研究和补充此框架源码的机制实现说明,如: 
Hook机制,controller反射机制,Model的ORM实现,路由解析定位的实现,模板的编译机制,session方法使用机制,文件编译缓存,PageTrace的使用等,欢迎大家一起探讨学习。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
ThinkPHP是一个免费开源的,快速、简单的面向对象的轻量级PHP开发框架,遵循Apache2开源协议发布,是为了敏捷WEB应用 开发和简化企业级应用开发而诞生的。拥有众多的优秀功能和特性,经历了三年多发展的同时,在社区团队的积极参与下,在易用性、扩展性和性能方面不断优化和 改进,众多的典型案例确保可以稳定用于商业以及门户级的开发。 ThinkPHP借鉴了国外很多优秀的框架和模式,使用面向对象的开发结构和MVC模式,采用单一入口模式等,融合了Struts的 Action思想和JSP的TagLib(标签库)、RoR的ORM映射和ActiveRecord模式,封装了CURD和一些常用操作,在项目配置、类 库导入、模版引擎、查询语言、自动验证、视图模型、项目编译、缓存机制、SEO支持、分布式数据库、多数据库连接和切换、认证机制和扩展性方面均有独特的 表现。 使用ThinkPHP,你可以更方便和快捷的开发和部署应用。当然不仅仅是企业级应用,任何PHP应用开发都可以从ThinkPHP的简单 和快速的特性中受益。ThinkPHP本身具有很多的原创特性,并且倡导大道至简,开发由我的开发理念,用最少的代码完成更多的功能,宗旨就是让WEB应 用开发更简单、更快速。为此ThinkPHP会不断吸收和融入更好的技术以保证其新鲜和活力,提供WEB应用开发的最佳实践! ThinkPHP遵循Apache2开源许可协议发布,意味着你可以免费使用ThinkPHP,甚至允许把你基于ThinkPHP开发的应用开源或商业产 品发布/销售。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值