入口文件index.php:


// 定义应用目录
define('APP_PATH', __DIR__ . '/../application/');
// 加载框架引导文件
require __DIR__ . '/../thinkphp/start.php';

引导文件start.php:


namespace think; // 加载基础文件
require __DIR__ . '/base.php';
// 执行应用
App::run()->send();

基础文件base.php:


defined('THINK_PATH') or define('THINK_PATH', __DIR__ . DS);
define('LIB_PATH', THINK_PATH . 'library' . DS);
define('CORE_PATH', LIB_PATH . 'think' . DS);
// 此处省略一堆的define... // 载入Loader类
require CORE_PATH . 'Loader.php';
// 注册自动加载
\think\Loader::register();

think\App::run:


public static function run(Request $request = null)
{
is_null($request) && $request = Request::instance();
$config = self::initCommon(); // 获取应用调度信息
$dispatch = self::routeCheck($request, $config);
// 记录当前调度信息
$request->dispatch($dispatch);
// 执行调度
$data = self::exec($dispatch, $config); // 输出数据到客户端
if ($data instanceof Response) {
$response = $data;
} elseif (!is_null($data)) {
// 默认自动识别响应输出类型
$isAjax = $request->isAjax();
$type = $isAjax ? Config::get('default_ajax_return') : Config::get('default_return_type');
$response = Response::create($data, $type);
} else {
$response = Response::create();
} return $response;
}

routeCheck拿到$_SERVER['PATH_INFO']获取控制器和操作名,返回格式:


array(2) {
["type"] => string(6) "module"
["module"] => array(3) {
[0] => NULL
[1] => string(5) "index"
[2] => string(5) "hello"
}
}

exec()调用module()通过反射来实例化控制器和执行操作:


protected static function exec($dispatch, $config)
{
$data = self::module($dispatch['module'], $config);
return $data;
} /**
* 执行模块
* @access public
* @param array $result 模块/控制器/操作
* @param array $config 配置参数
* @param bool $convert 是否自动转换控制器和操作名
* @return mixed
*/
public static function module($result, $config)
{
// 获取控制器名
$controller = strip_tags($result[1] ?: $config['default_controller']);
// 获取操作名
$action = strip_tags($result[2] ?: $config['default_action']);
// 实例化控制器
$instance = self::invokeClass($controller);
// 执行控制器方法
return self::invokeMethod([$instance, $action]);
} /**
* 调用反射执行类的实例化 支持依赖注入
* @access public
* @param string $class 类名
* @param array $vars 变量
* @return mixed
*/
public static function invokeClass($class, $vars = [])
{
$reflect = new \ReflectionClass($class);
$constructor = $reflect->getConstructor();
if ($constructor) {
$args = self::bindParams($constructor, $vars);
} else {
$args = [];
}
return $reflect->newInstanceArgs($args);
} /**
* 调用反射执行类的方法 支持参数绑定
* @access public
* @param string|array $method 方法
* @param array $vars 变量
* @return mixed
*/
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);
}
$args = self::bindParams($reflect, $vars); return $reflect->invokeArgs(isset($class) ? $class : null, $args);
}

最终run()获得Response对象,调用Response->send()方法输出数据

结论

$_SERVER['PATH_INFO']获得模块/控制器/操作,通过反射实例化控制器并执行操作

疑问

为什么没有直接用autoload来调度控制器呢?

缺点

不支持单模块和多模块并存,配置文件需要指定是否多模块,我觉得可以做成共存,这样很容易实现控制器的复用,比如

  • Application/controller/Index.php
  • Application/a/controller/Index.php

当url为:/a/index/index,优先执行a模块Application/a/controller/Index的index方法,如果a模块不存在这个方法,调用外围的Application/controller/Index下的index方法

