thinkphp
Download
Skip this Video
Download Presentation
ThinkPHP 执行流程分析

Loading in 2 Seconds...

play fullscreen
1 / 20

ThinkPHP 执行流程分析 - PowerPoint PPT Presentation


  • 91 Views
  • Uploaded on

ThinkPHP 执行流程分析. [email protected] http://www.yhustc.com. 前言. 要分析什么? 分析一下从访问 index.php 到加载 Action 文件、调用用户指定操作的过程。 达到什么样的效果? 分析一下在进入自己指定的模块与操作之前发生过一些什么事情,以及如何通过 index.php 进入指定的模块与操作,让你能搞明白这些事情,要的就这效果。. 入口文件的定义. <?php define(\'THINK_PATH\', \'../ThinkPHP\'); // 定义项目名称,如果不定义,默认为入口文件名称

loader
I am the owner, or an agent authorized to act on behalf of the owner, of the copyrighted work described.
capcha
Download Presentation

PowerPoint Slideshow about ' ThinkPHP 执行流程分析' - kelly-caldwell


An Image/Link below is provided (as is) to download presentation

Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author.While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server.


- - - - - - - - - - - - - - - - - - - - - - - - - - E N D - - - - - - - - - - - - - - - - - - - - - - - - - -
Presentation Transcript
slide2
前言
  • 要分析什么?

分析一下从访问index.php到加载Action文件、调用用户指定操作的过程。

  • 达到什么样的效果?

分析一下在进入自己指定的模块与操作之前发生过一些什么事情,以及如何通过index.php进入指定的模块与操作,让你能搞明白这些事情,要的就这效果。

slide3
入口文件的定义

<?php

