최신 ThinkPHP 5.0.8을 기반으로 원본 아이디어는 xmind 마인드맵 제작입니다. 그림이 선명하지 않다고 생각되면 xmind 소스 파일을 다운로드하여 xmind 소프트웨어로 열 수 있습니다.
또한 마인드맵에 사용된 소스코드는 모두 맵노트에 있으니 xmind 소스파일을 다운로드 하셔야만 보실 수 있습니다.
ThinkPHP5 개발을 스스로 배우고 싶은 학생이라면 이 혜택을 놓치지 마세요. 현재 ThinkPHP5 프로젝트 개발에 참여하고 있는 프로그래머들은 향후 참고를 위해 저장해 둘 수 있습니다
1. 마인드맵:
2. ThinkPHP5의 전체 설명을 텍스트 버전으로 제공 프레임워크 아키텍처 :
프레임워크 아키텍처
1 아키텍처 개요
1.1 MVC 디자인 패턴 기반
1.1.1 모델: 모델
1.1.2 보기:보기
1.1.3 컨트롤러: 컨트롤러
1.2 MVC 기반 URL 액세스 라우팅
1.2.1 http:/ /도메인 이름/ 항목 파일/모듈/컨트롤러/작업/매개 변수/값...
1.3 항목 파일
1.3.1 대부분 common: index .php
1.3.2 다음과 같은 다른 항목 파일을 모듈에 바인딩할 수 있습니다: admin.php
1.4 Application App
1.4.1 프레임워크 수명주기를 관리하는 개체: thinkApp 클래스
1.4.2 항목 파일에 의해 호출 및 실행
1.4.3 동일한 APP_PATH를 가진 애플리케이션 디렉토리는 동일한 것으로 간주됩니다. 애플리케이션
1.4.4 애플리케이션에는 프런트엔드의 index.php, 백엔드의 admin.php와 같이 여러 개의 입구가 있을 수 있습니다.
1.4.5 애플리케이션에는 자체적인 독립적인 구성 파일과 공용 함수 파일
1.5 모듈
1.5.1 애플리케이션은 일반적으로 여러 모듈로 구성됩니다
1.5.2 모듈은 일반적으로 응용 프로그램 디렉터리의 하위 디렉터리: app/index/
1.5.3 모듈은 일반적으로 여러 컨트롤러 클래스 파일로 구성됩니다.
1.5.4 간단한 응용 프로그램의 경우, 모듈 디렉토리를 생성할 필요가 없습니다. 단일 모듈 아키텍처를 사용하고 애플리케이션 구성에서 다중 모듈 지원을 끄십시오. 'app_multi_module'=>false
1.5.5 모듈은 자체 독립적인 모듈을 가질 수도 있습니다. 구성 파일, 공용 파일 및 클래스 라이브러리 파일
1.6 ControllerController
1.6.1 컨트롤러는 사용자 요청에 대한 응답, 모델 처리 호출, 뷰 출력을 선택하고 비즈니스 처리에 개입해서는 안 됩니다
1.6.2 각 컨트롤러는 실제로 클래스 파일입니다: Index.php
1.6.3 5.0부터 컨트롤러는 없이 정상적으로 작동할 수 있습니다. 상위 클래스 상속
<?php namespace app\index\controller; class Index { public function index() { return 'hello,thinkphp!'; } }
1.7 Action
1.7.1 컨트롤러에는 여러 작업 방법이 포함되며 작업 방법은 URL 액세스의 최소 단위입니다
1.7.2 작업 방법에 매개변수가 필요한 경우 $_GET 또는 $_POST를 전달해야 합니다.
<?php namespace app\index\controller; class Index { public function index() { return 'index'; } public function hello($name) { return 'Hello,'.$name; } }
1.8 모델 모델
1.8.1 실제 비즈니스 로직을 완성하고 데이터 캡슐화 및 형식 독립적인 데이터 반환
<🎜1.9 보기 보기1.9.1 모델 클래스를 호출하는 컨트롤러에서 반환되는 데이터는 패키징되어 다른 형식으로 반환되어야 합니다. 뷰 클래스에 의해. 1.9.2 필요에 따라 직접 렌더링할지 템플릿 출력을 사용할지 결정할 수 있습니다1.9.3 뷰에는 컨트롤러의 작업에 해당하는 일련의 템플릿 파일이 있습니다1.9.4 작업 방법에서 템플릿 디렉터리를 동적으로 설정할 수 있습니다.
1.10 네임스페이스 NameSpace
2 라이프사이클
<?php // 应用入口文件 // 定义项目路径 define('APP_PATH', __DIR__ . '/../application/'); // 加载框架引导文件 require __DIR__ . '/../thinkphp/start.php';
<?php namespace think; // ThinkPHP 引导文件 // 加载基础文件 require __DIR__ . '/base.php'; // 执行应用 App::run()->send();
2.2.1 base.php 로드
<?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.1 시스템 상수 정의 로드
2.2.1.3.2.4 Composer가 설치되어 있는 경우 Composer를 자동 로딩하도록 등록2.2.1.3.2.5 확장 확장 디렉터리 등록
2.2 .1.3.3 클래스 라이브러리 자동 로딩 감지 시퀀스
2.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框架(一):基础知识,开发规范与目录结构