1. 入口文件index.php

用户对url的访问首先被定位到http://<serverIp>/<appName>/index.php, 这里的入口文件index.php做三件事情:1.1, 1.2, 1.3

1.1 定义或载入全局变量

常见的有APP_NAME(项目名称), APP_PATH(项目路径), THINK_PATH(ThinkPHP框架路径);

我研究的是ThinkSNS1.6,它除了用ThinkPHP的全局变量比如THINK_MODE, 又加入了自己定义的一些全局变量,如SITE_PATH, SITE_URL,

注意到ThinkSNS定义了自己的模式ThinkSNS,





define('THINK_MODE','ThinkSNS');





关于ThinkPHP的模式扩展,在ThinkPHP2.0完全开发手册6.10模式扩展章节中有介绍,总的思想是通过模式扩展使得开发者可以定制自己需要使用的ThinkPHP底层框架核心,不必拘泥于ThinkPHP默认的标准模式。



1.2 加载框架入口文件ThinkPHP.php

入口文件通常是ThinkPHP.php,





require(THINK_PATH."/ThinkPHP.php");





而ThinkSNS定义了自己的入口文件ThinkSNS.php,不过总体的思想是一样的。

在这个框架入口文件,做下面的事情:



1.2.1 记录开始运行时间

$GLOBALS['_beginTime'] = microtime(TRUE);





1.2.2 检测THINK_PATH,APP_NAME, APP_PATH

// ThinkPHP系统目录定义

if(!defined('THINK_PATH')) define('THINK_PATH', dirname(__FILE__));

if(!defined('APP_NAME')) define('APP_NAME', basename(dirname($_SERVER['SCRIPT_FILENAME'])));

if(!defined('APP_PATH')) define('APP_PATH', dirname($_SERVER['SCRIPT_FILENAME']));





1.2.3 检测项目编译缓存目录定义,没有则取项目的Temp目录

1.2.4 加载常量定义文件defines.php和公共函数文件functions.php

require THINK_PATH.'/Common/defines.php';



...



$runtime[] = THINK_PATH.'/Common/functions.php'; // 系统函数





1.2.5 加载核心基类

// 核心基类必须加载

$runtime[] = THINK_PATH.'/Lib/Think/Core/Think.class.php';





1.2.6 加载核心编译文件

核心编译文件列表由文件core.php给出;可以自定制,放在CONFIG_PATH下;或者可以根据扩展模式放在THINK_MODE下;或者使用默认的THINK_PATH.'/Common/core.php'

// 读取核心编译文件列表

if(is_file(CONFIG_PATH.'core.php')) {



// 加载项目自定义的核心编译文件列表

$list = include CONFIG_PATH.'core.php';

}else{

if(defined('THINK_MODE')) {

// 根据设置的运行模式加载不同的核心编译文件

$list = include



THINK_PATH.'/Mode/'.strtolower(THINK_MODE).'.php';

}else{

// 默认核心

$list = include THINK_PATH.'/Common/core.php';

}

}





默认的THINK_PATH.'/Common/core.php'的内容为



// 系统默认的核心列表文件

return array(

THINK_PATH.'/Lib/Think/Exception/ThinkException.class.php', // 异常处理类

THINK_PATH.'/Lib/Think/Core/Log.class.php', // 日志处理类

THINK_PATH.'/Lib/Think/Core/App.class.php', // 应用程序类

THINK_PATH.'/Lib/Think/Core/Action.class.php', // 控制器类

//THINK_PATH.'/Lib/Think/Core/Model.class.php', // 模型类

THINK_PATH.'/Lib/Think/Core/View.class.php', // 视图类

THINK_PATH.'/Common/alias.php', // 加载别名

);





这样就加载了系统核心类库(包括App、Action、Model、View、ThinkException、Log)

1.2.7 生成核心编译缓存~runtime.php

如果没有定义NO_CACHE_RUNTIME, 则把上面步骤中加载的文件统一写到~runtime.php中,下次就可以直接调用核心编译缓存~runtime.php,无需再一一加载





