Thinkphp5源码分析2--App.php 框架入口类

// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: liu21st
// +----------------------------------------------------------------------

namespace think;

use think\exception\ ClassNotFoundException;
use think\exception\ HttpException;
use think\exception\ HttpResponseException;
use think\exception\ RouteNotFoundException;

/**
* App 应用管理
* @author liu21st
*/

class App
{
/**
* @var bool 是否初始化过
*/
protected static $init = false;

/**
* @var string 当前模块路径
*/
public static $modulePath;

/**
* @var bool 应用调试模式
*/
public static $debug = true;

/**
* @var string 应用类库命名空间
*/
public static $namespace = 'app';

/**
* @var bool 应用类库后缀
*/
public static $suffix = false;

/**
* @var bool 应用路由检测
*/
protected static $routeCheck;

/**
* @var bool 严格路由检测
*/
protected static $routeMust;

/**
* @var array 请求调度分发
*/
protected static $dispatch;

/**
* @var array 额外加载文件
*/
protected static $file = [];

/**
* 执行应用程序
* @access public
* @param Request $request 请求对象
* @return Response
* @throws Exception
*/

//thinkphp5框架入口,执行run方法
public static function run( Request $request = null)
{
//返回实例think\Request方法,该方法在thinkphp\library\think\Request.php中
$request = is_null( $request) ? Request:: instance() : $request;
//捕获异常
try {
// 执行当前类的initCommon方法,返回 \thinkphp\convention.php里的全部配置信息
$config = self:: initCommon();
// 模块/控制器绑定
if ( defined( 'BIND_MODULE')) {
BIND_MODULE && Route:: bind(BIND_MODULE);

// \thinkphp\convention.php配置里auto_bind_module参数设为true时执行,默认不执行
} elseif ( $config[ 'auto_bind_module']) {
// 入口自动绑定
$name = pathinfo( $request-> baseFile(), PATHINFO_FILENAME);
if ( $name && 'index' != $name && is_dir(APP_PATH . $name)) {
Route:: bind( $name);
}
}

//thinkphp\convention.php配置里default_filter参数设为true时执行,默认不执行
$request-> filter( $config[ 'default_filter']);

// 默认语言
Lang:: range( $config[ 'default_lang']);

// 开启多语言机制 检测当前语言
$config[ 'lang_switch_on'] && Lang:: detect();
$request-> langset( Lang:: range());

// 加载系统语言包
Lang:: load([
THINK_PATH . 'lang' . DS . $request-> langset() . EXT,
APP_PATH . 'lang' . DS . $request-> langset() . EXT,
]);
// 监听 app_dispatch
Hook:: listen( 'app_dispatch', self:: $dispatch);
// 获取应用调度信息
$dispatch = self:: $dispatch;
// 未设置调度信息则进行 URL 路由检测
if ( empty( $dispatch)) {
/*执行当前类的routeCheck方法,获取调度信息,如访问index模块下index控制器里的index方法,则
$dispatch = array(2) { ["type"]=> string(6) "module"
["module"]=> array(3) {
[0]=> string(5) "index" [1]=> string(5) "index" [2]=> string(5) "index" } }
*/
$dispatch = self:: routeCheck( $request, $config);
}
// 记录当前调度信息 将获取的调度信息,即模块,控制器,方法名存入Request类的dispatch属性中
$request-> dispatch( $dispatch);
// 记录路由和请求信息 ,调式模式,在\application\config.php 参数app_debug可配置
if ( self:: $debug) {

//将调度信息写入日志 ,执行\thinkphp\library\think\Log.php 中 Log类的record方法
Log:: record( '[ ROUTE ] ' . var_export( $dispatch, true), 'info');

/*将\thinkphp\library\think\Request.php Request类中header方法
获取的头部信息写入日志 */
Log:: record( '[ HEADER ] ' . var_export( $request-> header(), true), 'info');

//记录当前请求的参数
Log:: record( '[ PARAM ] ' . var_export( $request-> param(), true), 'info');
}
// 监听 app_begin
Hook:: listen( 'app_begin', $dispatch);
// 请求缓存检查
$request-> cache(
$config[ 'request_cache'],
$config[ 'request_cache_expire'],
$config[ 'request_cache_except']
);
//执行当前类的exec方法
$data = self:: exec( $dispatch, $config);
} catch ( HttpResponseException $exception) {

$data = $exception-> getResponse();

}

// 清空类的实例化
Loader:: clearInstance();
// 输出数据到客户端 判断$data是否为Response类的实例
if ( $data instanceof Response) {
$response = $data;
} elseif (! is_null( $data)) {
// 默认自动识别响应输出类型
$type = $request-> isAjax() ?
Config:: get( 'default_ajax_return') :
Config:: get( 'default_return_type');
/* 这句代码是整个框架的核心,$data 是获得反射类的实例,假如访问的是index模块下的index控制器中index方法
$data = new app\index\controller\Index();$data = $data->index();
为什么tp框架要用反射来执行类的方法? 当前App.php的命名空间是think,而控制器的命名空间是app\index\controller
反射很好的解决了执行不同命名空间下的类,反射可以简单地理解为实例化类后执行类中的方法。
具体可以查看本类的 invokeFunction invokeMethod invokeClass三个方法。
将返回的反射实例$data,也就是 app\index\controller\Index下的index方法,
存入 \thinkphp\library\think\Response.php Response类中的$data属性
*/
$response = Response:: create( $data, $type);

} else {
$response = Response:: create();
}

// 监听 app_end
Hook:: listen( 'app_end', $response);
//返回返回的反射实例
return $response;
}

/**
* 初始化应用,并返回配置信息
* @access public
* @return array
*/

public static function initCommon()
{
// 当前类中的init变量默认为false,也就是空,执行以下语句
if ( empty( self:: $init)) {
/*判断APP_NAMESPACE这个常量是否存在,默认APP_NAMESPACE不存在,无需执行此语句,如要配置,
可在thinkphp\base.php下加上 define('APP_NAMESPACE', 'application');*/
if ( defined( 'APP_NAMESPACE')) {
//若配置APP_NAMESPACE,则当前类的$namespace变量修改为所配置的值
self:: $namespace = APP_NAMESPACE;
}
/*self::$namespace当前类的namespace属性,APP_PATH: application目录路径,
执行先前载入的\thinkphp\library\think\Loader.php文件Loader类中addNamespace方法*/
Loader:: addNamespace( self:: $namespace, APP_PATH);
// 初始化应用,执行当前类的init方法,加载配置文件
$config = self:: init();
self:: $suffix = $config[ 'class_suffix'];
// 应用调试模式
self:: $debug = Env:: get( 'app_debug', Config:: get( 'app_debug'));
if (! self:: $debug) {
//设置错误信息的类别, ini_set用来设置php.ini的值,在脚本运行时保持新的值,并在脚本结束时恢复
ini_set( 'display_errors', 'Off');
} elseif (!IS_CLI) {
// 重新申请一块比较大的 buffer
if ( ob_get_level() > 0) {
$output = ob_get_clean();
}

ob_start();

if (! empty( $output)) {
echo $output;
}

}

if (! empty( $config[ 'root_namespace'])) {
Loader:: addNamespace( $config[ 'root_namespace']);
}

// 加载额外文件
if (! empty( $config[ 'extra_file_list'])) {
foreach ( $config[ 'extra_file_list'] as $file) {
$file = strpos( $file, '.') ? $file : APP_PATH . $file . EXT;
if ( is_file( $file) && ! isset( self:: $file[ $file])) {
include $file;
self:: $file[ $file] = true;
}
}
}

// 设置系统时区
date_default_timezone_set( $config[ 'default_timezone']);

// 监听 app_init
Hook:: listen( 'app_init');

self:: $init = true;
}

return Config:: get();
}

/**
* 初始化应用或模块
* @access public
* @param string $module 模块名
* @return array
*/
//此方法主要载入application和模块中配置文件的信息
private static function init( $module = '')
{
// 定位模块目录
$module = $module ? $module . DS : '';
/* \tpfive\public/../application/init.php
加载初始化文件 ,判断application目录下是否存在init.php */
if ( is_file(APP_PATH . $module . 'init' . EXT)) {
include APP_PATH . $module . 'init' . EXT;

//判断runtime目录下是否存在init.php
} elseif ( is_file(RUNTIME_PATH . $module . 'init' . EXT)) {
//载入init.php文件
include RUNTIME_PATH . $module . 'init' . EXT;
} else {
/* $module值为空时获取application目录下的config.php里全部配置信息,$module有值时,
则获取$module,也就是模块目录下config.php里的配置,所以配置写在模块里面的config.php也是可用的 */
$config = Config:: load(CONF_PATH . $module . 'config' . CONF_EXT);
// 读取数据库配置文件 application目录下的database.php
$filename = CONF_PATH . $module . 'database' . CONF_EXT;
Config:: load( $filename, 'database');
// 读取扩展配置文件 判断是否存在application目录下extra目录
if ( is_dir(CONF_PATH . $module . 'extra')) {
$dir = CONF_PATH . $module . 'extra';
$files = scandir( $dir);
foreach ( $files as $file) {
if ( '.' . pathinfo( $file, PATHINFO_EXTENSION) === CONF_EXT) {
$filename = $dir . DS . $file;
//载入 \application\extra下配置文件
Config:: load( $filename, pathinfo( $file, PATHINFO_FILENAME));
}
}
}

// 加载应用状态配置
if ( $config[ 'app_status']) {
Config:: load(CONF_PATH . $module . $config[ 'app_status'] . CONF_EXT);
}
/* 加载行为扩展文件 $module值为空时,判断application\tags.php
有值时判断$module也就是地址栏模块下tags.php是否存在*/
if ( is_file(CONF_PATH . $module . 'tags' . EXT)) {
/*application目录下的tags.php,执行\thinkphp\library\think\Hook.php Hook类中的import方法
传入参数为\application\tags.php 和地址栏模块下tags.php中的全部配置信息,
把参入参数的配置信息赋值到Hook类的$tags静态属性中*/
Hook:: import( include CONF_PATH . $module . 'tags' . EXT);
}

// 加载公共文件
$path = APP_PATH . $module;

//判断\application\common.php 或地址栏模块下common.php是否存在
if ( is_file( $path . 'common' . EXT)) {

//载入\application\common.php 和地址栏模块下common.php中的配置信息
include $path . 'common' . EXT;
}

// 加载当前模块语言包
if ( $module) {
Lang:: load( $path . 'lang' . DS . Request:: instance()-> langset() . EXT);
}

}
//返回所有配置信息
return Config:: get();
}

/**
* 设置当前请求的调度信息
* @access public
* @param array | string $dispatch 调度信息
* @param string $type 调度类型
* @return void
*/
public static function dispatch( $dispatch, $type = 'module')
{
self:: $dispatch = [ 'type' => $type, $type => $dispatch];
}

/**
* 执行函数或者闭包方法 支持参数调用
* @access public
* @param string | array |\ Closure $function 函数或者闭包
* @param array $vars 变量
* @return mixed
*/
public static function invokeFunction( $function, $vars = [])
{
$reflect = new \ReflectionFunction( $function);
$args = self:: bindParams( $reflect, $vars);

// 记录执行信息
self:: $debug && Log:: record( '[ RUN ] ' . $reflect-> __toString(), 'info');

return $reflect-> invokeArgs( $args);
}

/**
* 调用反射执行类的方法 支持参数绑定
* @access public
* @param string | array $method 方法
* @param array $vars 变量
* @return mixed
*/
/*反射类的方法 $method = array(2) {
[0]=> object(app\index\controller\Index)#5 (0) { } [1]=> string(5) "index" } */
public static function invokeMethod( $method, $vars = [])
{
//首先判断传递的第一个参数是否为数组
if ( is_array( $method)) {
$class = is_object( $method[ 0]) ? $method[ 0] : self:: invokeClass( $method[ 0]);
//实例化反射类中的方法
$reflect = new \ReflectionMethod( $class, $method[ 1]);
} else {
// 静态方法
$reflect = new \ReflectionMethod( $method);
}
//执行当前类的bindParams方法
$args = self:: bindParams( $reflect, $vars);

//将当前反射类的信息写入日志
self:: $debug && Log:: record( '[ RUN ] ' . $reflect-> class . '->' . $reflect-> name . '[ ' . $reflect-> getFileName() . ' ]', 'info');
//执行反射类中的方法,并返回
return $reflect-> invokeArgs( isset( $class) ? $class : null, $args);
}

/**
* 调用反射执行类的实例化 支持依赖注入
* @access public
* @param string $class 类名
* @param array $vars 变量
* @return mixed
*/

//反射操作 $class = ''app\index\controller\Index';
public static function invokeClass( $class, $vars = [])
{
/* ReflectionClass函数是建立 $class 这个反射类,假设$class = 'app\index\controller\Index';
也就是实例化 new app\index\controller\Index; */
$reflect = new \ReflectionClass( $class);

//getConstructor 获取类的构造函数
$constructor = $reflect-> getConstructor();
//传入类的构造函数,执行本类的bindParams方法
$args = $constructor ? self:: bindParams( $constructor, $vars) : [];
//newInstanceArgs 创建一个类的新实例,给出的参数将传递到类的构造函数
return $reflect-> newInstanceArgs( $args);
}

/**
* 绑定参数
* @access private
* @param \ReflectionMethod | \ReflectionFunction $reflect 反射类
* @param array $vars 变量
* @return array
*/
/* $reflect 为实例化反射类中的方法 ,假设访问index模块下index控制器中的index方法,
$reflect = new app\index\controller\Index(); $reflect = $reflect->index(); */
private static function bindParams( $reflect, $vars = [])
{
//自动获取请求变量
if ( empty( $vars)) {
/* 'url_param_type在\application\config.php配置
// URL参数方式 0 按名称成对解析 1 按顺序解析
'url_param_type' => 0,默认$vars 获取路由规则或参数配置
*/
$vars = Config:: get( 'url_param_type') ?
Request:: instance()-> route() :
Request:: instance()-> param();
}
$args = [];

//getNumberOfParameters 获取构造函数参数的个数
if ( $reflect-> getNumberOfParameters() > 0) {
// 判断数组类型 数字数组时按顺序绑定参数
reset( $vars);
$type = key( $vars) === 0 ? 1 : 0;
//getParameters 获取函数全部参数
foreach ( $reflect-> getParameters() as $param) {
//循环遍历,作为参数传递给当前类的getParamValue方法
$args[] = self:: getParamValue( $param, $vars, $type);
}
}
//返回处理后的参数
return $args;
}

/**
* 获取参数值
* @access private
* @param \ReflectionParameter $param 参数
* @param array $vars 变量
* @param string $type 类别
* @return array
*/
private static function getParamValue( $param, & $vars, $type)
{
$name = $param-> getName();
$class = $param-> getClass();
//执行反射类的方法
if ( $class) {
$className = $class-> getName();
$bind = Request:: instance()-> $name;

if ( $bind instanceof $className) {
$result = $bind;
} else {
if ( method_exists( $className, 'invoke')) {
$method = new \ReflectionMethod( $className, 'invoke');

if ( $method-> isPublic() && $method-> isStatic()) {
return $className:: invoke( Request:: instance());
}
}

$result = method_exists( $className, 'instance') ?
$className:: instance() :
new $className;
}
} elseif ( 1 == $type && ! empty( $vars)) {
$result = array_shift( $vars);
} elseif ( 0 == $type && isset( $vars[ $name])) {
$result = $vars[ $name];

//解析执行类构造函数时执行
} elseif ( $param-> isDefaultValueAvailable()) {
//getDefaultValue拿到构造函数参数的值
$result = $param-> getDefaultValue();
} else {
throw new \InvalidArgumentException( 'method param miss:' . $name);
}

return $result;
}

/**
* 执行调用分发
* @access protected
* @param array $dispatch 调用信息
* @param array $config 配置信息
* @return Response | mixed
* @throws \InvalidArgumentException
*/
protected static function exec( $dispatch, $config)
{
switch ( $dispatch[ 'type']) {
case 'redirect': // 重定向跳转
$data = Response:: create( $dispatch[ 'url'], 'redirect')
-> code( $dispatch[ 'status']);
break;
case 'module': // 模块/控制器/操作
$data = self:: module(
$dispatch[ 'module'],
$config,
isset( $dispatch[ 'convert']) ? $dispatch[ 'convert'] : null
);
break;
case 'controller': // 执行控制器操作
$vars = array_merge( Request:: instance()-> param(), $dispatch[ 'var']);
$data = Loader:: action(
$dispatch[ 'controller'],
$vars,
$config[ 'url_controller_layer'],
$config[ 'controller_suffix']
);
break;
case 'method': // 回调方法
$vars = array_merge( Request:: instance()-> param(), $dispatch[ 'var']);
$data = self:: invokeMethod( $dispatch[ 'method'], $vars);
break;
case 'function': // 闭包
$data = self:: invokeFunction( $dispatch[ 'function']);
break;
case 'response': // Response 实例
$data = $dispatch[ 'response'];
break;
default:
throw new \InvalidArgumentException( 'dispatch type not support');
}
return $data;
}

/**
* 执行模块
* @access public
* @param array $result 模块/控制器/操作
* @param array $config 配置参数
* @param bool $convert 是否自动转换控制器和操作名
* @return mixed
* @throws HttpException
*/

// 开始调度,获取地址栏参数信息,$config为\thinkphp\convention.php里的配置信息
public static function module( $result, $config, $convert = null)
{
//判断传递过来的$result是否为字符串
if ( is_string( $result)) {
$result = explode( '/', $result);
}
//实例化think\Request, 该类在thinkphp\library\think目录下Request.php
$request = Request:: instance();
//判断application目录下的config.php参数中的app_multi_module是否为true,
if( $config[ 'app_multi_module']){
/* 多模块部署,$result[0] 是否有参数,没有则通过\thinkphp\convention.php下的default_module参数
获取,config可设置default_module,就是默认模块,$module默认值为index */
$module = strip_tags( strtolower( $result[ 0] ?: $config[ 'default_module']));
$bind = Route:: getBind( 'module');

// 先设置available变量,判断模块是否允许访问
$available = false;
if ( $bind) {
// 绑定模块
list( $bindModule) = explode( '/', $bind);

if ( empty( $result[ 0])) {
$module = $bindModule;
$available = true;
} elseif ( $module == $bindModule) {
$available = true;
}

/* 寻找配置中的deny_module_list是否与$module的值对应,deny_module_list在配置application下的
config.php可设置, deny_module_list默认是common,也就是commmon这个模块禁止访问, 不执行以下语句,
那$available的值为false ,并且application目录下$module文件夹是否存在 */
} elseif (! in_array( $module, $config[ 'deny_module_list']) && is_dir(APP_PATH . $module)) {
//deny_module_list数组中没有找到该模块值,并且该模块文件是存在的,那$available的值会为true
$available = true;
}
// 模块初始化 ,module和available有值时执行,上面语句将 $available设置为true,
// $available的值就为1,并且$module有值,则执行以下语句
if ( $module && $available) {
// 初始化模块 实例化thinkphp\library\think目录下Request.php中Request类的module方法
$request-> module( $module);
//获取\thinkphp\convention.php和\application\extra\queue.php的全部配置信息
$config = self:: init( $module);
// 模块请求缓存检查
$request-> cache(
$config[ 'request_cache'],
$config[ 'request_cache_expire'],
$config[ 'request_cache_except']
);
} else {
//找不到模块或模块文件不存在,抛出异常
throw new HttpException( 404, 'module not exists:' . $module);
}
} else {
// 单一模块部署
$module = '';
$request-> module( $module);
}
// 设置默认过滤机制
$request-> filter( $config[ 'default_filter']);
// 当前模块路径 存入当前类$modulePath属性中
App:: $modulePath = APP_PATH . ( $module ? $module . DS : '');
// 是否自动转换控制器和操作名 is_bool — 检测变量是否是布尔型
$convert = is_bool( $convert) ? $convert : $config[ 'url_convert'];
// 获取控制器名 application下的config.php中的参数default_controller的值,默认为index
$controller = strip_tags( $result[ 1] ?: $config[ 'default_controller']);
//判断是否为自动转换控制器
$controller = $convert ? strtolower( $controller) : $controller;

// 获取操作名 application下的config.php中的参数default_action的值,默认为index
$actionName = strip_tags( $result[ 2] ?: $config[ 'default_action']);
if (! empty( $config[ 'action_convert'])) {
$actionName = Loader:: parseName( $actionName, 1);
} else {
$actionName = $convert ? strtolower( $actionName) : $actionName;
}
// 设置当前请求的控制器、操作
$request-> controller( Loader:: parseName( $controller, 1))-> action( $actionName);

// 开始监听模块
Hook:: listen( 'module_init', $request);

/*
$controller 控制器名
$config['url_controller_layer'] = 'controller';
$config['controller_suffix'] = 'false';
//空控制器名
$config['empty_controller'] = 'Error';

先开始执行类的反射 \thinkphp\library\think\Loader.php 中Loader类的controller方法
*/
try {
//返回app\index\controller\Index类的实例
$instance = Loader:: controller(
$controller,
$config[ 'url_controller_layer'],
$config[ 'controller_suffix'],
$config[ 'empty_controller']
);
} catch ( ClassNotFoundException $e) {
throw new HttpException( 404, 'controller not exists:' . $e-> getClass());
}
// 获取当前操作名 action_suffix操作方法后缀,\application\config.php配置
$action = $actionName . $config[ 'action_suffix'];

$vars = [];
//is_callable — 检测参数是否为合法的可调用结构
if ( is_callable([ $instance, $action])) {

// 执行操作方法
$call = [ $instance, $action];
// 严格获取当前操作方法名 ReflectionMethod 报告了一个方法的有关信息
$reflect = new \ReflectionMethod( $instance, $action);

//获取操作名(方法名)
$methodName = $reflect-> getName();

$suffix = $config[ 'action_suffix'];
$actionName = $suffix ? substr( $methodName, 0, - strlen( $suffix)) : $methodName;

//把操作方法存入Request类action 属性中
$request-> action( $actionName);

} elseif ( is_callable([ $instance, '_empty'])) {
// 空操作
$call = [ $instance, '_empty'];
$vars = [ $actionName];
} else {
// 操作不存在
throw new HttpException( 404, 'method not exists:' . get_class( $instance) . '->' . $action . '()');
}

//监听执行类
Hook:: listen( 'action_begin', $call);
//执行反射类中的方法 当前类的invokeMethod方法
return self:: invokeMethod( $call, $vars);
}

/**
* URL路由检测(根据PATH_INFO)
* @access public
* @param \think\ Request $request 请求实例
* @param array $config 配置信息
* @return array
* @throws \think\ Exception
*/
//解析地址栏参数
public static function routeCheck( $request, array $config)
{
//获取访问的地址栏参数
$path = $request-> path();

/* $depr='/',pathinfo_depr为'/' \application\config.php中可查看pathinfo_depr */
$depr = $config[ 'pathinfo_depr'];
$result = false;

/*路由检测 如果当前类$routeCheck不为空,$check值为当前类$routeCheck的值,否则为true
\application\config.php中可查看url_route_on */
$check = ! is_null( self:: $routeCheck) ? self:: $routeCheck : $config[ 'url_route_on'];

//$check有值时执行
if ( $check) {
// 开启路由 \runtime\route.php存在时执行
if ( is_file(RUNTIME_PATH . 'route.php')) {
// 读取路由缓存
$rules = include RUNTIME_PATH . 'route.php';
is_array( $rules) && Route:: rules( $rules);

//\runtime\route.php不存在时执行
} else {

/* // 路由配置文件(支持配置多个)
'route_config_file' => ['route'],
route_config_file 可在 \application\config.php中配置
*/
$files = $config[ 'route_config_file'];
//可载入多个路由配置文件
foreach ( $files as $file) {
if ( is_file(CONF_PATH . $file . CONF_EXT)) {
// 导入路由配置 默认只导入/application/route.php,载入多个在route_config_file中配置
$rules = include CONF_PATH . $file . CONF_EXT;

/*首先判断$rules变量是否是数组,如果是则执行
\thinkphp\library\think\Route.php Route中import类,并将配置作为参数传入 */
is_array( $rules) && Route:: import( $rules);
}
}
}
/* 路由检测(根据路由定义返回不同的URL调度)
$request 为 \think\Request的实例;
$path 经框架处理,$path = public/index.php/后面的参数 例如:
访问index模块下index控制器里的index方法,则$path = 'index/index/index';
$depr = '/'
$config['url_domain_deploy'] = 'false'; (\application\config/php可以配置url_domain_deploy)
执行Route类中静态方法check,并把上述变量传入
*/
$result = Route:: check( $request, $path, $depr, $config[ 'url_domain_deploy']);
$must = ! is_null( self:: $routeMust) ? self:: $routeMust : $config[ 'url_route_must'];
if ( $must && false === $result) {
// 路由无效
throw new RouteNotFoundException();
}
}

// 路由无效 解析模块/控制器/操作/参数... 支持控制器自动搜索
if ( false === $result) {
//执行当前Route类的parseUrl方法,返回模块控制器和方法名
$result = Route:: parseUrl( $path, $depr, $config[ 'controller_auto_search']);
}

return $result;
}

/**
* 设置应用的路由检测机制
* @access public
* @param bool $route 是否需要检测路由
* @param bool $must 是否强制检测路由
* @return void
*/
public static function route( $route, $must = false)
{
self:: $routeCheck = $route;
self:: $routeMust = $must;
}
}

你可能感兴趣的:(Thinkphp5源码分析2--App.php 框架入口类)