Basierend auf der neuesten Version von ThinkPHP 5.0.8 wurde es ursprünglich von xmind mind map erstellt. Wenn Sie das Gefühl haben, dass das Bild nicht klar ist, können Sie die xmind-Quelldatei herunterladen und mit der xmind-Software öffnen.
Darüber hinaus befindet sich der in der Mind Map verwendete Quellcode vollständig in den Map-Notizen. Sie können ihn nur sehen, wenn Sie die xmind-Quelldatei herunterladen.
Studenten, die die ThinkPHP5-Entwicklung selbst erlernen möchten, dürfen sich diesen Vorteil nicht entgehen lassen. Programmierer, die derzeit an der Entwicklung des ThinkPHP5-Projekts arbeiten, können es zum späteren Nachschlagen speichern
1. Mindmap:
2. Textversion der Gesamtbeschreibung von die Framework-Architektur:
Framework-Architektur
1 Architekturübersicht
1.1 Basierend auf MVC-Entwurfsmuster
1.1.1 Modell: Modell
1.1.2 Ansicht:Ansicht
1.1.3 Controller: Controller
1.2 MVC-basiertes URL-Zugriffsrouting
1.2.1 http:/ /Domänenname/ Eintragsdatei/Modul/Controller/Operation/Parameter/Wert...
1.3 Eintragsdatei
1.3.1 Most allgemein: index .php
1.3.2 Sie können andere Eintragsdateien an das Modul binden, wie zum Beispiel: admin.php
1.4 Anwendungs-App
1.4.1 Objekte, die den Framework-Lebenszyklus verwalten: thinkApp-Klasse
1.4.2 Von der Eintragsdatei aufgerufen und ausgeführt
1.4.3 Anwendungsverzeichnisse mit demselben APP_PATH werden als gleich betrachtet Anwendung
1.4.4 Eine Anwendung kann mehrere Eingänge haben, z. B. index.php im Frontend und admin.php im Backend
1.4.5 Die Anwendung verfügt über eine eigene unabhängige Konfigurationsdatei und öffentliche Funktionsdatei
1.5 Modul
1.5.1 Eine Anwendung besteht normalerweise aus mehreren Modulen
1.5.2 Ein Modul ist normalerweise ein Unterverzeichnis im Anwendungsverzeichnis: app/index/
1.5.3 Module bestehen normalerweise aus mehreren Controller-Klassendateien. Diese Klassen können in Verzeichnissen verwaltet werden
1.5.4 Für einfache Anwendungen. Sie müssen kein Modulverzeichnis erstellen. Verwenden Sie eine Einzelmodularchitektur und deaktivieren Sie die Multimodulunterstützung in der Anwendungskonfiguration: 'app_multi_module'=>false
1.5.5 Module können auch ihre eigenen unabhängigen Module haben Konfigurationsdateien, öffentliche Dateien und Klassenbibliotheksdateien
1.6 ControllerController
1.6.1 Der Controller ist dafür verantwortlich, auf Benutzeranfragen zu reagieren, die Modellverarbeitung aufzurufen, Auswahl der Ansichtsausgabe und sollte nicht in die Geschäftsverarbeitung eingreifen
1.6.2 Jeder Controller ist eigentlich eine Klassendatei: Index.php
1.6.3 Ab 5.0 kann der Controller ohne normal arbeiten jede übergeordnete Klasse erben
<?php namespace app\index\controller; class Index { public function index() { return 'hello,thinkphp!'; } }
1.7 Aktion
1.7.1 Ein Controller enthält mehrere Operationsmethoden, und die Operationsmethode ist die kleinste URL-Einheit Zugriff
1.7.2 Operationsmethode, falls erforderlich. Parameter müssen übergeben werden: $_GET oder $_POST
<?php namespace app\index\controller; class Index { public function index() { return 'index'; } public function hello($name) { return 'Hello,'.$name; } }
1.8 Modellmodell
1.8.1 Schließen Sie das eigentliche Geschäft ab Logik- und Datenkapselung sowie formatunabhängige Rückgabe von Daten
1.8.2 Das Modell unterstützt ein geschichtetes Design: Logikschicht/Dienstschicht/Ereignisschicht
1.8.3 Die Modellklasse muss nicht Greifen Sie auf die Datenbank zu. Es ist nur für CURD-Operationen verbunden, was wirklich inert ist verschiedene Formate von der Ansichtsklasse erstellt und zurückgegeben.
1.9.2 Sie können je nach Bedarf festlegen, ob Sie direkt rendern oder die Vorlagenausgabe verwenden möchten
1.9.3 Die Ansicht verfügt über eine Reihe von Vorlagendateien, die den Vorgängen im Controller entsprechen
1.9.4 Das Vorlagenverzeichnis kann in der Betriebsmethode dynamisch festgelegt werden
1.10 Namespace NameSpace
1.10.1 Namespace wird hauptsächlich verwendet in die Klassenbibliotheksdatei des Frameworks
1.10.2 Der Namespace muss dem automatischen Lademechanismus von PSR-4 entsprechen: Der Space-Name entspricht dem Pfad der Klasse
2 Lebenszyklus
2.1 Eintragsdatei index.php
2.1.1 Speicherort: public/index.php
2.1.2 Die Eintragsdatei normalerweise nur definiert Konstanten und lädt die Framework-Boot-Datei
2.2 Boot-Datei: start.php
<?php // 应用入口文件 // 定义项目路径 define('APP_PATH', __DIR__ . '/../application/'); // 加载框架引导文件 require __DIR__ . '/../thinkphp/start.php';
<?php namespace think; // ThinkPHP 引导文件 // 加载基础文件 require __DIR__ . '/base.php'; // 执行应用 App::run()->send();
<?php // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK ] // +---------------------------------------------------------------------- // | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- // | Author: liu21st <liu21st@gmail.com> // +---------------------------------------------------------------------- define('THINK_VERSION', '5.0.5'); define('THINK_START_TIME', microtime(true)); define('THINK_START_MEM', memory_get_usage()); define('EXT', '.php'); define('DS', DIRECTORY_SEPARATOR); defined('THINK_PATH') or define('THINK_PATH', __DIR__ . DS); define('LIB_PATH', THINK_PATH . 'library' . DS); define('CORE_PATH', LIB_PATH . 'think' . DS); define('TRAIT_PATH', LIB_PATH . 'traits' . DS); defined('APP_PATH') or define('APP_PATH', dirname($_SERVER['SCRIPT_FILENAME']) . DS); defined('ROOT_PATH') or define('ROOT_PATH', dirname(realpath(APP_PATH)) . DS); defined('EXTEND_PATH') or define('EXTEND_PATH', ROOT_PATH . 'extend' . DS); defined('VENDOR_PATH') or define('VENDOR_PATH', ROOT_PATH . 'vendor' . DS); defined('RUNTIME_PATH') or define('RUNTIME_PATH', ROOT_PATH . 'runtime' . DS); defined('LOG_PATH') or define('LOG_PATH', RUNTIME_PATH . 'log' . DS); defined('CACHE_PATH') or define('CACHE_PATH', RUNTIME_PATH . 'cache' . DS); defined('TEMP_PATH') or define('TEMP_PATH', RUNTIME_PATH . 'temp' . DS); defined('CONF_PATH') or define('CONF_PATH', APP_PATH); // 配置文件目录 defined('CONF_EXT') or define('CONF_EXT', EXT); // 配置文件后缀 defined('ENV_PREFIX') or define('ENV_PREFIX', 'PHP_'); // 环境变量的配置前缀 // 环境常量 define('IS_CLI', PHP_SAPI == 'cli' ? true : false); define('IS_WIN', strpos(PHP_OS, 'WIN') !== false); // 载入Loader类 require CORE_PATH . 'Loader.php'; // 加载环境变量配置文件 if (is_file(ROOT_PATH . '.env')) { $env = parse_ini_file(ROOT_PATH . '.env', true); foreach ($env as $key => $val) { $name = ENV_PREFIX . strtoupper($key); if (is_array($val)) { foreach ($val as $k => $v) { $item = $name . '_' . strtoupper($k); putenv("$item=$v"); } } else { putenv("$name=$val"); } } } // 注册自动加载 \think\Loader::register(); // 注册错误和异常处理机制 \think\Error::register(); // 加载惯例配置文件 \think\Config::set(include THINK_PATH . 'convention' . EXT);
2.2.1.2 Umgebungsvariablendefinitionsdateien laden
2.2.1.3 Automatischen Lademechanismus registrieren
2.2.1.3. 1 Loader::register() aufrufen, um Standardklassenbibliotheken und Klassenbibliotheken von Drittanbietern zu laden
2.2.1.3.2 Automatisch geladene Inhalte
2.2.1.3.2.1 Automatisches Laden der Registrierungssystemmethode thinkLoader::autoload
2.2.1.3.2.2 System-Namespace-Definition registrieren
2.2.1.3.2.3 Zuordnungsdatei der Klassenbibliothek laden (falls vorhanden)
2.2.1.3 .2.4 Wenn Composer installiert ist, registrieren Sie Composer, um automatisch geladen zu werden
2.2.1.3.2.5 Registrieren Sie das Erweiterungserweiterungsverzeichnis
2.2.1.3.3 Erkennungssequenz für automatisches Laden der Klassenbibliothek
2.2.1.3.3.1 Ob Klassenbibliothekszuordnung definiert werden soll
2.2.1.3.3.2 PSR-4 Automatisches Laden Erkennung
2.2.1.3.3.3 PSR- 0 Automatische Ladeerkennung
2.2.1.4 Registrierungsfehler und Ausnahmebehandlungsmechanismus
2.2.1.4.1 Execute Error::register( ) Registrierung, die aus drei Teilen besteht
2.2 .1.4.1.1 Methode zum Herunterfahren der Anwendung: thinkError::appShutdown
2.2.1.4.1.2 Fehlerbehandlungsmethode: thinkError::appError
2.2.1.4.1.3 Ausnahmebehandlungsmethode: thinkError::appException
2.2.1.5 Laden Sie die Konventionskonfigurationsdatei
2.2.1.5.1 thinkConfig::set(include THINK_PATH . 'convention ' . EXT);
2.2.2 Führen Sie die Anwendung aus :App::run()->send();
2.2.2.1 App::run() gibt das Request-Objekt ein und gibt das Antwortobjekt
zurück2.2.2.2 Response::send():发送数据到客户端
2.3 应用初始化:App::initCommon()和init()方法
/** * 初始化应用 */ public static function initCommon() { if (empty(self::$init)) { // 初始化应用 $config = self::init(); self::$suffix = $config['class_suffix']; // 应用调试模式 self::$debug = Env::get('app_debug', Config::get('app_debug')); if (!self::$debug) { 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; } } // 注册应用命名空间 self::$namespace = $config['app_namespace']; Loader::addNamespace($config['app_namespace'], APP_PATH); 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 */ private static function init($module = '') { // 定位模块目录 $module = $module ? $module . DS : ''; // 加载初始化文件 if (is_file(APP_PATH . $module . 'init' . EXT)) { include APP_PATH . $module . 'init' . EXT; } elseif (is_file(RUNTIME_PATH . $module . 'init' . EXT)) { include RUNTIME_PATH . $module . 'init' . EXT; } else { $path = APP_PATH . $module; // 加载模块配置 $config = Config::load(CONF_PATH . $module . 'config' . CONF_EXT); // 读取数据库配置文件 $filename = CONF_PATH . $module . 'database' . CONF_EXT; Config::load($filename, 'database'); // 读取扩展配置文件 if (is_dir(CONF_PATH . $module . 'extra')) { $dir = CONF_PATH . $module . 'extra'; $files = scandir($dir); foreach ($files as $file) { if (strpos($file, CONF_EXT)) { $filename = $dir . DS . $file; Config::load($filename, pathinfo($file, PATHINFO_FILENAME)); } } } // 加载应用状态配置 if ($config['app_status']) { $config = Config::load(CONF_PATH . $module . $config['app_status'] . CONF_EXT); } // 加载行为扩展文件 if (is_file(CONF_PATH . $module . 'tags' . EXT)) { Hook::import(include CONF_PATH . $module . 'tags' . EXT); } // 加载公共文件 if (is_file($path . 'common' . EXT)) { include $path . 'common' . EXT; } // 加载当前模块语言包 if ($module) { Lang::load($path . 'lang' . DS . Request::instance()->langset() . EXT); } } return Config::get(); }
2.3.1.1 定位模块目录
2.3.1.2 加载初始化文件
2.3.1.2.1 加载模块配置
2.3.1.2.2 读取数据库配置文件
2.3.1.2.3 读取扩展配置文件
2.3.1.2.4 加载应用状态配置
2.3.1.2.5 加载行为扩展文件
2.3.1.2.6 加载公共文件
2.3.1.2.7 加载当前模块语言包
2.3.2 检测应用调试模式:self::$debug = Env::get('app_debug', Config::get('app_debug'));
2.3.3 注册应用命名空间:self::$namespace = $config['app_namespace'];
2.3.4 加载额外文件:'extra_file_list'
2.3.5 设置系统时区:date_default_timezone_set($config['default_timezone']);
2.3.6 监听app_init: Hook::listen('app_init');
2.3.7 返回所有配置项:return Config::get();
2.4 URL访问检测:
2.4.1 PATH_INFO:http://serverName/index.php/index/index/hello/val/value
2.4.2 兼容方式:http://serverName/index.php?s=/index/index/hello&val=value
2.5 路由检测:App::routeCheck($request, array $config)与设置路由机制:route($route, $must = false)
/** * 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 = $config['pathinfo_depr']; $result = false; // 路由检测 $check = !is_null(self::$routeCheck) ? self::$routeCheck : $config['url_route_on']; if ($check) { // 开启路由 if (is_file(RUNTIME_PATH . 'route.php')) { // 读取路由缓存 $rules = include RUNTIME_PATH . 'route.php'; if (is_array($rules)) { Route::rules($rules); } } else { $files = $config['route_config_file']; foreach ($files as $file) { if (is_file(CONF_PATH . $file . CONF_EXT)) { // 导入路由配置 $rules = include CONF_PATH . $file . CONF_EXT; if (is_array($rules)) { Route::import($rules); } } } } // 路由检测(根据路由定义返回不同的URL调度) $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) { // 路由无效 解析模块/控制器/操作/参数... 支持控制器自动搜索 $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; } }
2.5.1 路由到模块/控制器/操作
2.5.2 路由到外部重定向地址;
2.5.3 路由到控制器方法;
2.5.4 路由到闭包函数;
2.5.5 路由到类的方法;
2.6 请求分发与响应输出:Response::send()
2.6.1 控制器的所有操作方法都是 return 返回而不是直接输出
2.6.2 自动转换成 default_return_type 参数配置的格式
2.7 应用结束,写入日志
2.7.1 系统的日志包括用户调试输出的和系统自动生成的日志,统一会在应用结束的时候进行写入操作
2.7.2 日志的写入操作受日志初始化的影响
3 入口文件
3.1 采用单一入口模式进行项目部署(并非唯一入口)
3.2 不同应用对应不同入口,但入口文件内容和功能基本一致
3.3 入口文件内容
<?php // 定义应用目录 define('APP_PATH', __DIR__ . '/../application/'); // 加载框架引导文件 require __DIR__ . '/../thinkphp/start.php';
3.3.1 定义应用目录:define('APP_PATH', __DIR__ . '/../application/');
3.3.2 定义系统常量:define('CONF_PATH', __DIR__ . '/../config/');
3.3.3 加载框架引导文件: require __DIR__ . '/../thinkphp/start.php';
3.4 入口文件位于public目录下
3.4.1 这是为了让应用部署更安全
3.4.2 public必须是Web可访问目录
3.4.3 其实文件或目录应该放在非Web访问目录下面
4 URL访问
4.1 URL设计
4.1.1 PATH_INFO:http://index.php/模块/控制器/操作/[参数名/参数值...]
4.1.2 兼容模型:http://index.php?s=/模块/控制器/操作/[参数名/参数值...]
4.1.3 不支持普通URL模式,但传参可以:http://index.php/module/controller/action?id=10
4.1.4 URL默认不区分大小写,都会转为小写的,控制器部分自动转为驼峰法处理
4.2 隐藏入口文件
4.2.1 隐藏入口文件,可优化URL,网站更安全
4.2.2 在入口文件同级:public/.htaccess
4.2.3 Apache配置文件httpd.conf加载:mod_rewrite.so模块,支持URL重写
4.2.4 httpd.conf:AllowOverride None 将None设置为 All
5 模块设计
5.1 默认为多模块,支持单一模块设计
5.2 模块命名空间均为app为根空间
5.3 模块可以看作是类库的集合:控制器类,模型类
5.4 模块类库:app\模块名\类库\类名
5.5 入口文件中隐藏模块和控制器
由于默认是采用多模块的支持,所以多个模块的情况下必须在URL地址中标识当前模块,如果只有一个模块的 话,可以进行模块绑定,方法是应用的入口文件中添加如下代码:
// 绑定当前访问到index模块 define('BIND_MODULE','index');
绑定后,我们的URL访问地址则变成:
http://serverName/index.php/控制器/操作/[参数名/参数值...]
访问的模块是 index 模块。 如果你的应用比较简单,模块和控制器都只有一个,那么可以在应用公共文件中绑定模块和控制器,如下:
// 绑定当前访问到index模块的index控制器 define('BIND_MODULE','index/index');
设置后,我们的URL访问地址则变成:
http://serverName/index.php/操作/[参数名/参数值...]
访问的模块是 index 模块,控制器是 Index 控制器。
5.5.1 绑定当前访问的模块:define('BIND_MODULE','index');
5.5.2 绑定当前访问的模块和控制器:define('BIND_MODULE','userlogin/getname');
5.6 单一模块设计:'app_multi_module'=>false,
5.6.1 可以把应用目录当作模块目录
5.6.2 模块中的控制器命名空间也要调整
6 命名空间
6.1 命名空间的路径与类库文件的目录一致,可以实现类的自动加载(惰性加载)
6.2 根命名空间:类库包
6.2.1 think:系统核心类库 (think/library/think)
6.2.2 traits:系统trait类库(think/library/traits)
6.2.3 app:应用类库(application)
6.2.4 自定义根命名空间
6.2.4.1 默认加载EXTEND_APTH目录中的类库,目录名为根
我们只需要把自己的类库包目录放入 EXTEND_PATH 目录(默认为 extend ,可配置),就可以自动注册对 应的命名空间,例如:
我们在 extend 目录下面新增一个 my 目录,然后定义一个 \my\Hello 类( 类文件位于 extend/my/Hello.php )如下:
<?php namespace my; class Hello { public function index() { return 'hello tp5'; } }
我们就可以在控制器中,直接实例化和调用:
<?php namespace app\index\controller; class Index { public function index() { $obj = new \my\Hello(); return $obj->index(); } }
6.2.4.2 可在入口文件中重新定义:define('EXTEND_PATH','../vendor/');
6.2.4.3 手动注册根命名空间
6.2.4.3.1 应用公共文件:common.php中添加如代码:
在应用公共文件中添加下面的代码:
\think\Loader::addNamespace('my','../application/extend/my/');
如果要同时注册多个根命名空间,可以使用:
\think\Loader::addNamespace([ 'my' => '../application/extend/my/', 'org' => '../application/extend/org/', ]);
6.2.4.3.2 应用配置文件:config.php中添加:
可以直接在应用的配置文件中添加配置,系统会在应用执行的时候自动注册。
'root_namespace' => [ 'my' => '../application/extend/my/', 'org' => '../application/extend/org/', ]
6.3 可以给命名空间创建别名
6.3.1 应用公共文件common.php
7 trait引入
7.1 trait提供了一种代码复用机制,是类的公共方法集,与继承相比,相当于横向扩展了类的功能
7.2 PHP5.4使用load_trait()引入,PHP5.5以上可以直接自动加载
但由于PHP5.4版本不支持 trait 的自动加载,因此如果是PHP5.4版本,必须手动导入 trait 类库,系统 提供了一个助手函数 load_trait ,用于自动加载 trait 类库,例如,可以这样正确引入 trait 类库。
namespace app\index\controller; load_trait('controller/Jump'); class index { // 引入traits\controller\Jump use \traits\controller\Jump; public function index() { $this->assign('name','value'); $this->show('index'); } }
如果你的PHP版本大于 5.5 的话,则可以省略 load_trait 函数引入 trait 。
namespace app\index\controller; class index { use \traits\controller\Jump; public function index() { } }
可以支持同时引入多个 trait 类库,例如:
namespace app\index\controller; load_trait('controller/Other'); load_trait('controller/Jump'); class index { use \traits\controller\Other; use \traits\controller\Jump; public function index() { } }
或者使用
namespace app\index\controller; load_trait('controller/Other'); load_trait('controller/Jump'); class index { use \traits\controller\Other,\traits\controller\Jump; public function index() { } }
7.3 trait命名冲突的解决方案
7.3.1 insteadof:冲突时指定使用哪一个trait类
7.3.2 as:将另一个冲突的trait类以别名的方式访问
8 API友好
8.1 数据输出
8.1.1 控制器中数据输出统一用Response类处理,并不直接输出
8.1.2 设置 default_return_type 或者动态设置不同类型的 Response 输出就可以自动进行数据转换
8.1.3 大多数情况下,你只需要在控制器中返回字符串或者数组即可
8.1.4 默认为html,可在配置文件中:'default_return_type'=>'json'
8.2 错误调试
8.2.1 Trace 调试功能支持 Socket 在内的方 式,可以实现远程的开发调试
三、ThinkPHP5框架思维导图下载地址:
【相关推荐】
1. 图解ThinkPHP5框架(一):基础知识,开发规范与目录结构