// 生成核心编译缓存 去掉文件空白以减少大小

if(!defined('NO_CACHE_RUNTIME')) {

$compile = defined('RUNTIME_ALLINONE');

$content = compile(THINK_PATH.'/Common/defines.php',$compile);

$content .= compile(defined('PATH_DEFINE_FILE')? PATH_DEFINE_FILE : THINK_PATH.'/Common/paths.php',$compile);

foreach ($runtime as $file){

$content .= compile($file,$compile);

}

if(defined('STRIP_RUNTIME_SPACE') && STRIP_RUNTIME_SPACE == false ) {

file_put_contents(RUNTIME_PATH.'~runtime.php','<?php'.$content);

}else{ file_put_contents(RUNTIME_PATH.'~runtime.php',strip_whitespace('<?php'.$content));

}

unset($content);



}





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

// 记录加载文件时间

$GLOBALS['_loadTime'] = microtime(TRUE);





1.3 执行应用,实例化App类

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

$App = new App();

$App->run();





在调用$App->run()时,具体做的事情,可看ThinkPHP\Lib\Think\Core\App.class.php里的public function run(),



/**

+----------------------------------------------------------

* 运行应用实例 入口文件使用的快捷方法

+----------------------------------------------------------

* @access public

+----------------------------------------------------------

* @return void

+----------------------------------------------------------

*/

public function run() {

$this->init();

// 记录应用初始化时间

if(C('SHOW_RUN_TIME'))

$GLOBALS['_initTime'] = microtime(TRUE);

$this->exec();

$GLOBALS['_endTime'] = microtime(TRUE);

// 保存日志记录

if(C('WEB_LOG_RECORD'))

Log::save();

return ;

}





那么接着看$this->init()做什么事情,根据下面的代码,看到

首先如果编译后的项目文件~app.php存在则直接加载它,如果不存在则调用build函数来生成~app.php;

之后通过define('MODULE_NAME',$this->getModule())和define('ACTION_NAME', $this->getAction())将模块和动作的名字放入全局变量



/**

+----------------------------------------------------------

* 应用程序初始化

+----------------------------------------------------------

* @access public

+----------------------------------------------------------

* @return void

+----------------------------------------------------------

*/

public function init()

{

// 设定错误和异常处理

set_error_handler(array(&$this,"appError"));

set_exception_handler(array(&$this,"appException"));

// 检查项目是否编译过

// 在部署模式下会自动在第一次执行的时候编译项目

if(is_file(RUNTIME_PATH.'~app.php') && (!is_file(CONFIG_PATH.'config.php') || filemtime(RUNTIME_PATH.'~app.php')>filemtime(CONFIG_PATH.'config.php'))) {

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

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

}else{

// 预编译项目

$this->build();

}

// 项目开始标签

if(C('TAG_PLUGIN_ON')) tag('app_begin');



// 设置系统时区 PHP5支持

if(function_exists('date_default_timezone_set'))

date_default_timezone_set(C('TIME_ZONE'));



if(C('SESSION_AUTO_START'))

// Session初始化

session_start();



// 应用调度过滤器

// 如果没有加载任何URL调度器

// 默认只支持 QUERY_STRING 方式

// 例如 ?m=user&a=add

if(C('DISPATCH_ON')) {

import('Dispatcher');

Dispatcher::dispatch();

}



if(!defined('PHP_FILE'))

// PHP_FILE 由内置的Dispacher定义

// 如果不使用该插件,需要重新定义

define('PHP_FILE',_PHP_FILE_);



// 取得模块和操作名称

// 可以在Dispatcher中定义获取规则

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

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



// 加载模块配置文件

if(is_file(CONFIG_PATH.strtolower(MODULE_NAME).'_config.php'))

C(include CONFIG_PATH.strtolower(MODULE_NAME).'_config.php');



// 系统检查

$this->checkLanguage(); //语言检查

$this->checkTemplate(); //模板检查



if(C('HTML_CACHE_ON')) { // 开启静态缓存

import('HtmlCache');

HtmlCache::readHTMLCache();

}



// 项目初始化标签

if(C('TAG_PLUGIN_ON')) tag('app_init');



return ;

}





