ThinkPHP 5 简明开发手册
介绍
ThinkPHP V5.0——为API开发而设计的高性
能框架
ThinkPHP5.0版本是一个颠覆和重构版本,采用全新的架构思
想,引入了很多的PHP新特性,优化了核心,减少了依赖,实现
了真正的惰性加载,并针对API开发做了大量的优化。
新版主要功能特性如下:
(目前尚处于Beta版本,仅供学习参考,请谨慎用于项目)
由于版本库更新较多,很多内容文档可能不一定会及时更新,请谅解,正式版发布后文档才会趋于完
善。
[ 底层架构 ]
真正的惰性加载
核心类库组件化
框架引导文件
采用Traits扩展
API友好(输出、异常和调试)
文件命名规范调整
[ 调试和异常 ]
专为API开发而设计的输出、调试和异常处理
日志类支持本地文件/SAE/页面Trace/SocketLog输出,可以实现远程浏览器插件调试
内置trace方法直接远程调试
异常预警通知驱动设计
数据库SQL性能分析支持
[ 路由 ]
本文档使用 看云 构建 -1-
ThinkPHP 5 简明开发手册 -2-
独立路由类库
静态方法注册路由规则
自定义路由检测方法
路由分组功能支持
规则路由中的变量支持采用正则规则定义(包括全局和局部)
闭包劫持完善
路由别名支持
支持路由到多层控制器
[ 控制器 ]
控制器类无需继承controller类
灵活的多层控制器支持
可以Traits引入高级控制器功能
控制器rest/yar/rpc/hprose/jsonrpc扩展
前置操作方法支持排除和指定操作
控制器操作方法统一return设计
[ 模型 ]
简化的核心模型
Traits引入高级模型/视图模型/关联模型
主从分布时候主数据库读操作支持
改进的join方法和order方法
取消字段缓存
[ 视图 ]
视图解析驱动设计(模板引擎)
所有方法不再直接输出而是返回交由系统统一输出处理
动态切换模板主题设计
动态切换模板引擎设计
[ 数据库 ]
完全基于PDO实现
简化的数据库驱动设计
SQL性能监控(需要开启数据库调试模式)
[ 其他方面 ]
本文档使用 看云 构建
ThinkPHP 5 简明开发手册
目录和MVC文件自动生成支持
I函数默认添加变量修饰符为/s
一个行为类里面支持为多个标签位定义不同的方法
更多的社交扩展类库
在RC版本发布之前,ThinkPHP5仍然可能存在功能变化。
相对于3.2版本,废除了如下功能:
编译缓存
LITE文件
字段缓存
计划支持的功能包括:
单元测试支持;
命令行工具集;
队列;
由于ThinkPHP5设计之初并未考虑兼容旧版本升级,因此如果从3.2版本升级将会有不少的问题需要注
意,在正式版发布之前官方会尽量给出一份升级指南文档。
本文档使用 看云 构建 -3-
ThinkPHP 5 简明开发手册
快速入门
本章内容提供了ThinkPHP5.0的一些基本用法,并且处于不断完善过程。
注意:本章内容会随着最新版本的功能变化而做出一定的调整,因此相关功能的说明均针对Github的最
新版本,而非官网下载版本。
GITHUB地址:/top-think/think
安装配置
ThinkPHP5的环境要求如下:
PHP >= 5.4.0
PDO PHP Extension
CURL PHP Extension
严格来说,ThinkPHP无需安装过程,这里所说的安装其实就是把ThinkPHP框架放入WEB运行环境(前提
是你的WEB运行环境已经OK ),可以通过两种方式获取和安装ThinkPHP。
一、下载ThinkPHP安装
获取ThinkPHP的方式很多,官方网站()是最好的下载和文档获取来源。
官网提供了稳定版本的下载:/down/framework.html
由于ThinkPHP5.0还在测试阶段,所以需要通过Git服务器下载,Git服务地址:/top-
think/think
下载或者使用GIT克隆到本地后,请(解压缩后)放置于你的WEB根目录下面的 tp5 子目录。
二、使用Composer安装
ThinkPHP支持使用Composer安装,如果还没有安装 Composer,你可以按 Composer安装 中的方法安
装。在 Linux 和 Mac OS X 中可以运行如下命令:
curl -sS /installer | php
mv composer.phar /usr/local/bin/composer
在 Windows 中,你需要下载并运行 Composer-Setup.exe。
本文档使用 看云 构建 -4-
ThinkPHP 5 简明开发手册
如果遇到任何问题或者想更深入地学习 Composer,请参考 Composer 文档(英文),Composer 中
文。
如果你已经安装有 Composer 请确保使用的是最新版本,你可以用 composer self-update 命令更新
Composer 为最新版本。
然后在命令行下面,切换到你的web根目录下面并执行下面的命令:
composer create-project topthink/think tp5 dev-master --prefer-dist
由于目前尚未正式发布,所以先用 dev-master 分支。
如果出现错误提示,请根据提示操作或者参考Composer中文文档。
如果国内访问composer的速度比较慢,可以参考这里的说明使用国内镜像
无论你采用什么方式获取的ThinkPHP框架,现在只需要做最后一步来验证是否正常运行。
在浏览器中输入地址:
http://localhost/tp5/public/
如果浏览器输出如图所示:
恭喜你,现在已经完成ThinkPHP的安装!
如果你无法正常运行并显示ThinkPHP的欢迎页面,那么请参考下面的列表检查下你的服务器环境:
PHP5.4以上版本(注意:PHP5.4dev版本和PHP6均不支持 )
WEB服务器是否正常启动
目录结构
下载最新版框架后,解压缩到web目录下面,可以看到初始的目录结构如下: -5-
本文档使用 看云 构建
ThinkPHP 5 简明开发手册
project 应用部署目录
├─composer.json composer定义文件
├─README.md README文件
├─build.php 自动生成定义文件(参考)
├─LICENSE.txt 授权说明文件
├─application 应用目录(可设置)
│ ├─common 公共模块目录(可更改)
│ ├─runtime 应用的运行时目录(可写,可设置)
│ ├─module 模块目录
│ │ ├─config.php 模块配置文件
│ │ ├─common.php 模块函数文件
│ │ ├─controller 控制器目录
│ │ ├─model 模型目录
│ │ ├─view 视图目录
│ │ ├─ ... 更多类库目录
│ ├─common.php 公共函数文件
│ ├─route.php 路由配置文件
│ ├─database.php 数据库配置文件
│ └─config.php 公共配置文件
├─public WEB部署目录(对外访问目录)
│ ├─index.php 应用入口文件
│ ├─.htaccess 用于apache的重写
│ └─router.php 快速测试文件(用于自带webserver)
├─thinkphp 框架系统目录
│ ├─library 框架类库目录
│ │ ├─behavior 行为类库目录
│ │ ├─think Think类库包目录
│ │ ├─org Org类库包目录
│ │ ├─traits 系统Traits目录
│ │ ├─ ... 更多类库目录
│ ├─extend 扩展类库目录(可自定义)
│ ├─vendor 第三方类库目录
│ ├─mode 应用模式目录
│ ├─tpl 系统模板目录
│ ├─base.php 基础文件
│ ├─convention.php 框架惯例配置文件
│ └─start.php 框架引导文件
router.php用于php自带webserver支持,可用于快速测试
进入public目录后,启动命令:php -S localhost:8888 router.php
5.0版本自带了一个完整的应用目录结构和默认的应用入口文件,开发人员可以在这个基础之上灵活调整。
上面的目录结构和名称是可以改变的,这取决于你的入口文件和配置参数。
由于ThinkPHP5.0.0的架构设计对模块的目录结构保留了很多的灵活性,尤其是对于用于存储的目录具
有高度的定制化,因此上述的目录结构仅供规范参考。
本文档使用 看云 构建 -6-
ThinkPHP 5 简明开发手册
系统架构
URL设计
ThinkPHP5.0.0在没有启用路由的情况下典型的URL访问规则是:
http://serverName/应用(或应用入口文件)/模块/控制器/操作/[参数名/参
数值...]
支持切换到命令行访问,如果切换到命令行模式下面的访问规则是:
>php.exe index.php(应用入口文件) 模块/控制器/操作/[参数名/参数值...]
可以看到,无论是URL访问还是命令行访问,都采用PATHINFO模式的访问地址,其中PATHINFO的分隔
符是可以设置的。
首先,解释下其中的几个概念:
应用 基于同一个入口文件访问的项目我们称之为一个应用。
模块 一个应用下面可以包含多个模块,每个模块在应用目录下面都是一个独立的子目录。
控制器 每个模块可以包含多个控制器,一个控制器通常体现为一个(控制器)类。
操作 每个控制器类可以包含多个操作方法,每个操作是URL访问的最小单元。
简化URL访问
在ThinkPHP5.0中,出于优化的URL访问原则,我们还做出了如下的URL访问设计,这些设计包括:
隐藏应用入口文件
应用入口文件通常就是指index.php,可以通过URL重写隐藏。
隐藏应用入口文件index.php,以Apache为例说明如何设置。
下面是Apache的配置过程,可以参考下:
1、httpd.conf配置文件中加载了mod_rewrite.so模块
2、AllowOverride None 将None改为 All
3、把下面的内容保存为 .htaccess 文件放到应用入口文件的同级目录下
本文档使用 看云 构建 -7-
ThinkPHP 5 简明开发手册
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ index.php/$1 [QSA,PT,L]
隐藏模块
由于默认是采用多模块的支持,所以多个模块的情况下必须在URL地址中标识当前模块,如果只有一个模
块的话,可以进行模块绑定,方法是应用的公共文件中添加如下代码:
// 绑定index模块
\think\Route::bind('module','index');
设置后,我们的URL访问地址则变成:
http://serverName/应用入口/控制器/操作/[参数名/参数值...] // 访问的模块
是index模块
隐藏控制器
如果你的应用比较简单,模块和控制器都只有一个,那么可以在应用公共文件中绑定模块和控制器,如
下:
// 绑定index模块的index控制器
\think\Route::bind('module','index/index');
设置后,我们的URL访问地址则变成:
http://serverName/应用入口/操作/[参数名/参数值...] // 访问的模块是
index模块,控制器是Index控制器
单一模块
如果你的应用比较简单,只有一个模块,那么可以尝试使用单一模块结构,方法如下:
首先在入口文件中设置
// 关闭多模块设计
define('APP_MULTI_MODULE',false);
应用的目录结构就变成:
本文档使用 看云 构建 -8-
ThinkPHP 5 简明开发手册
├─application 应用目录(可设置)
│ ├─runtime 应用的运行时目录(可写,可设置)
│ ├─controller 控制器目录
│ ├─model 模型目录
│ ├─view 视图目录
│ ├─ ... 更多类库目录
│ ├─common.php 函数文件
│ ├─route.php 路由配置文件
│ ├─database.php 数据库配置文件
│ └─config.php 配置文件
URL访问地址变成
http://serverName/应用入口/控制器/操作/[参数名/参数值...]
单一模块设计的应用类库的命名空间有所调整,例如:
app\controller\Index
app\model\User
更多的URL简化和定制还可以通过URL路由功能实现。
命名规范
命名规范
ThinkPHP5的命名规范如下:
目录和文件
框架核心类库的目录统一使用小写规范,但应用目录名不强制规范,驼峰法和小写+下划线均支持,看
团队规范;
类库、函数文件统一以 .php 为后缀;
类的文件名均以命名空间定义,并且命名空间的路径和类库文件所在路径一致(包括大小写);
类名和类文件名保持一致,并统一采用驼峰法命名(首字母大写)
函数和类、属性命名
类的命名采用驼峰法,并且首字母大写,例如 User 、 UserType ,不需要添加controller、model
等后缀,UserController直接更改为User;
函数的命名使用小写字母和下划线(小写字母开头)的方式,例如 get_client_ip ;
方法的命名使用驼峰法,并且首字母小写或者使用下划线“_”,例如 getUserName ,
本文档使用 看云 构建 -9-
ThinkPHP 5 简明开发手册
_parseType ,通常下划线开头的方法属于私有方法;
属性的命名使用驼峰法,并且首字母小写或者使用下划线“_”,例如 tableName 、 _instance ,通
常下划线开头的属性属于私有属性;
以双下划线“__”打头的函数或方法作为魔法方法,例如 __call 和 __autoload ;
常量和配置
常量以大写字母和下划线命名,例如 APP_DEBUG 和 APP_MODE ;
配置参数以小写字母和下划线命名,例如 url_route_on ;
数据表和字段
数据表和字段采用小写加下划线方式命名,并注意字段名不要以下划线开头,例如 think_user 表和
user_name 字段,类似 _username 这样的数据表字段可能会被过滤。
应用类库命名空间规范
应用类库的根命名空间统一为app(可以设置APP_NAMESPACE更改);
例如: app\index\controller\Index 和 app\index\model\User 。
自动生成
自动生成
ThinkPHP5.0.0 具备自动创建功能,可以用来自动生成需要的模块和目录结构。
首先要在入口文件开启自动创建,如下:
define('APP_AUTO_BUILD',true);
开启后,需要定义自动创建的定义文件 build.php 。
默认的框架的根目录下面自带了一个 build.php 示例参考文件,把这个文件复制到application目录下面然
后根据需要修改后就可以用于自动生成。
自动生成机制需要 application 目录具备可写权限。
默认的build.php内容如下:
本文档使用 看云 构建 - 10 -
ThinkPHP 5 简明开发手册
return [
// 生成运行时目录
'runtime' => [
'__dir__' => ['cache', 'log', 'temp'],
],
// 定义index模块的自动生成
'index' => [
'__file__' => ['tags.php', 'user.php', 'hello.php'],
'__dir__' => ['behavior', 'controller', 'model', 'view'],
'controller' => ['Index', 'Test', 'UserType'],
'model' => [],
'view' => ['index/index'],
],
// 。。。 其他更多的模块定义
];
可以给每个模块定义需要自动生成的文件和目录,以及MVC类。
__dir__ 表示生成目录(支持多级目录)
__file__ 表示生成文件(不定义默认会生成 config.php 文件)
controller 表示生成controller类
model表示生成model类
view表示生成html文件(支持子目录)
自动生成以 APP_PATH 为起始目录, __dir__ 和 __file__ 表示需要自动创建目录和文件,其他的则表示
为模块自动生成。
模块的自动生成则以 APP_PATH.'模块名/' 为起始目录。
并且会自动生成模块的默认的Index访问控制器文件用于显示框架的欢迎页面。
我们还可以在 APP_PATH 目录下面自动生成其它的文件和目录,或者增加多个模块的自动生成,例如:
本文档使用 看云 构建 - 11 -
ThinkPHP 5 简明开发手册
return [
'__dir__' => ['runtime/cache','runtime/log','runtime/temp'],
'__file__' => ['hello.php','test.php'],
// 定义index模块的自动生成
'index' => [
'__file__' => ['tags.php', 'user.php', 'hello.php'],
'__dir__' => ['behavior', 'controller', 'model', 'view'],
'controller' => ['Index', 'Test', 'UserType'],
'model' => [],
'view' => ['index/index'],
],
// 定义test模块的自动生成
'test'=>[
'__dir__' => ['behavior','controller','model','widget'],
'controller'=> ['Index','Test','UserType'],
'model' => ['User','UserType'],
'view' => ['index/index','index/test'],
],
// 。。。 其他更多的模块定义
];
为了性能考虑,在生成完成之后,建议删除或者更名 build.php 文件。
将来计划添加扫描当前数据库自动生成模型类的功能。
引导文件
入口文件
入口文件是指应用的访问入口文件,由于ThinkPHP采用单一入口模式,支持多模块设计,因此多个模块的
访问入口也是同一个。
入口文件唯一需要指定的就是应用的路径,然后加载框架的入口(引导)文件。例如:
// 定义项目路径
define('APP_PATH','../app/');
// 加载框架引导文件
require '../thinkphp/start.php';
ThinkPHP5用引导文件替代了旧版的框架入口文件,引导文件是可以根据环境和项目需要定制和调整的,
而且引导文件的位置是可以随意放置。
引导文件
由于ThinkPHP5.0.0采用的是可分离式设计,因此,类库文件之间彼此相互独立,不是特别依赖,所以在
本文档使用 看云 构建 - 12 -
ThinkPHP 5 简明开发手册
项目开发的过程中,灵活和自由度较高,因此需要通过一定的组装和设置来完成,为了简化开发者进行实
际的开发工作,引导文件就是起到这样的作用,预先定义和配置了一些规则。
引导文件一般来说,同时可以作为项目入口文件中框架的入口文件,例如,我们的项目入口文件定义如
下:
define('APP_PATH',dirname(__DIR__).'/application/');
require dirname(__DIR__).'/thinkphp/start.php';
start.php就是系统自带的一个引导文件,包含了相关初始化和应用执行。
namespace think;
// ThinkPHP 引导文件
// 加载基础文件
require __DIR__ . '/base.php';
require CORE_PATH . 'Loader.php';
// 注册自动加载
Loader::register();
// 注册错误和异常处理机制
register_shutdown_function(['think\Error', 'appShutdown']);
set_error_handler(['think\Error', 'appError']);
set_exception_handler(['think\Error', 'appException']);
// 加载模式定义文件
$mode = require MODE_PATH . APP_MODE . EXT;
// 加载模式别名定义
if (isset($mode['alias'])) {
Loader::addMap(is_array($mode['alias']) ? $mode['alias'] : include $mode['alias']);
}
// 加载模式配置文件
if (isset($mode['config'])) {
is_array($mode['config']) ? Config::set($mode['config']) : Config::load($mode['config']);
}
// 加载模式行为定义
if (isset($mode['tags'])) {
Hook::import(is_array($mode['tags']) ? $mode['tags'] : include $mode['tags']);
}
// 执行应用
App::run(Config::get());
自动加载 - 13 -
本文档使用 看云 构建
ThinkPHP 5 简明开发手册
概述
ThinkPHP5.0.0 真正实现了按需加载,所有类库采用自动加载机制,采用了两种方式来实现:命名空间和
类库映射,并且支持composer类库的自动加载。
自动加载的实现由 \think\Loader 类库完成。
命名空间
由于新版ThinkPHP完全采用了命名空间的特性,因此只需要给类库正确定义所在的命名空间,而命名空间
的路径与类库文件的目录一致,那么就可以实现类的自动加载。
例如,如果我们实例化 \think\log\driver\File 类的话:
$class = new \think\log\driver\File();
系统会自动加载 thinkphp\library\think\log\driver\File.php 文件。
如果实例化:
$class = new \org\UploadFile();
系统会自动加载 thinkphp\library\org\UploadFile.php 文件。
如果不清楚什么是命名空间,可以参考PHP手册相关部分。这里就不对命名空间的用法做过多的描述了。
系统对根命名空间的检测顺序如下:
1、优先检测是否存在注册过的根命名空间
2、检测composer自动加载的类库
3、然后检测核心目录(LIB_PATH)下是否存在根命名空间的对应子目录
4、检测是否应用类库(APP_PATH)命名空间
5、检测扩展类库目录(EXTEND_PATH)下是否存在根命名空间对应的子目录
如果你需要额外的根命名空间的自动加载支持,可以首先注册根命名空间,例如:
\think\Loader::addNamespace('org',MY_PATH.'org/');
\think\Loader::addNamespace('com',MY_PATH.'com/');
注册的根命名空间优先,并且ThinkPHP5注册的命名空间根必须是小写。 - 14 -
注册新的命名空间支持后,我们就可以自动加载该命名空间下面的类库了。
类库映射
本文档使用 看云 构建
ThinkPHP 5 简明开发手册
遵循我们上面的命名空间定义规范的话,基本上可以完成类库的自动加载了,但是如果定义了较多的命名
空间的话,效率会有所下降,所以,我们可以给常用的类库定义类库映射。命名类库映射相当于给类文件
定义了一个别名,效率会比命名空间定位更高效,例如:
\think\Loader::addMap('think\Log',LIB_PATH.'think\Log.php');
\think\Loader::addMap('org\util\Array',LIB_PATH.'org\util\Array.php');
也可以利用addMap方法批量导入类库映射定义,例如:
$map = ['think\Log'=>LIB_PATH.'think\Log.php','org\util\array'=>LIB_PATH.'org\util\Array.php'];
\think\Loader::addMap($map);
通过类库映射的方式注册的类可以不遵循命名空间必须对应子目录的规范。
类库导入
如果你不需要系统的自动加载功能,又或者没有使用命名空间的话,那么也可以使用Think\Loader类的
import方法手动加载类库文件,例如:
\think\Loader::import('org.util.array');
\think\Loader::import('@.util.upload');
类库导入也采用类似命名空间的概念(但不需要实际的命名空间支持),支持的“根命名空间”包括:
目录 说明
behavior 系统行为类库
think 核心基类库
org 扩展类库包
com 企业类库包
@ 表示当前模块类库包
vendor 第三方类库
traits 系统Traits类库
如果完全遵从系统的命名空间定义的话,一般来说无需手动加载类库文件,直接实例化即可。
Composer自动加载
5.0版本支持Composer安装的类库的自动加载,你可以直接按照Composer依赖库中的命名空间直接调
用。
本文档使用 看云 构建 - 15 -
ThinkPHP 5 简明开发手册
配置
概述
配置的加载、设置和获取功能统一由\think\Config类完成。
使用
加载配置文件
\think\Config::load('配置文件名');
配置文件一般位于 APP_PATH 目录下面,如果需要加载其它位置的配置文件,需要使用完整路径,例如:
\think\Config::load(APP_PATH.'config/config.php');
系统默认的配置定义格式是PHP返回数组的方式,例如:
return [
'配置参数1'=>'配置值',
'配置参数1'=>'配置值',
// ... 更多配置
];
如果你定义格式是其他格式的话,可以使用parse方法来导入,例如:
\think\Config::parse(APP_PATH.'my_config.ini','ini');
\think\Config::parse(APP_PATH.'my_config.xml','xml');
parse方法的第一个参数需要传入完整的文件名或者配置内容。
如果不传入第二个参数的话,系统会根据配置文件名自动识别配置类型,所以下面的写法仍然是支持的:
\think\Config::parse('my_config.ini');
parse方法除了支持读取配置文件外,也支持直接传入配置内容,例如:
$config = 'var1=val - 16 -
var2=val';
\think\Config::parse($config,'ini');
本文档使用 看云 构建
ThinkPHP 5 简明开发手册 - 17 -
支持传入配置文件内容的时候 第二个参数必须显式指定。
标准的ini格式文件定义:
配置参数1=配置值
配置参数2=配置值
标准的xml格式文件定义:
val1
val2
配置类采用驱动方式支持各种不同的配置文件类型,因此可以根据需要随意扩展。
设置配置参数
使用set方法动态设置参数,例如:
\think\Config::set('配置参数','配置值');
// 或者使用快捷方法
C('配置参数','配置值');
也可以批量设置,例如:
\think\Config::set(['配置参数1'=>'配置值','配置参数2'=>'配置值']);
// 或者使用
C(['配置参数1'=>'配置值','配置参数2'=>'配置值']);
二级配置
配置参数支持二级,例如,下面是一个二级配置的设置和读取示例:
$config = [
'user'=>['type'=>1,'name'=>'thinkphp'],
'db' =>['type'=>'mysql','user'=>'root','password'=>''],
];
// 设置配置参数
\think\Config::set($config);
// 读取二级配置参数
echo \think\Config::get('user.type');
// 或者 echo C('user.type');
系统不支持二级以上的配置参数读取,需要手动分步骤读取。
本文档使用 看云 构建
ThinkPHP 5 简明开发手册
有作用域的情况下,仍然支持二级配置的操作。
如果采用其他格式的配置文件的话,二级配置定义方式如下(以ini和xml为例):
[user]
type=1
name=thinkphp
[db]
type=mysql
user=rot
password=''
标准的xml格式文件定义:
1
thinkphp
mysql
root
set方法也支持二级配置,例如:
\think\Config::set(['type'=>'file','prefix'=>'think'],'cache');
独立配置文件
新版支持配置文件分离,只需要配置 extra_config_list 参数(在应用公共配置文件中)。
例如,不使用独立配置文件的话,数据库配置信息应该是在config.php中配置如下:
本文档使用 看云 构建 - 18 -
ThinkPHP 5 简明开发手册
/* 数据库设置 */
'database' => [
// 数据库类型
'type' => 'mysql',
// 服务器地址
'hostname' => '127.0.0.1',
// 数据库名
'database' => 'thinkphp',
// 数据库用户名
'username' => 'root',
// 数据库密码
'password' => '',
// 数据库连接端口
'hostport' => '',
// 数据库连接参数
'params' => [],
// 数据库编码默认采用utf8
'charset' => 'utf8',
// 数据库表前缀
'prefix' => '',
// 数据库调试模式
'debug' => false,
],
如果需要使用独立配置文件的话,则首先在config.php中添加配置:
'extra_config_list' => ['database'],
定义之后,数据库配置就可以独立使用 database.php 文件,配置内容如下:
本文档使用 看云 构建 - 19 -
ThinkPHP 5 简明开发手册
/* 数据库设置 */
return [
// 数据库类型
'type' => 'mysql',
// 服务器地址
'hostname' => '127.0.0.1',
// 数据库名
'database' => 'thinkphp',
// 数据库用户名
'username' => 'root',
// 数据库密码
'password' => '',
// 数据库连接端口
'hostport' => '',
// 数据库连接参数
'params' => [],
// 数据库编码默认采用utf8
'charset' => 'utf8',
// 数据库表前缀
'prefix' => '',
// 数据库调试模式
'debug' => false,
],
如果配置了 extra_config_list 参数,并同时在 config.php 和 database.php 文件中都配置的话,则
database.php 文件的配置会覆盖 config.php 中的设置。
系统默认设置了两个独立配置文件,包括 database 和 route 。
读取配置参数
设置完配置参数后,就可以使用get方法读取配置了,例如:
echo \think\Config::get('配置参数1');
系统为get方法定义了一个快捷函数C,以上可以简化为:
echo C('配置参数1');
读取所有的配置参数:
dump(\think\Config::get());
// 或者 dump(C());
或者你需要判断是否存在某个设置参数:
本文档使用 看云 构建 - 20 -
ThinkPHP 5 简明开发手册
\think\Config::has('配置参数2');
作用域
配置参数支持作用域的概念,默认情况下,所有参数都在同一个系统默认作用域下面。如果你的配置参数
需要用于不同的项目或者相互隔离,那么就可以使用作用域功能,作用域的作用好比是配置参数的命名空
间一样。
\think\Config::load('my_config.php','','user'); // 导入my_config.php中的配置参数,并纳入user作用域
\think\Config::parse('my_config.ini','ini','test'); // 解析并导入my_config.ini 中的配置参数,读入test作用域
\think\Config::set('user_type',1,'user'); // 设置user_type参数,并纳入user作用域
\think\Config::set($config,'test'); // 批量设置配置参数,并纳入test作用域
echo \Think\Config::get('user_type','user'); // 读取user作用域的user_type配置参数
dump(\Think\Config::get('','user')); // 读取user作用域下面的所有配置参数
dump(C('',null,'user')); // 同上
\think\Config::has('user_type','test'); // 判断在test作用域下面是否存在user_type参数
路由
概述
由于ThinkPHP5.0默认采用的URL规则是:
http://server/module/controller/action/param/value/...
路由解析的最终结果通常是把URL地址解析到模块的某个控制器下的操作方法,在特殊的情况下,也可以
跳转到外部地址或者执行闭包函数。
新版的路由功能做了大量的增强,包括:
支持路由到模块(模块/控制器/操作)、控制器(控制器类/操作)、类(任何类库);
闭包路由的增强;
规则路由支持全局和局部变量规则定义(正则);
支持路由到任意层次的控制器;
子域名路由功能改进;
路由分组并支持分组参数定义;
通过函数自定义路由检测规则;
ThinkPHP5.0的路由比较灵活,系统支持三种方式的URL解析规则:
一、普通模式 - 21 -
本文档使用 看云 构建
ThinkPHP 5 简明开发手册
关闭路由,完全使用默认的pathinfo方式URL:
'url_route_on' => false,
路由关闭后,不会解析任何路由规则,采用默认的PATH_INFO 模式访问URL:
module/controller/action/param/value/...
但仍然可以通过Action参数绑定、空控制器和空操作等特性实现URL地址的简化。
二、混合模式
开启路由,并使用路由+默认PATH_INFO方式的混合:
'url_route_on' => true,
该方式下面,只需要对需要定义路由规则的访问地址定义路由规则,其它的仍然按照默认的PATH_INFO模
式访问URL。
三、强制模式
开启路由,并设置必须定义路由才能访问:
'url_route_on' => true,
'url_route_must'=> true,
这种方式下面必须严格给每一个访问地址定义路由规则(首页除外),否则将抛出异常。
注册路由规则
路由功能由 think\Route 类实现,包括路由注册和检测。
路由注册可以采用方法动态单个和批量注册,也可以直接定义路由定义文件的方式进行集中注册。
动态注册
使用Route类的register方法注册路由规则(通常可以在模块的公共文件中注册,或者定义配置文件后在公
共文件中批量导入的方式注册),例如注册如下路由规则后:
\think\Route::register('new/:id','index/New/read');
我们访问:
本文档使用 看云 构建 - 22 -
ThinkPHP 5 简明开发手册
http://serverName/new/5
ThinkPHP5.0的路由规则定义是从根目录开始,而不是基于模块名的。
其实是访问的:
http://serverName/index/new/read/id/5
可以在register方法中指定请求类型,不指定的话默认为GET请求类型,例如:
\think\Route::register('new/:id','New/update','POST');
表示定义的路由规则在POST请求下才有效。
系统提供了为不同的请求类型定义路由规则的简化方法,例如:
\think\Route::get('new/:id','New/read'); // 定义GET请求路由规则
\think\Route::post('new/:id','New/update'); // 定义POST请求路由规则
\think\Route::put('new/:id','New/update'); // 定义PUT请求路由规则
\think\Route::delete('new/:id','New/delete'); // 定义DELETE请求路由规则
\think\Route::any('new/:id','New/read'); // 所有请求都支持的路由规则
如果要定义get和post请求支持的路由规则,也可以用:
\think\Route::register('new/:id','New/read','GET|POST');
我们也可以批量注册路由规则,例如:
\think\Route::register(['new/:id'=>'New/read','blog/:name'=>'Blog/detail']);
\think\Route::get(['new/:id'=>'New/read','blog/:name'=>'Blog/detail']);
\think\Route::post(['new/:id'=>'New/update','blog/:name'=>'Blog/detail']);
注册多个路由规则后,系统会依次遍历注册过的满足请求类型的路由规则,一旦匹配到正确的路由规则后
则开始调用控制器的操作方法,后续规则就不再检测。
定义路由配置文件
如果不希望这么麻烦注册路由规则,可以直接在应用目录下面的 route.php 直接定义路由规则,内容示例
如下:
本文档使用 看云 构建 - 23 -
ThinkPHP 5 简明开发手册
return [
'__pattern__' => [
'name' => '\w+',
],
'new/:id' => 'New/read',
'[blog]' => [
':id' => ['Blog/read', ['method' => 'get'], ['id' => '\d+']],
':name' => ['Blog/read', ['method' => 'post']],
],
];
__pattern__ 表示定义路由变量的全局规则。更详细的使用我们会在后面描述。
路由规则定义
路由定义由三个部分组成:路由表达式、路由地址和参数、路由响应的请求类型。
以register方法为例的话就是:
Think\Route::register('路由表达式','路由地址和参数','请求类型(默认为
GET)','匹配参数(数组)','变量规则');
批量注册的时候规则是:
\think\Route::register(['路由表达式'=>'路由地址和参数',...],'','请求类型(默认为GET)','匹配参数(数组)','变
量规则');
或者
\think\Route::get(['路由表达式'=>'路由地址和参数',...],'','匹配参数(数组)','变量规则'); // GET响应路由
\think\Route::post(['路由表达式'=>'路由地址和参数',...],'','匹配参数(数组)','变量规则'); // POST响应路由
\think\Route::put(['路由表达式'=>'路由地址和参数',...],'','匹配参数(数组)','变量规则'); // PUT响应路由
为了便于描述路由表达式和路由地址的对应关系,下面关于路由规则的描述定义均以批量定义的形式来表
达。
路由表达式
路由表达式统一使用规则路由表达式定义,只能使用字符串。
正则路由定义功能已经废除,改由变量规则定义完成。
规则表达式
本文档使用 看云 构建 - 24 -
ThinkPHP 5 简明开发手册
规则表达式通常包含静态地址和动态地址,或者两种地址的结合,例如下面都属于有效的规则表达式:
'my'=>'Member/myinfo', // 静态地址路由
'blog/:id'=>'Blog/read', // 静态地址和动态地址结合
'new/:year/:month/:day'=>'News/read', // 静态地址和动态地址结合
':user/:blog_id'=>'Blog/read',// 全动态地址
规则表达式的定义以“/”为参数分割符(无论你的URL_PATHINFO_DEPR设置是什么,请确保在定义规
则表达式的时候统一使用“/”进行URL参数分割)。
每个参数中以“:”开头的参数都表示动态参数,并且会自动对应一个GET参数,例如:id表示该处匹配到的
参数可以使用 $_GET['id'] 方式获取, :year :month :day 则分别对应 $_GET['year'] $_GET['month']
$_GET['day'] 。
完全匹配
规则匹配检测的时候只是对URL从头开始匹配,只要URL地址包含了定义的路由规则就会匹配成功,如果
希望完全匹配,可以使用$符号,例如:
'new/:cate$'=> 'News/category',
http://serverName/index.php/new/info
会匹配成功,而
http://serverName/index.php/new/info/2
则不会匹配成功
如果是采用
'new/:cate'=> 'News/category',
方式定义的话,则两种方式的URL访问都可以匹配成功。
路由地址及参数
路由地址和额外参数表示前面的路由表达式最终需要路由到的地址以及一些需要的参数,支持下面4种方式
定义:
定义方式 定义格式
方式1:路由到模块/控制器 '[模块/控制器/操作]?额外参数1=值1&额外参数2=值2...'
本文档使用 看云 构建 - 25 -
ThinkPHP 5 简明开发手册 定义格式
定义方式 '外部地址'(默认301重定向) 或者 ['外部地址','重定向代码']
方式2:路由到重定向地址
方式3:路由到控制器的方 '@控制器/操作'
法
'\完整的命名空间类'(执行run方法) 或者 ['\完整的命名空间类','方法
方式4:路由到类的方法 名']
路由到模块/控制器/操作
这是最常用的一种路由地址定义,路由地址中的 [模块/控制器/操作] 的解析规则是先从后面的操作开始解
析,然后依次往前解析控制器和模块,如果没有则用默认控制器及默认模块。
如果关闭路由功能,那么解析规则其实就是采用该放手。
路由地址中支持多级控制器,使用下面的方式进行设置:
'blog/:id'=>'index/group.blog/read'
表示路由到下面的控制器类,
index/controller/group/Blog
路由到重定向地址
重定向的外部地址必须以“/”或者http开头的地址。
如果路由地址以“/”或者“http”开头则会认为是一个重定向地址或者外部地址,例如:
'blog/:id'=>'/blog/read/id/:1'
和
'blog/:id'=>'blog/read'
虽然都是路由到同一个地址,但是前者采用的是301重定向的方式路由跳转,这种方式的好处是URL可以比
较随意(包括可以在URL里面传入更多的非标准格式的参数),而后者只是支持模块和操作地址。举个例
子,如果我们希望avatar/123重定向到
/member/avatar/id/123_small的话,只能使用:
'avatar/:id'=>'/member/avatar/id/:1_small'
本文档使用 看云 构建 - 26 -
ThinkPHP 5 简明开发手册
路由地址采用重定向地址的话,如果要引用动态变量,也是采用:1、:2 的方式。
采用重定向到外部地址通常对网站改版后的URL迁移过程非常有用,例如:
'blog/:id'=>'/read/:1'
表示当前网站(可能是 )的 blog/123地址会直接重定向到
/read/123。
路由到控制器的方法
这种方式看起来似乎和第一种是一样的,本质的区别是直接执行某个控制器类的方法,而不需要去解析 模
块/控制器/操作 这些。
例如,定义如下路由后:
'blog/:id'=>'@index/blog/read',
系统会直接执行
\think\Loader::action('index/blog/read');
相当于直接调用 \app\index\controller\blog类的read方法。
路由到类的方法
这种方式更进一步,可以支持执行任何类的方法,而不仅仅是执行控制器的操作方法,例如:
'blog/:id'=>['\app\index\service\Blog','read'],
执行的是 \app\index\service\Blog类的read方法。
额外参数
在路由跳转的时候支持额外传入参数对(额外参数指的是不在URL里面的参数,隐式传入需要的操作中,
有时候能够起到一定的安全防护作用,后面我们会提到)。例如:
'blog/:id'=>'blog/read?status=1&app_id=5',
上面的路由规则定义中额外参数的传值方式都是等效的。status和app_id参数都是URL里面不存在的,属
于隐式传值,当然并不一定需要用到,只是在需要的时候可以使用。
匹配参数
本文档使用 看云 构建 - 27 -
ThinkPHP 5 简明开发手册
匹配参数用于设置当前的路由规则详细的匹配条件,匹配参数是优先于路由表达式检测的,目前支持设置
的匹配参数包括:
参数名 参数说明
method 请求类型
ext 伪静态后缀
domain 域名检测
https 是否https访问
callback 自定义检测,可以支持所有is_callable的定义,包括闭包
behavior 自定义行为检测
例如我们可以设置当前的路由规则只有当伪静态后缀为html的时候才会匹配:
\think\Route::register('new/:id','New/read','GET',['ext'=>'html']);
或者
\think\Route::get('new/:id','New/read',['ext'=>'html']);
设置后,URL访问地址:
http://serverName/new/6
将无法正确匹配,所以会报错。只有访问:
http://serverName/new/6.html
的时候才能正常访问。
如果设置如下:
\think\Route::get('new/:id','New/read',['https'=>true]);
那么访问
https://serverName/new/6
才是有效匹配的。
如果定义了
本文档使用 看云 构建 - 28 -
ThinkPHP 5 简明开发手册
\think\Route::get('new/:id','New/read',['callback'=>'checkRoute']);
则调用自定义的checkRoute方法进行检测是否匹配当前路由。
变量规则
ThinkPHP5.0支持在规则路由中为变量用正则的方式指定变量规则,弥补了之前变量规则太局限的问题,
并且支持全局规则设置。使用方式如下:
设置全局变量规则,全局路由有效:
// 设置name变量规则(采用正则定义)
\think\Route::pattern('name','\w+');
// 支持批量添加
\think\Route::pattern(['name'=>'\w+','id'=>'\d+']);
局部变量规则,仅在当前路由有效:
// 定义GET请求路由规则 并设置name变量规则
\Think\Route::get('new/:id','New/read',[],['name'=>'\w+']);
如果一个变量同时定义了全局规则和局部规则,局部规则会覆盖全局变量的定义。
完整URL规则
如果要对整个URL进行变量规则检查,可以进行url 变量规则(效果相当于之前版本的使用正则路由规则检
测),例如:
// 定义GET请求路由规则 并设置完整URL变量规则
\Think\Route::get('new/:id','New/read',[],['__url__'=>'new\/\w+']);
URL映射
URL映射其实属于URL路由的静态简化版,由于不进行路由规则的遍历操作而是直接定位,因此效率较
高,但也因为是类似于静态路由的概念,从而作用有限。
注册URL映射的方法如下:
\think\Route::map('new/top','news/index?type=top');
定义之后,如果我们访问:
http://serverName/new/top
本文档使用 看云 构建 - 29 -
ThinkPHP 5 简明开发手册
其实是访问:
http://serverName/index/news/index/type/top
和路由匹配不同的是,URL映射匹配是完整匹配,所以如果访问:
http://serverName/new/top/var/test
尽管前面也有new/top,但并不会被匹配到index/news/index/type/top。
URL映射定义也支持批量方式:
\think\Route::map(['new/top'=>'news/index?type=top','blog/new'=>'Blog/index?type=new']);
因为URL映射中的映射规则是静态定义,所以不能含有动态变量,而且在匹配的时候必须是完全匹配,所
以下面的定义是不支持的或者无法生效的:
\think\Route::map('new/:id','news/read');
URL映射无法支持匹配请求类型。
如果你绑定了模块那么,URL映射会自动加上模块名。
闭包定义支持
我们可以使用闭包的方式定义一些特殊需求的路由,而不需要执行控制器的操作方法了,例如:
\think\Route::get('test',function(){ echo 'just test';});
\think\Route::get('hello/:name',function($name){ echo 'Hello,'.$name;});
参数传递
闭包定义的参数传递在规则路由和正则路由的两种情况下有所区别。
规则路由
规则路由的参数传递比较简单:
\think\Route::get('hello/:name',function($name){ echo 'Hello,'.$name;});
规则路由中定义的动态变量的名称 就是闭包函数中的参数名称,不分次序。 - 30 -
因此,如果我们访问的URL地址是:
本文档使用 看云 构建
ThinkPHP 5 简明开发手册
http://serverName/hello/thinkphp
则浏览器输出的结果是:
Hello,thinkphp
路由分组
路由分组功能允许把相同前缀的路由定义合并分组,这样可以提高路由匹配的效率,不必每次都去遍历完
整的路由规则。
例如,我们有定义如下两个路由规则的话
'blog/:id' => ['Blog/read', ['method' => 'get'], ['id' => '\d+']],
'blog/:name' => ['Blog/read', ['method' => 'post']],
可以合并到一个blog分组
'[blog]' => [
':id' => ['Blog/read', ['method' => 'get'], ['id' => '\d+']],
':name' => ['Blog/read', ['method' => 'post']],
],
可以使用Route类的group方法进行注册,如下:
\think\Route::group('blog',[
':id' => ['Blog/read', ['method' => 'get'], ['id' => '\d+']],
':name' => ['Blog/read', ['method' => 'post']],
]);
可以给分组路由定义一些公用的路由设置参数,例如:
\think\Route::group('blog',[
':id' => ['Blog/read', [], ['id' => '\d+']],
':name' => ['Blog/read', [],
],['method'=>'get','ext'=>'html']);
URL生成
可以统一使用 \think\Url类生成URL地址,例如:
本文档使用 看云 构建 - 31 -
ThinkPHP 5 简明开发手册
\think\Url::build('hello');
\think\Url::build('index/hello');
// 或者使用帮助函数
U('hello');
U('index/hello');
如果传入的url地址存在路由定义,会自动转换为路由定义。
控制器
访问控制器
ThinkPHP引入了分层控制器的概念,通过URL访问的控制器为访问控制器层(Controller)或者主控制
器,访问控制器是由 Think\App 类负责调用和实例化的,无需手动实例化。URL解析和路由后,会把当前
的URL地址解析到 [ 模块/控制器/操作 ],其实也就是执行某个控制器类的某个操作方法,下面是一个示
例:
namespace app\index\controller;
class New
{
public function index(){
return 'index';
}
public function add(){
return 'add';
}
public function edit($id){
return 'edit:'.$id;
}
}
当前定义的主控制器位于index模块下面,所以当访问不同的URL地址的页面输出如下:
http://serverName/index/new/index // 输出 index
http://serverName/index/new/add // 输出 add
http://serverName/index/new/edit/id/5 // 输出 edit:5
新版的控制器可以不需要继承任何基类,当然,你可以定义一个公共的控制器基础类来被继承,也可以
通过控制器扩展来完成不同的功能(例如Restful实现)。
渲染模板和输出
本文档使用 看云 构建 - 32 -
ThinkPHP 5 简明开发手册
默认的情况下,如果不需要渲染模板,无需继承 think\Controller 类,如果需要进行模板渲染等操作,可
以改为:
namespace app\index\controller;
use think\Controller;
class New extends Controller
{
public function index(){
return $this->fetch();
}
public function add(){
return $this->fetch();
}
public function edit($id){
return $this->show('edit:'.$id);
}
}
新版控制器一般不需要任何输出,直接return即可。 - 33 -
多层控制器
新版支持任意层次的控制器,并且支持路由,例如:
namespace app\index\controller\one;
use think\Controller;
class New extends Controller
{
public function index(){
return $this->fetch();
}
public function add(){
return $this->fetch();
}
public function edit($id){
return $this->show('edit:'.$id);
}
}
访问地址可以使用
http://serverName/index.php/index/one.new/index
空操作和空控制器
空操作
本文档使用 看云 构建
ThinkPHP 5 简明开发手册
空操作是指系统在找不到指定的操作方法的时候,会定位到空操作( _empty )方法来执行,利用这个机
制,我们可以实现错误页面和一些URL的优化。
例如,下面我们用空操作功能来实现一个城市切换的功能。
我们只需要给City类定义一个 _empty (空操作)方法:
namespace app\index\controller;
class City {
public function _empty($name){
//把所有城市的操作解析到city方法
return $this->showCity($name);
}
//注意 showCity方法 本身是 protected 方法
protected function showCity($name){
//和$name这个城市相关的处理
return '当前城市' . $name;
}
}
接下来,我们就可以在浏览器里面输入
http://serverName/index/city/beijing/
http://serverName/index/city/shanghai/
http://serverName/index/city/shenzhen/
由于City并没有定义beijing、shanghai或者shenzhen操作方法,因此系统会定位到空操作方法 _empty
中去解析,_empty方法的参数就是当前URL里面的操作名,因此会看到依次输出的结果是:
当前城市:beijing
当前城市:shanghai
当前城市:shenzhen
空控制器
空控制器的概念是指当系统找不到指定的控制器名称的时候,系统会尝试定位空控制器(Error),利用这个
机制我们可以用来定制错误页面和进行URL的优化。
现在我们把前面的需求进一步,把URL由原来的
http://serverName/index/city/shanghai/
变成
http://serverName/index/shanghai/ - 34 -
本文档使用 看云 构建
ThinkPHP 5 简明开发手册
这样更加简单的方式,如果按照传统的模式,我们必须给每个城市定义一个控制器类,然后在每个控制器
类的index方法里面进行处理。 可是如果使用空模块功能,这个问题就可以迎刃而解了。 我们可以给项目
定义一个Error控制器类
namespace app\index\controller;
class Error {
public function index(){
//根据当前模块名来判断要执行那个城市的操作
$cityName = CONTROLLER_NAME;
return $this->city($cityName);
}
//注意 city方法 本身是 protected 方法
protected function city($name){
//和$name这个城市相关的处理
return '当前城市' . $name;
}
}
接下来,我们就可以在浏览器里面输入
http://serverName/index/beijing/
http://serverName/index/shanghai/
http://serverName/index/shenzhen/
由于系统并不存在beijing、shanghai或者shenzhen控制器,因此会定位到空控制器(Error)去执行,会
看到依次输出的结果是:
当前城市:beijing
当前城市:shanghai
当前城市:shenzhen
空控制器和空操作还可以同时使用,用以完成更加复杂的操作。
Rest控制器
如果需要让你的控制器支持RESTful的话,可以使用Rest控制器,在定义访问控制器的时候直接继承
Think\Controller\Rest即可,例如:
namespace app\index\controller;
use think\controller\Rest;
class New extends Rest
{
}
本文档使用 看云 构建 - 35 -
ThinkPHP 5 简明开发手册
RESTFul方法定义
RESTFul方法和标准模式的操作方法定义主要区别在于,需要对请求类型和资源类型进行判断,大多数情
况下,通过路由定义可以把操作方法绑定到某个请求类型和资源类型。如果你没有定义路由的话,需要自
己在操作方法里面添加判断代码,示例:
namespace app\index\controller;
use think\controller\Rest;
class New extends Rest{
Public function rest() {
switch ($this->_method){
case 'get': // get请求处理代码
if ($this->_type == 'html'){
}elseif($this->_type == 'xml'){
}
break;
case 'put': // put请求处理代码
break;
case 'post': // put请求处理代码
break;
}
}
}
在Rest操作方法中,可以使用$this->_type获取当前访问的资源类型,用$this->_method获取当前的请
求类型。
Rest类还提供了response方法用于REST输出:
response输出数据
用法 response($data,$type='',$code=200)
参数
返回值 data(必须):要输出的数据
type(可选):要输出的类型
支持restOutputType参数允许的类型,如果为空则取restDefaultType参数设置值
code (可选):HTTP状态
无
Response方法会自动对data数据进行输出类型编码,目前支持的包括xml json html。
除了普通方式定义Restful操作方法外,系统还支持另外一种自动调用方式,就是根据当前请求类型和资源
类型自动调用相关操作方法。系统的自动调用规则是:
定义规范 说明
操作名提交类型资源后缀 标准的Restful方法定义,例如 read_get_pdf
操作名_资源后缀 当前提交类型和restDefaultMethod相同的时候,例如read_pdf
本文档使用 看云 构建 - 36 -
ThinkPHP 5 简明开发手册 说明
定义规范 当前资源后缀和restDefaultType相同的时候,例如read_post
操作名_提交类型
这种方式的rest方法定义采用了空操作机制,所以要使用这种方式的前提就是不能为当前操作定义方法,
如果检测到相关的restful方法则不再检查后面的方法规范,例如我们定义了InfoController如下:
namespace app\index\controller;
use think\controller\Rest;
class Info extends Rest{
Public function read_get_xml($id){
// 输出id为1的Info的XML数据
}
Public function read_xml($id){
// 输出id为1的Info的XML数据
}
Public function read_json($id){
// 输出id为1的Info的json数据
}
}
如果我们访问的URL是:
http://serverName/index/info/read/id/1.xml
假设我们没有定义路由,这样访问的是Info模块的read操作,那么上面的请求会调用Info类的
read_get_xml方法,而不是read_xml方法,但是如果访问的URL是:
http://serverName/index/info/read/id/1.json
那么则会调用read_json方法。
分层控制器
除了访问控制器外,我们还可以定义其他分层控制器类,这些分层控制器是不能够被URL访问直接调用到
的,只能在访问控制器、模型类的内部,或者视图模板文件中进行调用。
例如,我们定义New事件控制器如下:
本文档使用 看云 构建 - 37 -
ThinkPHP 5 简明开发手册
namespace app\index\event;
class New {
public function insert(){
echo 'insert';
}
public function update($id){
echo 'update:'.$id;
}
public function delete($id){
echo 'delete:'.$id;
}
}
定义完成后,就可以用下面的方式实例化并调用方法了:
$Event = \think\Loader::controller('New','event');
$Event->update(5); // 输出 update:5
$Event->delete(5); // 输出 delete:5
为了方便调用,系统提供了A快捷方法直接实例化多层控制器,例如:
$Event = A('New','event');
$Event->update(5); // 输出 update:5
$Event->delete(5); // 输出 delete:5
支持跨模块调用,例如:
$Event = A('Admin/New','event');
$Event->update(5); // 输出 update:5
表示实例化Admin模块的New控制器类,并执行update方法。
除了实例化分层控制器外,还可以直接调用分层控制器类的某个方法,例如:
$result = \think\Loader::action('New/update',['id'=>5],'event'); // 输出 update:5
也可以使用快捷R方法实现相同的功能:
$result = R('New/update',['id'=>5],'event'); // 输出 update:5
利用分层控制器的机制,我们可以用来实现Widget(其实就是在模板中调用分层控制器),例如:
定义 index\widget\New 控制器类如下:
本文档使用 看云 构建 - 38 -
ThinkPHP 5 简明开发手册
namespace \app\index\widget;
class New {
public function header(){
echo 'header';
}
public function left(){
echo 'left';
}
public function menu($name){
echo 'menu:'.$name;
}
}
我们在模板文件中就可以直接调用 app\index\widget\New 分层控制器了,例如:
<?php R('New/menu',['name'=>'think'],'widget');?>
框架还提供了W方法用于简化Widget控制器的调用,例如可以直接使用:
<?php W('New/menu',['name'=>'think']);?>
模型
概述
模型类Think\Model配合数据库中间层Think\Db实现了完整的ORM功能,包括CURD和ActiveRecord实
现。
基础模型类Model的设计非常灵活,无需进行任何模型定义,就可以进行相关数据表的ORM和CURD操
作,只有在需要封装单独的业务逻辑的时候,模型类才是必须被定义的。
新版采用了PHP的Trait特性实现了模型的动态组装,可以更加灵活的实现模型的扩展。
模型定义
如果你仅仅需要实现对数据表的CURD操作的话,实际上根本不需要定义模型类,直接实例化基础模型类
即可。(参考模型实例化)
只有当你需要额外定义模型的属性或者方法逻辑的时候,才需要额外定义模型类。模型类一般位于模块的
model 目录下面,例如:
本文档使用 看云 构建 - 39 -
ThinkPHP 5 简明开发手册
namespace app\index\model;
use think\Model;
class New extends Model{
public function getNews(){
//添加自己的业务逻辑
// ...
}
}
实例化代码如下:
$model = \think\Loader::model('index/New');
// 快捷方法
$model = D('index/New');
如果你的模型没有定义模型类的话,可以直接使用
$model = \think\Loader::table('New');
// 快捷方法
$model = M('New');
并且支持传入模型参数:
$config = [
'prefix' => 'think_',
'connection'=> $connection,
...
];
// 或者使用
$model = \think\Loader::table('New',$config);
支持的配置参数包括:
参数名 含义
prefix 数据表前缀
connection 数据库连接信息
table_name 实际的数据表(不含前缀)
true_table_name 实际的数据表(含前缀 支持指定数据库名)
db_name 数据库名称
支持多层的模型类定义,例如:
本文档使用 看云 构建 - 40 -
ThinkPHP 5 简明开发手册
namespace app\index\model\one;
use think\Model;
class New extends Model{
public function getNews(){
//添加自己的业务逻辑
// ...
}
}
实例化代码如下:
$model = \think\Loader::model('index/one/New');
// 快捷方法
$model = D('index/one/New');
注意如果类名是驼峰方式的话,例如:
namespace app\index\model;
use think\Model;
class UserType extends Model{
}
对应的模型文件名应该是:
application\index\model\UserType.php
默认情况下,模型类和数据表的默认对应关系如下:
模型名(类名) 约定对应数据表(假设数据库的前缀定义是 think_)
User think_user
UserType think_user_type
如果你的规则和上面的系统约定不符合,那么需要设置Model类的数据表名称属性。
在ThinkPHP的模型里面,有几个关于数据表名称的属性定义:
属性 说明
tableName 不包含表前缀的数据表名称,一般情况下默认和模型名称相同,只有当你的表名和
当前的模型类的名称不同的时候才需要定义。
包含前缀的数据表名称,也就是数据库中的实际表名,该名称无需设置,只有当上
trueTableName
面的规则都不适用的情况或者特殊情况下才需要设置。
dbName 定义模型当前对应的数据库名称,只有当你当前的模型类对应的数据库名称和配置
文件不同的时候才需要定义。
本文档使用 看云 构建 - 41 -
ThinkPHP 5 简明开发手册
下面举个例子来加深理解,例如,在数据库里面有一个think_categories表,而我们定义的模型类名称是
CategoryModel,按照系统的约定,这个模型的名称是Category,对应的数据表名称应该是
think_category(全部小写),但是现在的数据表名称是think_categories,因此我们就需要设置
tableName属性来改变默认的规则(假设我们定义的数据表前缀 database.db_prefix 为 think_)。
protected $tableName = 'categories';
注意这个属性的定义不需要加表的前缀think_
而对于另外一种特殊情况,数据库中有一个表(top_depts)的前缀和其它表前缀不同,不是think_ 而是
top_,这个时候我们就需要定义 trueTableName 属性了
protected $trueTableName = 'top_depts';
注意trueTableName需要完整的表名定义
除了数据表的定义外,还可以对数据库进行定义,例如:
protected $dbName = 'top';
查询语言
ThinkPHP5.0的查询语言基本和3.2版本保持一致,核心\Think\Model除了基本的CURD和AR查询之外,
还提供了一些统计函数、getField方法,及动态查询方法,使用如下:
$User = D('User');
$User->count();
$User->getField('name');
$User->getByName('thinkphp');
$User->getFieldByName('thinkphp','name');
查询语言基本和3.2版本没有任何变化,请先参考3.2的完全开发手册。 - 42 -
视图模型
视图模型的用法也是需要首先继承视图模型扩展,例如:
namespace app\index\model;
use think\model\View;
class UserType extends View{
}
其它用法和之前的视图模型用法一致。
本文档使用 看云 构建
ThinkPHP 5 简明开发手册
关联模型
namespace app\index\model;
use think\model\Relation;
class User extends Relation{
}
视图
视图功能由Think\View类和模板引擎(驱动)类一起完成。
实例化视图类
// 实例化视图类
$view = new \Think\View();
// 渲染模板输出
return $view->fetch();
如果你的控制器继承了\think\Controller类的话,则可以直接使用
// 渲染模板输出
return $this->fetch();
需要注意的是,ThinkPHP5的视图fetch方法不会直接渲染输出,只是返回解析后的内容。如果在控制
器类返回 视图解析内容的话,渲染输出系统会自动调用think\Response类的send方法进行渲染输出。
模板定位规则
模板文件目录默认位于模块的view目录下面,视图类的fetch方法中的模板文件的定位规则如下:
如果调用没有任何参数的fetch方法:
return $view->fetch();
则按照系统的默认规则定位模板文件到:
[模板文件目录]/当前控制器名/当前操作名.html
如果(指定操作)调用: - 43 -
本文档使用 看云 构建
ThinkPHP 5 简明开发手册 - 44 -
return $view->fetch('add');
则定位模板文件为:
[模板文件目录]/当前控制器名/add.html
如果调用控制器的某个模板文件使用:
return $view->fetch('user/add');
则定位模板文件为:
[模板文件目录]/user/add.html
全路径模板调用:
return $view->fetch(MODULE_PATH.'view/public/header.html');
则定位模板文件为:
MODULE_PATH.'view/public/header.html'
模板主题支持
默认并不支持模板主题功能,需要配置开启,例如:
$view = new \think\View();
return $view->theme('blue')->fetch('User/add');
表示使用blue模板主题风格输出,定位模板文件为:
[模板文件目录]/blue/User/add.html
或者也可以使用下面的方式支持模板主题:
$view = new \think\View();
return $view->fetch('blue/User/add');
和上面使用模板主题功能输出的模板文件是相同的。
如果要进行自动侦测模板主题的话,按照如下方式使用:
本文档使用 看云 构建
ThinkPHP 5 简明开发手册
$view = new \think\View();
return $view->theme(true)->fetch('User/add');
theme(true) 表示开启模板主题自动侦测功能,通常是在URL地址中传入模板主题参数,默认情况下,只
需要使用:
http://serverName/moduleName/controllerName/actionName/t/blue
之后,模板主题名称将会被保存到Cookie中,直到重新指定新的模板主题名称。
设置输出参数
可以在视图实例化的时候设置参数或者在模板输出之前动态设置参数,例如下面两种方式等效:
// 实例化视图类的时候设置参数
$view = new \think\View(['view_suffix'=>'.html','view_depr'=>'/']);
// 或者使用http方法动态设置视图输出参数
$view->config(['view_suffix'=>'.html','view_depr'=>'/']);
支持独立设置某个参数,例如:
$view->config('view_suffix','.html');
模板输出替换
支持对视图输出的内容进行字符替换,例如:
$view->config('parse_str',['__PUBLIC__'=>'/public/'])->fetch();
如果需要全局替换的话,可以直接在配置文件中添加:
'parse_str'=>[
'__PUBLIC__'=>'/public/',
'__ROOT__' => '/',
]
在渲染模板或者内容输出的时候就会自动根据设置的替换规则自动替换。
设置模板引擎
使用View类的engine方法设置当前视图输出的模板解析引擎,如果没有指定模板引擎的话 默认为PHP自
身模板。
本文档使用 看云 构建 - 45 -
ThinkPHP 5 简明开发手册
// 设置模板引擎
return $view->engine('think',['tpl_path'=>MODULE_PATH.'view/','cache_path'=>MODULE_PATH.'cach
e/','compile_type'=>'File'])->fetch();
模板引擎的参数根据不同的模板引擎而异。
视图类的模板引擎驱动位于 think\view\driver\ 目录下面,可以自行扩展。
Think模板引擎的驱动类实现如下:
namespace think\view\driver;
use think\Template;
class Think {
private $template = null;
public function __construct($config=[]){
$this->template = new Template($config);
}
public function fetch($template,$data=[],$cache=[]){
if(is_file($template)) {
$this->template->display($template,$data,$cache);
}else{
$this->template->fetch($template,$data);
}
}
}
模板引擎驱动类需要实现的接口方法就是fetch方法。
如果你不需要任何模板引擎,直接使用原生PHP作为模板解析的话,可以使用
$view->engine('php')->fetch();
如果全局使用的话,还可以直接配置:
'engine_type' => 'php',
视图绑定数据
绑定数据到模板输出有三种方式:
1、使用assign方法给模板变量赋值:
本文档使用 看云 构建 - 46 -
ThinkPHP 5 简明开发手册
// 实例化视图类
$view = new \think\View();
$view->assign('name','ThinkPHP');
$view->assign('email','thinkphp@');
// 或者批量赋值
$view->assign(['name'=>'ThinkPHP','email'=>'thinkphp@']);
// 模板输出
return $view->fetch();
2、直接对象赋值
// 实例化视图类
$view = new \think\View();
$view->name = 'ThinkPHP';
$view->email= 'thinkphp@';
// 模板输出
return $view->fetch();
3、在输出模板的时候传入模板变量
例如:
return $view->fetch('index',['name'=>'ThinkPHP','email'=>'thinkphp@']);
其他设置
如果希望直接解析内容而不通过模板文件的话,可以使用:
return $view->show($content,$vars);
指定当前的视图模板文件目录:
return $view->config('view_path',MODULE_PATH.'tpl/')->fetch();
模板
5.0对模板引擎进行了重构,主要改进如下:
兼容原来所有的标签功能和用法,已 对正则进行了优化,标签库和内置的普通标签可以使用一样的边界
符,比如都用"{}",只要不重名不会相互干扰,这样这些标签就可以和html标签区分开。(默认标签库和变
量标签配置都采用统一的定界符 {和} )
本文档使用 看云 构建 - 47 -
ThinkPHP 5 简明开发手册
模板支持多级继承
C继承B,而B又继承了A,C中的block会覆盖B和A中的同名block。
include标签支持多层嵌套,可以传变量。
如:
include file="Public/nav" selected="{$id}"
在Public/nav模板用[selected]得到的是[$id}被解析后的值,而在3.2版中这样的写法是不能正确得到{$id}
的值的。
增强了.语法的应用范围
{$user.name.$group.name} 解析后是
{:substr($varname.aa, $varname.bb)} 解析后是
.语法在各个标签中都可以使用,$a.b.c这样的形式都能正确解析成$a['b']['c']
增加了一些新的语法
{$varname.aa ?? 'xxx'} 表示如果有设置$varname则输出$varname,否则输出'xxx'。 解析后的代码为:
{$varname?='xxx'} 表示$varname为真时才输出xxx。 解析后的代码为:
{$varname ?: 'no'} 表示如果$varname为真则输出$varname,否则输出no。解析后的代码为:
{$a==$b ? 'yes' : 'no'} 前面的表达式为真输出yes,否则输出no, 条件可以是==、===、!=、!==、
>=、<=
对if标签及foreach也加了一些更简洁的用法
{if condition="表达式"}
{if (表达式)}
{if 表达式}
这三种写法结果是一样的
{foreach $list as $v} 解析后是最简洁的,只一个foreach语句
{foreach name="list" item="v“} 这僦是原来的写法,解析后foreach外层会多一if判断,item换成id也
可以
{foreach name="list" id="v" key="key" index="i" mod="2" offset="2" length="5"}
volist上的功能,foreach都有,只是volist默认会带上一些参数,而foreach需要指定这些参数才会生效
数据库
本文档使用 看云 构建 - 48 -
ThinkPHP 5 简明开发手册
ThinkPHP内置了抽象数据库访问层,把不同的数据库操作封装起来,我们只需要使用公共的Db类进行
操作,而无需针对不同的数据库写不同的代码和底层实现,Db类会自动调用相应的数据库驱动来处
理。采用PDO方式,目前包含了Mysql、SqlServer、PgSQL、Sqlite、Oracle、Mongo等数据库的支
持。
如果应用需要使用数据库,必须配置数据库连接信息,数据库的配置文件有多种定义方式。
一、全局配置定义
常用的配置方式是在公共配置文件或者模块配置文件中添加下面的配置参数:
'database'=> [
// 数据库类型
'type' => 'mysql',
// 数据库连接DSN配置
'dsn' => '',
// 服务器地址
'hostname' => '127.0.0.1',
// 数据库名
'database' => 'thinkphp',
// 数据库用户名
'username' => 'root',
// 数据库密码
'password' => '',
// 数据库连接端口
'hostport' => '',
// 数据库连接参数
'params' => [],
// 数据库编码默认采用utf8
'charset' => 'utf8',
// 数据库表前缀
'prefix' => 'think_',
// 数据库调试模式
'debug' => true,
// 数据库部署方式:0 集中式(单一服务器),1 分布式(主从服务器)
'deploy' => 0,
// 数据库读写是否分离 主从式有效
'rw_separate' => false,
// 读写分离后 主服务器数量
'master_num' => 1,
// 指定从服务器序号
'slave_no' => '',
];
也支持独立数据库配置文件定义的方式,例如在 application/database.php文件中定义如下:
本文档使用 看云 构建 - 49 -