thinkphp5源码解析(2)控制器的更多相关文章

  1. thinkphp5源码解析(1)数据库

    前言 tp5的数据库操作全部通过Db类完成,比较符合国人的习惯,比如简单的Db::query().Db::execute(),还有复杂的链式操作Db::where('id=1')->select ...

  2. .NET Core实战项目之CMS 第三章 入门篇-源码解析配置文件及依赖注入

    作者:依乐祝 原文链接:https://www.cnblogs.com/yilezhu/p/9998021.html 写在前面 上篇文章我给大家讲解了ASP.NET Core的概念及为什么使用它,接着 ...

  3. laravel源码解析

    本专栏系列文章已经收录到 GitBooklaravel源码解析 Laravel Passport——OAuth2 API 认证系统源码解析(下)laravel源码解析 Laravel Passport ...

  4. Spring5源码解析-论Spring DispatcherServlet的生命周期

    Spring Web框架架构的主要部分是DispatcherServlet.也就是本文中重点介绍的对象. 在本文的第一部分中,我们将看到基于Spring的DispatcherServlet的主要概念: ...

  5. spring 源码解析

    1. [文件] spring源码.txt ~ 15B     下载(167) ? 1 springн┤┬вио╬Ш: 2. [文件] spring源码分析之AOP.txt ~ 15KB     下载( ...

  6. SpringBoot之DispatcherServlet详解及源码解析

    在使用SpringBoot之后,我们表面上已经无法直接看到DispatcherServlet的使用了.本篇文章,带大家从最初DispatcherServlet的使用开始到SpringBoot源码中Di ...

  7. Laravel框架下路由的使用(源码解析)

    本篇文章给大家带来的内容是关于Laravel框架下路由的使用(源码解析),有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助. 前言 我的解析文章并非深层次多领域的解析攻略.但是参考着开发文 ...

  8. .Net Core 认证系统之基于Identity Server4 Token的JwtToken认证源码解析

    介绍JwtToken认证之前,必须要掌握.Net Core认证系统的核心原理,如果你还不了解,请参考.Net Core 认证组件源码解析,且必须对jwt有基本的了解,如果不知道,请百度.最重要的是你还 ...

  9. AspNetCore3.1_Secutiry源码解析_2_Authentication_核心对象

    系列文章目录 AspNetCore3.1_Secutiry源码解析_1_目录 AspNetCore3.1_Secutiry源码解析_2_Authentication_核心项目 AspNetCore3. ...

随机推荐

  1. 运行所选代码生成器时出错:“预期具有协定名称 "NuGet.VisualStudio.IVsPackageInstallerServices" 的1导出 ——VS2015错误记录

    在编写ASP.NET MVC控制器后,右键添加视图时,VS2015报出错误: 运行所选代码生成器时出错:“预期具有协定名称 "NuGet.VisualStudio.IVsPackageIns ...

  2. 剑指offer试题(PHP篇一)

    1.二维数组中的查找 题目描述 在一个二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序.请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数. ...

  3. CentOS7中关闭firewall,并使用iptables管理防火墙

    背景描述 在使用Docker时,启用centos7默认的firewall,启动端口映射时,防火墙规则不生效.docker默认使用了iptables防火墙机制.所以需要关闭firewall使用iptab ...

  4. python入门学习笔记(三)

    10.函数 求绝对值的函数 abs(x) 也可以在交互式命令行通过 help(abs) 查看abs函数的帮助信息.调用 abs 函数:>>> abs(100)100>>& ...

  5. 怎样才能收集到所有开发人员的blog(待续…)

    第一个问题,如何找到尽可能多的博客地址? 1. 找到一个知名blog, 遍历这个博客的外链. 2. 遍历找到的外链,并以同样逻辑找到其他博客. 3. 如果遍历到的博客地址已经存在则停止遍历. 还有一种 ...

  6. ASP.NET与ASP.NET MVC 的差异、优点及缺点

    众所周知,在微软的编程语言发展历史中,asp.net是不得不提的一个重要的发展阶段,它具有快速开发.层级明确的优点,但最大的缺点,同时也是它逐渐被废弃的原因就是,页面加载的viewstate过于庞大, ...

  7. Egret学习笔记 (Egret打飞机-3.实现背景循环滚动)

    游戏背景里面的猪脚飞机看起来是一直在向前飞,但是实际上只是一个视觉差而已. 猪脚是出于不动的状态,背景从上到下滚动,然后让玩家觉得飞机在不停的往前飞.(当然这只是其中一种实现思路) 差不多就是这样,然 ...

  8. windows转mac-开发环境搭建(二):mac上java环境搭建

    1.首先下载jdk,地址:http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html 2.安 ...

  9. 吾八哥学Selenium(三):操作复选框checkbox/单选框radio的方法

    复选框checkbox和单选框radio是web网站里经常会使用到的两个控件,那么在web自动化测试的时候如何利用Selenium来操作这俩控件呢?今天我们就来简单入门练习一下! html测试页面代码 ...

  10. ssh (Spring , Struts2 , Hibernate)框架的配置使用

    思维导图(基本配置) 1. 需要引入的包 2 .spring-config.xml 的配置 <!-- 链接数据库 外部配置文件扫入 --> <context:property-ove ...