$this->init()执行完后,就完成了定义MODULE_NAME和ACTION_NAME,接着执行

$this->exec(),





/**

+----------------------------------------------------------

* 执行应用程序

+----------------------------------------------------------

* @access public

+----------------------------------------------------------

* @return void

+----------------------------------------------------------

* @throws ThinkExecption

+----------------------------------------------------------

*/

public function exec()

{

// 是否开启标签扩展

$tagOn = C('TAG_PLUGIN_ON');

// 项目运行标签

if($tagOn) tag('app_run');



//创建Action控制器实例

$module = A(MODULE_NAME);

if(!$module) {

// 是否存在扩展模块

$_module = C('_modules_.'.MODULE_NAME);

if($_module) {

// 'module'=>array('classImportPath'[,'className'])

import($_module[0]);

$class = isset($_module[1])?$_module[1]:MODULE_NAME.'Action';

$module = new $class;

}else{

// 是否定义Empty模块

$module = A("Empty");

}

if(!$module) {

// 模块不存在 抛出异常

throw_exception(L('_MODULE_NOT_EXIST_').MODULE_NAME);

}

}



//获取当前操作名

$action = ACTION_NAME;

if(strpos($action,':')) {

// 执行操作链 最多只能有一个输出

$actionList = explode(':',$action);

foreach ($actionList as $action){

$module->$action();

}

}else{

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

// 执行前置操作

call_user_func(array(&$module,'_before_'.$action));

}else{

// 操作前置标签

if($tagOn) tag('action_before');

}

//执行当前操作

call_user_func(array(&$module,$action));

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

// 执行后缀操作

call_user_func(array(&$module,'_after_'.$action));

}else{

// 操作后置标签

if($tagOn) tag('action_after');

}

}

// 项目结束标签

if($tagOn) tag('app_end');

return ;

}





根据上面代码,

首先创建Action控制器实例$module = A(MODULE_NAME),

其中function A()是在文件functions.php里的,它负责实例化对应的Action的class,它的部分代码如下,它根据MODULE_NAME来加载对应的Ation Class的文件,之后通过$action = new $className()进行实例化.



if('@'===$appName) {

require_cache(LIB_PATH.'Action/'.$className.'.class.php');

}else{

import($appName.'.Action.'.$className);

}

if(class_exists($className)) {

$action = new $className();

$_action[$appName.$OriClassName] = $action;

return $action;

}else {

return false;

}





后记:由于看得文档时ThinkPHP2.0的,而所有的代码都是ThinkSNS1.6(使用的是ThinkPHP1.6)的,所以有些地方并不是很准确,但大体思想和步骤是一致的。
 