define(\'THINK_PATH\', \'../ThinkPHP\');

//定义项目名称,如果不定义,默认为入口文件名称

define(\'APP_NAME\', \'web\');

define(\'APP_PATH\', \'./web\');

//加载ThinkPHP框架公共入口文件

require(THINK_PATH.\'/ThinkPHP.php\');

//实例化一个网站应用实例

$App = new App();

//执行应用程序

$App->run();

?>

thinkphp php
ThinkPHP.php里面的干了些啥

记录开始执行时间 $GLOBALS[‘_beginTime’](20行)

检测 THINK_PATH、 APP_NAME、 APP_PATH、 RUNTIME_PATH 定义,如果没有则创建(23-26行)

//不知道你发现没有,以index.php这基准,通过APP_PATH,可以组装出任意路径

检查是否有核心缓存~runtime.php(28行)

if(file_exists(RUNTIME_PATH.\'~runtime.php\')) {

// 加载框架核心缓存文件

// 如果有修改核心文件请删除该缓存

require RUNTIME_PATH.\'~runtime.php\';

}else{

进入else

}

记录加载文件时间 $GLOBALS[\'_loadTime\'];

require thinkphp.php完成

thinkphp php 32 else
ThinkPHP.php 32行的else

加载系统定义文件 ThinkPHP\Common\defines.php 和公共函数文件 ThinkPHP\Common\functions.php(34-36行)

如果项目编译缓存目录不存在,则自动创建项目目录结构(41行buildAppDir()是在functions.php中定义的函数)

加载系统核心类库(包括ThinkPHP\LIB\THINK下级各子目录下的 Base、App、Action、Model、View、ThinkException、Log)(45-54行)

如果 PHP 版本低于 5.2.0 则加载兼容函数库 ThinkPHP\Common\compat.php(76行)

生成核心编译缓存~runtime.php(生成在APP_PATH\ Temp\目录下)

退出else

thinkphp lib think core app
进入ThinkPHP\Lib\Think\Core\App

入口文件中调用的$App->run()

public function run() {

$this->init();

$this->exec();

return ;

}

$App->run()返回的时候,对一个请求的处理就算完成了

app class php init 1
App.class.php的init函数(1)

设定错误和异常处理机制(set_error_handler和set_exception_handler)(92-93行)

项目预编译并载入(97-103行)

if(file_exists(RUNTIME_PATH.\'~app.php\') && filemtime(RUNTIME_PATH.\'~app.php\')>filemtime(CONFIG_PATH.\'config.php\')) {

// 直接读取编译后的项目文件

C(include RUNTIME_PATH.\'~app.php\');

}else{

// 预编译项目

$this->build();

}

设置时区支持(106-107行)

Session过滤器检查、 session初始化(109-115行)

app class php init 2
App.class.php的init函数(2)

检查并加载插件(118-120行)

if(C(\'THINK_PLUGIN_ON\')) {

$this->loadPlugIn();

}

URL分析和调度(126-135行)

if(C(\'DISPATCH_ON\')) {

if( \'Think\'== C(\'DISPATCH_NAME\') ) {

// 使用内置的ThinkDispatcher调度器

import(\'Think.Util.Dispatcher\');

Dispatcher::dispatch();

}else{

// 加载第三方调度器

apply_filter(\'app_dispatch\');

}

}

app class php init 3
App.class.php的init函数(3)

取得模块和操作名称 如果有伪装 则返回真实的名称(145-146行)

if(!defined(\'MODULE_NAME\'))

define(\'MODULE_NAME\', $this->getModule()); // Module名称

if(!defined(\'ACTION_NAME\'))

define(\'ACTION_NAME\', $this->getAction()); // Action操作

加载模块配置文件(149-151行)

页面防刷新机制检查(154-167行)

语言检查并读取对应的语言文件(170行)

$this->checkLanguage();

//通过COOKIE保存当前语言,可以dump($_COOKIE)看看

app class php init 4
App.class.php的init函数(4)

模板检查并定义相关的模板变量(171行)

$this->checkTemplate();

//通过COOKIE保存当前模板主题,可以dump($_COOKIE)看看

RBAC权限检测(173-184行)

RBAC最好单独了解,这个PPT里写不了那么全面

如果开启静态写入则读取静态缓存文件(186-189行)

应用初始化过滤插件app_init (191行)

apply_filter(‘app_init’); //ThinkPHP\Common\functions.php中有定义

记录应用初始化时间$GLOBALS[\'_initTime\']

初始化完成,init返回

build
Build了一些什么东西?

加载系统惯例配置文件ThinkPHP\Common\convention.php(213行)

加载项目配置文件APP_PATH\Conf\config.php(217行)

加载项目公共文件APP_PATH\Common\common.php(224行)

如果是调试模式加载系统调试配置文件ThinkPHP\Common\debug.php(233行)

如果定义了项目的调试配置文件则载入APP_PATH\Common\debug.php(236行)

生成项目编译缓存文件APP_PATH\Temp\~app.php(242行)

现在知道~app.php里面放了些啥吧?留一个问题,如何让一段代码每次都自动执行,而且不受RBAC权限控制的限制?

Build完毕,继续执行init

app class php loadplugin
App.class.php的loadplugin

加载有效插件文件(loadplugin函数在App.class.php 478行)

if(file_exists(RUNTIME_PATH.\'~plugins.php\')) {

include RUNTIME_PATH.‘~plugins.php’; //注意了,插件也会缓存,改了插件记得清缓存

}else{

// 检查插件数据

$common_plugins = get_plugins(THINK_PATH.\'/PlugIns\',\'Think\');// 公共插件

$app_plugins = get_plugins();// 项目插件 ThinkPHP\Common\functions.php中有定义

// 合并插件数据

$plugins = array_merge($common_plugins,$app_plugins);

// 缓存插件数据

$content = \'\';

foreach($plugins as $key=>$val) {

include $val[\'file\'];

$content .= php_strip_whitespace($val[\'file\']);

}

file_put_contents(RUNTIME_PATH.‘~plugins.php’,$content);

//RUNTIME_PATH默认就是APP_PATH\Temp

}

插件加载完毕,继续执行init

dispatcher class php dispatch
Dispatcher.class.php的dispatch

(Dispatcher.class.php的第一个函数就是dispatch)

检查当前URL模式URL_MODEL

如果存在$_GET变量,则根据当前的URL模式和设置进行重定向

进行路由定义检测

分析PATH_INFO的URL信息到数组

这一部分不难理解,就不详细讲代码了

URL解析完成,继续执行init

app class php getmodule
App.class.php的getModule

App.class.php 256行

检查 VAR_MODULE 变量(包括 GET 和 POST), 如果未定义,则获取默认模块名(258-262行)

检查组件模块

if(strpos($module,C(‘COMPONENT_DEPR’))) { // COMPONENT_DEPR 组件模式分隔符,默认是@

define(‘C_MODULE_NAME’,$module); // 带@的完整的模块名定义为C_MODULE_NAME

$array = explode(C(\'COMPONENT_DEPR\'),$module);

$module = array_pop($array);

// @后面部分作为实际的模块名称,返回后被定义为MODULE_NAME

}

检查模块URL伪装

if(C(\'MODULE_REDIRECT\')) {

$res = preg_replace(\'@(\w+):([^,\/]+)@e\', \'$modules[\\'\\1\\']="\\2";\', C(\'MODULE_REDIRECT\'));

if(array_key_exists($module,$modules)) {

define(‘P_MODULE_NAME’,$module); // 伪装的模块名定义为P_MODULE_NAME

$module = $modules[$module];

}

}

return $module;

模块名称解析完毕,也就是http://server/project/index.php/Model/Action/的Model部分,回到init

app class php getaction
App.class.php的getAction

App.class.php 292行

检查 VAR_ACTION 变量(包括 GET 和 POST), 如果未定义,则获取默认操作名

检查操作链(以下部分可以参考getModule自行分析,别骂我,学会自己分析是有必要的)

if(strpos($action,C(\'COMPONENT_DEPR\'))) {

// 记录完整的操作名

define(\'C_ACTION_NAME\',$action);

$array = explode(C(\'COMPONENT_DEPR\'),$action);

// 实际的模块名称

$action = array_pop($array);

}

检查操作URL伪装

if(C(\'ACTION_REDIRECT\')) {

$res = preg_replace(\'@(\w+):([^,\/]+)@e\', \'$actions[\\'\\1\\']="\\2";\', C(\'ACTION_REDIRECT\'));

if(array_key_exists($action,$actions)) {

// 记录伪装的操作名称

define(\'P_ACTION_NAME\',$action);

$action = $actions[$action];

}

}

操作名称解析完毕,也就是http://server/project/index.php/Model/Action/的Action部分,回到init

app class php exec 1
App.class.php的exec函数(1)

AUTO_LOAD_CLASS检查如果有则导入公共类(514-520行)

实例化当前模块的Action控制器类(522-526行)

if(defined(‘C_MODULE_NAME’)) { //组件化模块

$module = A(C_MODULE_NAME);

//A函数在ThinkPHP\Common\functions.php中定义,可以根据@连接的模块名自动处理找到正确的Action文件

}else{

$module = A(MODULE_NAME);

}

如果Action控制器不存在则检查空模块EmptyAction (527-534行)

app class php exec 2
App.class.php的exec函数(2)

App.class.php 537-555行

$action = ACTION_NAME.C(‘ACTION_SUFFIX’);

if(defined(‘C_ACTION_NAME’)) {

// 定义了操作链,执行操作链,最多只能有一个输出(这个得由用户自己控制,注意写代码的时候不要多处使用display来输出,用echo没问题)

$actionList = explode(C(\'COMPONENT_DEPR\'),C_ACTION_NAME);

foreach ($actionList as $action){

$module->$action(); //这里就是调用指定Action的指定function了

}

}else{

//如果存在前置操作,首先执行

if (method_exists($module,\'_before_\'.$action)) {

$module->{\'_before_\'.$action}();

}

//执行操作

$module->{$action}();

//执行指定Action的指定function,这里面的流程我就没法给你分析了,看自己代码怎么写的

//如果存在后置操作,继续执行

if (method_exists($module,\'_after_\'.$action)) {

$module->{\'_after_\'.$action}();

}

}

app class php exec 3
App.class.php的exec函数(3)

执行应用结束过滤器(557行)

apply_filter(\'app_end\');

写入错误日志(560-561行)

if(C(\'WEB_LOG_RECORD\'))

Log::save();

exec执行完毕,一个请求处理完成了

slide19
回到入口文件

<?php

define(\'THINK_PATH\', \'../ThinkPHP\');

//定义项目名称,如果不定义,默认为入口文件名称

define(\'APP_NAME\', \'web\');

define(\'APP_PATH\', \'./web\');

//加载ThinkPHP框架公共入口文件

require(THINK_PATH.\'/ThinkPHP.php\');

//实例化一个网站应用实例

$App = new App();

//执行应用程序

$App->run(); //分为init和exec两步

?>

slide20
小结

$App->run()分为init和exec两部分,现在都已经走完,但是这中间还省略了一部分分析,比如RBAC,比如用户代码中的那些操作中,Model相关的代码。建议用户自行分析一下,这样有助于对TP的理解。有什么问题欢迎到ThinkPHP论坛(http://bbs.thinkphp.cn)或者我的Blog(http://www.yhustc.com)来交流。

ad