# htaccess文件
~~~
<IfModule mod_rewrite.c>
Options +FollowSymlinks -Multiviews
RewriteEngine On
//不是目录
RewriteCond %{REQUEST_FILENAME} !-d
//不是文件
RewriteCond %{REQUEST_FILENAME} !-f
//重定向
RewriteRule ^(.*)$ index.php/$1 [QSA,PT,L]
</IfModule>
~~~
# 1、入口文件
用户发起的请求都会经过应用的入口文件,通常是 public/index.php文件。当然,你也可以更改或者增加新的入口文件。
通常入口文件的代码都比较简单,一个普通的入口文件代码如下:
~~~
// [ 应用入口文件 ]
// 定义应用目录
define('APP_PATH', __DIR__ . '/../application/');
// 加载框架引导文件
require __DIR__ . '/../thinkphp/start.php';
~~~
# 2、引导文件
接下来就是执行框架的引导文件,start.php文件就是系统默认的一个引导文件。在引导文件中,会依次执行下面操作:
* 加载系统常量定义;
* 加载环境变量定义文件;
* 注册自动加载机制;
* 注册错误和异常处理机制;
* 加载惯例配置文件;
* 执行应用;
~~~
// ThinkPHP 引导文件
// 1. 加载基础文件
require __DIR__ . '/base.php';
// 2. 执行应用
App::run()->send();
~~~
### 基础文件base.php
* 加载系统常量定义;
![](https://img.kancloud.cn/2f/db/2fdb0f0f3f6895b1e91b8dad26a90d15_928x463.png)
#### 预定义常量
预定义常量是指系统内置定义好的常量,不会随着环境的变化而变化,包括:
~~~
EXT 类库文件后缀(.php)
THINK_VERSION 框架版本号
~~~
#### 系统常量
系统常量会随着开发环境的改变或者设置的改变而产生变化。
~~~
IS_WIN 是否属于Windows 环境
IS_CLI 是否属于命令行模式
THINK_START_TIME 开始运行时间(时间戳)
THINK_START_MEM 开始运行时候的内存占用
ENV_PREFIX 环境变量配置前缀
~~~
#### 路径常量
系统和应用的路径常量用于系统默认的目录规范,可以通过重新定义改变,如果不希望定制目录,这些常量一般不需要更改。
~~~
DS 当前系统的目录分隔符
THINK_PATH 框架系统目录
ROOT_PATH 框架应用根目录
APP_PATH 应用目录(默认为application)
CONF_PATH 配置目录(默认为APP_PATH)
LIB_PATH 系统类库目录(默认为 THINK_PATH.'library/')
CORE_PATH 系统核心类库目录 (默认为 LIB_PATH.'think/')
TRAIT_PATH 系统trait目录(默认为 LIB_PATH.'traits/')
EXTEND_PATH 扩展类库目录(默认为 ROOT_PATH . 'extend/')
VENDOR_PATH 第三方类库目录(默认为 ROOT_PATH . 'vendor/')
RUNTIME_PATH 应用运行时目录(默认为 ROOT_PATH.'runtime/')
LOG_PATH 应用日志目录 (默认为 RUNTIME_PATH.'log/')
CACHE_PATH 项目模板缓存目录(默认为 RUNTIME_PATH.'cache/')
TEMP_PATH 应用缓存目录(默认为 RUNTIME_PATH.'temp/')
~~~
* 加载环境变量定义文件;
# 注册自动加载机制
~~~
// 载入Loader类
require CORE_PATH . 'Loader.php';
// 注册自动加载
\think\Loader::register();
~~~
#### Loader::register方法
系统的自动加载由下面主要部分组成:
注册系统的自动加载方法 \think\Loader::autoload
~~~
// 注册系统自动加载
spl_autoload_register($autoload ?: 'think\\Loader::autoload', true, true);
~~~
> 当php未找到方法时,自动调用Loader::autoload加载
>
注册系统命名空间定义
加载类库映射文件(如果存在)
如果存在Composer安装,则注册**Composer**自动加载
注册extend扩展目录
> 我们的扩展类库可以放在extend 目录下,thinkphp5会自动加载
系统会调用 Loader::register()方法注册自动加载,在这一步完成后,所有符合规范的类库(包括Composer依赖加载的第三方类库)都将自动加载。
一个类库的自动加载检测顺序为:
是否定义类库映射;
PSR-4自动加载检测;
PSR-0自动加载检测;
可以看到,定义类库映射的方式是最高效的。
# 注册错误和异常处理机制
~~~
// 注册错误和异常处理机制
\think\Error::register();
~~~
~~~
error_reporting(E_ALL);
//设置用户定义的错误处理函数:
set_error_handler([__CLASS__, 'appError']);
//设置用户定义的异常处理函数:
set_exception_handler([__CLASS__, 'appException']);
register_shutdown_function([__CLASS__, 'appShutdown']);
~~~
由三部分组成:
应用关闭方法:think\Error::appShutdown
错误处理方法:think\Error::appError
异常处理方法:think\Error::appException
> 注册应用关闭方法是为了便于拦截一些系统错误。
在整个应用请求的生命周期过程中,如果抛出了异常或者严重错误,均会导致应用提前结束,并响应输出异常和错误信息
* 加载惯例配置文件;
~~~
// 加载惯例配置文件
\think\Config::set(include THINK_PATH . 'convention' . EXT);
~~~
# 5、应用初始化
~~~
// 2. 执行应用
App::run()->send();
~~~
App::run()
初始化一个$request-->处理->>>返回处理的$response
$response->send()
系统会调用Response::send方法将最终的应用返回的数据输出到页面或者客户端,并自动转换成default_return_type参数配置的格式。
执行应用的第一步操作就是对应用进行初始化,包括:
* 实例化$request对象;
* 加载应用(公共)配置;
`$config = self::initCommon();`
* 读取数据库配置文件
* 加载扩展配置文件(由extra_config_list定义)extra目录;
* 加载应用状态配置;
` 'APP_STATUS' => 'test', `
> 系统会自动尝试加载项目配置目录下面的test.php 配置文件
* 加载别名定义;
* 加载行为定义;
> tags文件
* 加载公共(函数)文件;
> include common.php文件
* 加载扩展函数文件(由extra_file_list定义);
> THINK_PATHhelper助手文件
* 注册应用命名空间;
* 设置默认时区;
* 加载系统语言包;
# 7、路由检测
如果开启了url_route_on参数的话,会首先进行URL的路由检测。
如果一旦检测到匹配的路由,根据定义的路由地址会注册到相应的URL调度。
5.0的路由地址支持如下方式:
* 路由到模块/控制器/操作;
* 路由到外部重定向地址;
* 路由到控制器方法;
* 路由到闭包函数;
* 路由到类的方法;
# 8、分发请求
# 这里会初始化模块,同上应用初始化
在完成了URL检测和路由检测之后,路由器会分发请求到对应的路由地址,这也是应用请求的生命周期中最重要的一个环节。
在这一步骤中,完成应用的业务逻辑及数据返回。
建议统一使用return返回数据,而不是echo输出,如非必要,请不要使用exit或者die中断执行。
下面是系统支持的分发请求机制,可以根据情况选择:
模块/控制器/操作
这是默认的分发请求机制,系统会根据URL或者路由地址来判断当前请求的模块、控制器和操作名,并自动调用相应的访问控制器类,执行操作对应的方法。
该机制下面,首先会判断当前模块,并进行模块的初始化操作(和应用的初始化操作类似),模块的配置参数会覆盖应用的尚未生效的配置参数。
支持模块映射、URL参数绑定到方法,以及操作绑定到类等一些功能。
控制器方法
和前一种方式类似,只是无需判断模块、控制器和操作,直接分发请求到一个指定的控制器类的方法,因此没有进行模块的初始化操作。
外部重定向
可以直接分发请求到一个外部的重定向地址,支持指定重定向代码,默认为301重定向。
闭包函数
路由地址定义的时候可以直接采用闭包函数,完成一些相对简单的逻辑操作和输出。
类的方法
除了以上方式外,还支持分发请求到类的方法,包括:
静态方法: 'blog/:id'=>'\org\util\Blog::read'
类的方法:'blog/:id'=>'\app\index\controller\Blog@read'
# 9、响应输出
控制器的所有操作方法都是return返回而不是直接输出,系统会调用Response::send方法将最终的应用返回的数据输出到页面或者客户端,并自动转换成default_return_type参数配置的格式。所以,应用执行的数据输出只需要返回一个正常的PHP数据即可。