thinkphp执行流程的更多相关文章

  1. ThinkPHP中的跨控制器调用与框架执行流程

    一.跨控制器调用 UserController.class.php <?php namespace Home/Controller use Think/Controller class User ...

  2. ThinkPHP2.2框架执行流程图,ThinkPHP控制器的执行流程

    ThinkPHP2.2框架执行原理.流程图在线手册 ThinkPHP控制器的执行流程 对用户的第一次URL访问 http://<serverIp>/My/index.php/Index/s ...

  3. ThinkPHP 框架执行流程分析

    总体来说,应用的流程涉及到几个文件:Index.phpThinkPHP.phpThink.class.phpApp.class.phpDispatcher.class.phpThinkPHP/Mode ...

  4. Thinkphp设计模式和执行流程

    ThinkPHP设计模式 单例模式:数据库连接DB工厂模式:比如Db.class.php中的factory()方法适配器模式:驱动类,数据库观察者模式:Hook类 注册树模式:绑定容器外观模式:fac ...

  5. (一)熟悉执行流程——基于ThinkPHP3.2的内容管理框架OneThink学习

    ThinkPHP作为国内具有代表性的PHP框架,经过多年的发展,受到越来越多公司与开发者的青睐.我也在忙里偷闲中抽出部分时间,来学习这个优秀的框架.在开始学习这个框架时,最好通过实例来学习,更容易结合 ...

  6. 步步深入:MySQL架构总览->查询执行流程->SQL解析顺序

    前言: 一直是想知道一条SQL语句是怎么被执行的,它执行的顺序是怎样的,然后查看总结各方资料,就有了下面这一篇博文了. 本文将从MySQL总体架构--->查询执行流程--->语句执行顺序来 ...

  7. 第二天 ci执行流程

    第二天 ci执行流程 welcome 页面 this this->load 单入口框架index.php 两个文件夹 system application定义 定义常亮路径 载入 codeign ...

  8. 轻量级前端MVVM框架avalon - 执行流程2

    接上一章 执行流程1 在这一大堆扫描绑定方法中应该会哪些实现? 首先我们看avalon能帮你做什么? 数据填充,比如表单的一些初始值,切换卡的各个面板的内容({{xxx}},{{xxx|html}}, ...

  9. [Java编程思想-学习笔记]第4章 控制执行流程

    4.1  return 关键字return有两方面的用途:一方面指定一个方法结束时返回一个值:一方面强行在return位置结束整个方法,如下所示: char test(int score) { if ...

随机推荐

  1. SharePoint Server 2013 Excel Web Access无法显示

    环境信息:SharePoint Server 2013 中文版,版本为15.0.4420.1017 Windows Server 2008 r2中文版 Sql Server 2012 问题描述:在Sh ...

  2. Time - Time-interval Measurements

    public class TimeHelper { private long _start, _stop, _elapsed; /// <summary> /// 获取初始时间戳 /// ...

  3. NSArray 数组

    前言 数组只能存储 OC 对象,不能存储 C 语言中的基本数据类型,也不能存储 nil . Xcode 7 对系统中常用的一系列容器类型都增加了泛型支持(),有了泛型后就可以指定容器类中对象的类型了. ...

  4. 洛谷P4494 [HAOI2018]反色游戏(tarjan)

    题面 传送门 题解 我们先来考虑一个联通块,这些关系显然可以写成一个异或方程组的形式,形如\(\oplus_{e\in edge_u}x_e=col_u\) 如果这个联通块的黑色点个数为奇数,那么显然 ...

  5. linux下 zip解压 tar解压 gz解压 bz2等各种解压文件命令

    .tar 解包:tar xvf FileName.tar 打包:tar cvf FileName.tar DirName (注:tar是打包,不是压缩!) ——————————————— .gz 解压 ...

  6. HTML的相关路径与绝对路径的问题---通过网络搜索整理

    问题描述:    在webroot中有个index.jsp 在index.jsp中写个表单. 现在在webroot中有个sub文件夹,sub文件夹中有个submit.jsp想得到index.jsp表单 ...

  7. Tensorflow的认识

    1.基本概念(Tensorflow) 使用图(graphs)来表示计算任务 n 在被称之为会话(Session)的上下文(context)中执行图 n 使用tensor表示数据 n 通过变量(Vari ...

  8. C语言数据结构-链式队列的实现-初始化、销毁、清空、长度、队列头元素、插入、删除、显示操作

    1.数据结构-链式队列的实现-C语言 typedef struct QNode { int data; struct QNode *next; }QNode,*QueuePtr; typedef st ...

  9. Jenkins持续集成企业实战系列之Jenkins持续集成简介及安装-----02

    1.      Jenkins持续集成简介 注:原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 .作者信息和本声明.否则将追究法律责任.    最初接触Jenkins也是由于公司需求, ...

  10. JAVA基础——Java 中必须了解的常用类

    Java中必须了解的常用类 一.包装类 相信各位小伙伴们对基本数据类型都非常熟悉,例如 int.float.double.boolean.char 等.基本数据类型是不具备对象的特性的,比如基本类型不 ...