thinkphp5源码解析(2)控制器
入口文件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)控制器的更多相关文章
- thinkphp5源码解析(1)数据库
前言 tp5的数据库操作全部通过Db类完成,比较符合国人的习惯,比如简单的Db::query().Db::execute(),还有复杂的链式操作Db::where('id=1')->select ...
- .NET Core实战项目之CMS 第三章 入门篇-源码解析配置文件及依赖注入
作者:依乐祝 原文链接:https://www.cnblogs.com/yilezhu/p/9998021.html 写在前面 上篇文章我给大家讲解了ASP.NET Core的概念及为什么使用它,接着 ...
- laravel源码解析
本专栏系列文章已经收录到 GitBooklaravel源码解析 Laravel Passport——OAuth2 API 认证系统源码解析(下)laravel源码解析 Laravel Passport ...
- Spring5源码解析-论Spring DispatcherServlet的生命周期
Spring Web框架架构的主要部分是DispatcherServlet.也就是本文中重点介绍的对象. 在本文的第一部分中,我们将看到基于Spring的DispatcherServlet的主要概念: ...
- spring 源码解析
1. [文件] spring源码.txt ~ 15B 下载(167) ? 1 springн┤┬вио╬Ш: 2. [文件] spring源码分析之AOP.txt ~ 15KB 下载( ...
- SpringBoot之DispatcherServlet详解及源码解析
在使用SpringBoot之后,我们表面上已经无法直接看到DispatcherServlet的使用了.本篇文章,带大家从最初DispatcherServlet的使用开始到SpringBoot源码中Di ...
- Laravel框架下路由的使用(源码解析)
本篇文章给大家带来的内容是关于Laravel框架下路由的使用(源码解析),有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助. 前言 我的解析文章并非深层次多领域的解析攻略.但是参考着开发文 ...
- .Net Core 认证系统之基于Identity Server4 Token的JwtToken认证源码解析
介绍JwtToken认证之前,必须要掌握.Net Core认证系统的核心原理,如果你还不了解,请参考.Net Core 认证组件源码解析,且必须对jwt有基本的了解,如果不知道,请百度.最重要的是你还 ...
- AspNetCore3.1_Secutiry源码解析_2_Authentication_核心对象
系列文章目录 AspNetCore3.1_Secutiry源码解析_1_目录 AspNetCore3.1_Secutiry源码解析_2_Authentication_核心项目 AspNetCore3. ...
随机推荐
- 夏令营讲课内容整理 Day 6 Part 1.
Day6讲了三个大部分的内容. 1.STL 2.初等数论 3.倍增 Part1主要与STL有关. 1.概述 STL的英文全名叫Standard Template Library,翻译成中文就叫标准 ...
- POJ 1873 The Fortified Forest [凸包 枚举]
The Fortified Forest Time Limit: 1000MS Memory Limit: 30000K Total Submissions: 6400 Accepted: 1 ...
- 用js脚本一键下载网页所有图片
年前这两天稍微闲一点了,琢磨了一点js脚本,功能是把当前网页页面上的所有图片一次性保存到本地,免得每次都要对图片右键保存. 测试环境:Chrome开发者模式下(启动Chrome,按F12即可) 测试网 ...
- python学习:递归列出目录里的文件
#!/usr/bin/python import os import sys def print_files(path): lsdir = os.listdir(path) d ...
- CentOS 7 安装 Nginx 反向代理 node
安装 nginx yum install epel-release yum install nginx 配置 nginx sudo vim /etc/nginx/nginx.conf, 改成下面配置: ...
- VS2015 (C/C++) 生成的程序,不能在server2008上运行
项目本来是为Linux下运行做的,但是客户环境需要在windows下运行,幸好用的一些库是跨平台的. 于是用vs2015编译. 然后就发现在2008上却运行时库,装了2015的运行时库后, 在运行,就 ...
- 谈谈语音通信中的各种tone
今天谈的这个主题(tone)存在于我们的日常打电话过程中.先举两个场景:1,你拿起固话话筒准备打电话,按电话号码前先从话筒里听到"嗡"的连续音,这叫dial tone(拨号音,表示 ...
- 速卖通AE平台+聚石塔+奇门 完整教程V2
公司是跨境电商,在阿里马马的速卖通平台上开有店铺,并且基于速卖通开放平台,自主研发了ERP系统,居今已有3年多的时间了,一直很稳定. 今年初,速卖通AE开放平台改版,并入淘宝开放平台中,我们的麻烦就开 ...
- B站标题/子标题/url爬取示例(requests+re)
#coding:utf-8 __author__ = "zhoumi" 3 import requests import re import urllib ''' 本文档目的在于获 ...
- 求第k小的数 O(n)复杂度
思路:利用快速排序的思想,把数组递归划分成两部分.设划分为x,数组左边是小于等于x,右边大于x.关键在于寻找一个最优的划分,经过 Blum . Floyd . Pratt . Rivest . Tar ...