ThinkPHP之入门讲解
1 ThinkPHP
ThinkPHP
是一个免费开源的,快速、简单的面向对象的轻量级PHP开发框架,是为了敏捷WEB应用开发和简化企业应用开发而诞生的。
ThinkPHP 官网地址
1.1 框架
1.1.1 目录讲解
1.1.1.1 5.x
ThinkPHP 5.x 目录结构如下,默认是支持多模块
以下内容以5.0为基础讲解
project 应用部署目录
├─application 应用目录(可设置)
│ ├─common 公共模块目录(可更改)
│ ├─index 模块目录(可更改)
│ │ ├─config.php 模块配置文件
│ │ ├─common.php 模块函数文件
│ │ ├─controller 控制器目录
│ │ ├─model 模型目录
│ │ ├─view 视图目录
│ │ └─ ... 更多类库目录
│ ├─command.php 命令行工具配置文件
│ ├─common.php 应用公共(函数)文件
│ ├─config.php 应用(公共)配置文件
│ ├─database.php 数据库配置文件
│ ├─tags.php 应用行为扩展定义文件
│ └─route.php 路由配置文件
├─extend 扩展类库目录(可定义)
├─public WEB 部署目录(对外访问目录)
│ ├─static 静态资源存放目录(css,js,image)
│ ├─index.php 应用入口文件
│ ├─router.php 快速测试文件
│ └─.htaccess 用于 apache 的重写
├─runtime 应用的运行时目录(可写,可设置)
├─vendor 第三方类库目录(Composer)
├─thinkphp 框架系统目录
│ ├─lang 语言包目录
│ ├─library 框架核心类库目录
│ │ ├─think Think 类库包目录
│ │ └─traits 系统 Traits 目录
│ ├─tpl 系统模板目录
│ ├─.htaccess 用于 apache 的重写
│ ├─.travis.yml CI 定义文件
│ ├─base.php 基础定义文件
│ ├─composer.json composer 定义文件
│ ├─console.php 控制台入口文件
│ ├─convention.php 惯例配置文件
│ ├─helper.php 助手函数文件(可选)
│ ├─LICENSE.txt 授权说明文件
│ ├─phpunit.xml 单元测试配置文件
│ ├─README.md README 文件
│ └─start.php 框架引导文件
├─build.php 自动生成定义文件(参考)
├─composer.json composer 定义文件
├─LICENSE.txt 授权说明文件
├─README.md README 文件
├─think 命令行入口文件
1.1.1.2 6.0以上
6.0以上,默认安装后的目录结构就是一个单应用模式,如下结构
www WEB部署目录(或者子目录)
├─app 应用目录
│ ├─controller 控制器目录
│ ├─model 模型目录
│ ├─ ... 更多类库目录
│ │
│ ├─common.php 公共函数文件
│ └─event.php 事件定义文件
│
├─config 配置目录
│ ├─app.php 应用配置
│ ├─cache.php 缓存配置
│ ├─console.php 控制台配置
│ ├─cookie.php Cookie配置
│ ├─database.php 数据库配置
│ ├─filesystem.php 文件磁盘配置
│ ├─lang.php 多语言配置
│ ├─log.php 日志配置
│ ├─middleware.php 中间件配置
│ ├─route.php URL和路由配置
│ ├─session.php Session配置
│ ├─trace.php Trace配置
│ └─view.php 视图配置
│
├─view 视图目录
├─route 路由定义目录
│ ├─route.php 路由定义文件
│ └─ ...
│
├─public WEB目录(对外访问目录)
│ ├─index.php 入口文件
│ ├─router.php 快速测试文件
│ └─.htaccess 用于apache的重写
│
├─extend 扩展类库目录
├─runtime 应用的运行时目录(可写,可定制)
├─vendor Composer类库目录
├─.example.env 环境变量示例文件
├─composer.json composer 定义文件
├─LICENSE.txt 授权说明文件
├─README.md README 文件
├─think 命令行入口文件
如果需要一个多应用的项目架构,目录结构可以参考下面的结构进行调整,但首先需要安装ThinkPHP的多应用扩展(命令:composer require topthink/think-multi-app
),具体可以参考多应用模式
www WEB部署目录(或者子目录)
├─app 应用目录
│ ├─app_name 应用目录
│ │ ├─common.php 函数文件
│ │ ├─controller 控制器目录
│ │ ├─model 模型目录
│ │ ├─view 视图目录
│ │ ├─config 配置目录
│ │ ├─route 路由目录
│ │ └─ ... 更多类库目录
│ │
│ ├─common.php 公共函数文件
│ └─event.php 事件定义文件
│
├─config 全局配置目录
│ ├─app.php 应用配置
│ ├─cache.php 缓存配置
│ ├─console.php 控制台配置
│ ├─cookie.php Cookie配置
│ ├─database.php 数据库配置
│ ├─filesystem.php 文件磁盘配置
│ ├─lang.php 多语言配置
│ ├─log.php 日志配置
│ ├─middleware.php 中间件配置
│ ├─route.php URL和路由配置
│ ├─session.php Session配置
│ ├─trace.php Trace配置
│ └─view.php 视图配置
│
├─public WEB目录(对外访问目录)
│ ├─index.php 入口文件
│ ├─router.php 快速测试文件
│ └─.htaccess 用于apache的重写
│
├─extend 扩展类库目录
├─runtime 应用的运行时目录(可写,可定制)
├─vendor Composer类库目录
├─.example.env 环境变量示例文件
├─composer.json composer 定义文件
├─LICENSE.txt 授权说明文件
├─README.md README 文件
├─think 命令行入口文件
注意
:多应用模式部署后,记得删除app
目录下的controller
目录(系统根据该目录作为判断是否单应用的依据)
1.1.2 配置文件
1.1.2.1 5.x
三个层级的配置文件:
- 框架主配置文件(惯例配置文件) thinkphp/convention.php
- 应用公共配置文件 application/config.php, application/database.php 对整个应用生效
- 模块配置文件 application/模块目录/config.php 对当前模块生效
其他说明:
- 配置文件格式 return array( 键值对 );
- 加载顺序: 框架主配置文件->应用公共配置文件->模块配置文件
- 配置文件生效顺序: 后加载的生效(后加载的配置项会覆盖之前配置项)
- 如果要手动进行配置,一般不要修改框架本身的主配置文件,而是在应用或者模块配置文件中进行配置。
1.1.2.2 6.0以上
在 ThinkPHP 6以上,thinkphp/convention.php
这个配置文件确实已经不再存在了。ThinkPHP 6 相较于之前的版本有了较大的改动,特别是在配置文件的管理方面。具体来说:
- 在 ThinkPHP 6 中,默认的配置文件被分散到了多个独立的配置文件中,放置在
config
目录下。每个配置文件针对不同的功能模块,例如 app.php、database.php、cache.php 等。这样的设计让配置更加模块化和清晰。 - convention.php 的去除
在 ThinkPHP 5.x 及之前的版本中,thinkphp/convention.php
用于存放框架的默认配置,这些配置在未被用户覆盖时会生效。
从 ThinkPHP 6 开始,这种集中式的默认配置文件被取消,取而代之的是多个配置文件。 - 配置优先级
在 ThinkPHP 6 中,用户可以通过config
目录中的文件来覆盖框架的默认配置。框架提供了一些默认配置,但这些配置是直接通过代码实现的,而不是放在一个单独的文件中。 - 如何自定义配置
如果需要自定义配置,可以在 config 目录中创建自己的配置文件,或者直接修改现有的配置文件。或者通过config()
函数来获取和设置配置项。
1.1.3 函数文件
1.1.3.1 5.x
框架助手函数文件 thinkphp/helper.php,一般不建议直接修改thinkphp/helper.php
应用公共函数文件 application/common.php
模块函数文件 application/模块目录/common.php
1.1.3.1 6.0以上
移除thinkphp/helper.php
:
- 在 ThinkPHP 5.x 中,
thinkphp/helper.php
文件,主要用于定义一些常用的辅助函数。这些辅助函数在项目开发中可以直接调用,简化了开发工作。
但是,在ThinkPHP 6.x
及更高版本中,thinkphp/helper.php
文件被移除了。原因是框架开发团队希望简化核心代码,并且推荐开发者通过引入自己需要的库或工具来实现相应的功能,而不是依赖于框架内置的辅助函数。
在 ThinkPHP 6.x 中的替代方案:Composer
引入工具包:对于一些常用的功能,可以通过Composer
引入第三方库来实现。例如,可以使用symfony/var-dumper
来替代 dump 函数。- 自定义辅助函数:如果有一些常用的函数,可以在项目中创建自己的辅助函数文件,然后在项目的入口文件(如
app.php
)中引入它。
移除app/模块目录/common.php
:
- 在 ThinkPHP 6 中,
app/模块目录/common.php
文件被移除是为了简化和灵活化项目结构。如果需要在模块中定义公共函数,可以在app/common.php
中统一管理
倡导将公共函数集中管理,通常放在app/common.php
文件中,这样可以避免每个模块都定义自己的common.php
,从而减少冗余代码,并且使得跨模块调用更加便捷
1.2 控制器
1.2.1 控制器的后缀
打开配置文件application/config.php,有如下配置:'controller_suffix' => false
,
表示默认情况下,控制器无特殊后缀。例如 Index控制器,文件名为Index.php
如果需要进行设置,可以设置为(我们不需要这么设置):'controller_suffix' => 'Controller'
,表示控制器以Controller
为后缀。例如Index控制器,文件名为IndexController.php
定义位置及命名规则:
- 定义位置:
application/模块目录/controller/目录下
(6.0以上默认是app了) - 命名规则:
控制器名称(首字母大写) + (控制器后缀,默认没有) + .php
- 默认:Index控制器 Index.php,User控制器 User.php,UserType控制器 UserType.php,Test控制器 Test.php
编写控制器:
- 声明命名空间:
namespace app\模块目录名\controller
- 引入控制器基类(可选):
use think\Controller;
,其中think
是命名空间Controller
是基类控制器 - 定义当前控制器类,继承控制器基类(可选)
1.2.2 框架中的命名空间
命名空间本身是PHP就有的,用来防止命名冲突问题的。
TP框架中的命名空间,通常和目录
挂钩。
原因:TP中的自动加载机制
,会将类的命名空间作为加载路径的一部分。
TP中命名空间使用:
- 声明命名空间 使用
namespace
关键字 - 引入指定的类 使用
use
关键字命名空间\类名称
- 完全限定式访问 在使用类时,
\完整命名空间\类名称(继承和实例化)
- 如果一个类没有命名空间,使用
\类名
1.2.3 url访问
ThinkPHP5.0
框架中,默认使用PATH_INFO
方式的url进行访问。
示例:http://www.tpshop.com/index.php/Index/Test/index/page/10
格式:http://域名/入口文件/模块名/控制器名称/操作方法名称/参数名/参数值
隐藏入口文件写法:http://域名/模块名/控制器名称/操作方法名称/参数名/参数值
1.2.4 调试模式
1.2.4.1 5.x
默认情况下,如果代码有误(比如控制器名拼写有误),会出现比较模糊的错误
错误描述比较模糊,不方便进行错误调试。这种模式通常叫做部署模式
(生产模式)。
开发阶段可以将框架设置为调试模式,便于进行错误调试:
修改 项目目录\application目录\config.php
中 app_debug=>true
开启调试模式后,报错信息格式就会很清晰
1.2.4.2 6.0以上
调试模式配置在 config/app.php
文件中,通过 app_debug => true
设置
如果通过create-project
默认安装的话, 会在根目录自带一个.example..env
文件,你可以直接更名为.env
文件中修改APP_DEBUG = true
也可以
1.3 创建模块
1.3.1 创建前台和后台模块
一个典型的应用是由多个模块组成的(通常有前台网站模块和后台管理系统模块),这些模块通常都是应用目录下面的一个子目录,每个模块都有自己独立的配置文件、公共文件和类库文件。
我们给项目创建home(前台)和admin(后台)两个模块
1.3.2 设置默认访问模块
打开配置文件application/config.php
,有如下配置:'default_module' => 'index'
,表示默认访问模块为index模块,可以更改默认模块为home模块
'default_module' => 'home'
在 6.0以上 中,可以通过修改配置文件来设置默认访问的模块。默认模块的配置通常在 config/app.php
文件中完成:'default_module' => 'admin'
1.4 Request请求类
1.4.1 获取输入变量
要获取当前的请求信息,可以使用\think\Request类
$request = \think\Request::instance();
或者使用助手函数
$request = request();
也可以单独获取get变量或者post变量
Request::instance()->get();
Request::instance()->post();
input('get.');
input('post.');
特殊说明:路由变量与get变量
http://www.tpshop.com/home/test/index/id/100?page=10
param
:能够获取所有参数(id, page)get
:只能获取?后面的请求字符串的参数(page)route
:只能获取到?前面的路由中的参数(id)
1.4.2 参数绑定
1.4.2.1 按名称绑定
方法参数绑定
是把URL地址(或者路由地址)中的变量作为操作方法的参数直接传入。
<?php
namespace app\index\Controller;
class Blog
{
public function read($id)
{
return 'id='.$id;
}
public function archive($year, $month='01')
{
return 'year='.$year.'&month='.$month;
}
}
注意这里的操作方法并没有具体的业务逻辑,只是简单的示范。
URL的访问地址分别是:
http://serverName/index.php/index/blog/read/id/5
http://serverName/index.php/index/blog/archive/year/2016/month/06
两个URL地址中的id参数和year和month参数会自动和read操作方法以及archive操作方法的同名参数绑定。
1.4.2.1 按顺序绑定(6.0后不支持)
按照URL的参数顺序进行绑定的方式,合理规划URL参数的顺序绑定对简化URL地址可以起到一定的帮助。
还是上面的例子,控制器不变,还是使用:
<?php
namespace app\index\Controller;
class Blog
{
public function read($id)
{
return 'id='.$id;
}
public function archive($year='2016',$month='01')
{
return 'year='.$year.'&month='.$month;
}
}
我们在配置文件中添加配置参数如下:
// URL参数方式改成顺序解析
'url_param_type' => 1,
接下来,访问下面的URL地址:
http://serverName/index.php/index/blog/read/5
http://serverName/index.php/index/blog/archive/2016/06
注意
:按参数顺序绑定的话,参数的顺序不能随意调整,在使用路由定义的情况下不建议使用顺序绑定,而且按 顺序绑定参数的话,操作方法的参数只能使用路由变量或者PATHINFO变量,而不能使用get或者post变量。
1.4.3 依赖注入
依赖注入
:简单的说,要在一个类A中使用另一个依赖类B时,不直接在类A中实例化类B,而是先实例化类B后再以参数的形式传入类A.
1.4.3.1 架构方法和方法注入
在控制器的架构方法中会自动注入当前请求对象,例如:
namespace app\index\controller;
use think\Request;
class Index
{
protected $request;
public function __construct(Request $request)
{
$this->request = $request;
}
public function hello(Request $request)
{
return 'Hello,' . $request->param('name') . '!';
}
}
- 接收参数 获取请求对象,调用param方法;或者直接调用input函数
- 参数绑定 在方法上声明形参,自动接收对应同名参数,主要针对id参数
- 依赖注入 在方法上声明类型形参(Request $request),自动获取请求对象
可以找到任何一种方法 接收请求参数
获取请求对象
$request = request();
$request = \think\Request::instance();
$request = $this->request; //仅限于继承了底层控制器的情况下
public function save(Request $request) //依赖注入
接收请求参数 param方法
$params = $request->param();
$params = input();
$params = request()->param();
$id = $request->param('id');
$id = input('id');
public function edit($id)//参数绑定
1.4.3.2 invoke
5.x中 invoke
方法自动调用(v5.0.2)
5.0.2版本开始,如果依赖注入的类有定义一个可调用的静态invoke
方法,则会自动调用invoke
方法完成依赖注入的自动实例化。
invoke
方法的参数是当前请求对象实例,例如:
namespace app\index\model;
use think\Model;
class User extends Model
{
public static function invoke(Request $request)
{
$id = $request->param('id');
return User::get($id);
}
}
1.5 视图
1.5.1 视图模板定位
1.5.1.1 5.x
为了对模板文件更加有效的管理,ThinkPHP对模板文件进行目录划分,默认的模板文件定义规则是:视图目录/控制器名(小写)/操作名(小写)+模板后缀
默认的视图目录是模块的view目录
,框架的默认视图文件后缀是.html
。
比如home模块 Index控制器index方法要调用的模板定义为view/index/index.html
渲染模板
最常用的是继承系统的控制器基类
后调用fetch
方法,调用格式:fetch('[模板文件]'[,'模板变量(数组)'])
模板文件的写法支持下面几种:
用法 | 描述 |
---|---|
不带任何参数 | 自动定位当前操作的模板文件 |
[模块@][控制器/][操作] | 常用写法,支持跨模块 |
完整的模板文件名 | 直接使用完整的模板文件名(包括模板后缀) |
下面是一个最典型的用法,不带任何参数:
// 不带任何参数 自动定位当前操作的模板文件
return $this->fetch();
表示系统会按照默认规则自动定位模板文件,其规则是:当前模块/默认视图目录/当前控制器(小写)/当前操作(小写).html
但是从V5.0.16+
版本开始,默认的模板文件名规则改为实际操作方法名的小写+下划线
写法。例如,如果操作方法是 showPage
,那么模板文件名将变成 show_page.html
,但可以配置template.auto_rule
的值为2
恢复之前的全小写规则。
如果有更改模板引擎的view_depr
设置(假设 'view_depr'=>'_'
)的话,则上面的自动定位规则变成:
当前模块/默认视图目录/当前控制器(小写)_当前操作(小写).html
,view_depr
是用于定义控制器名
与操作名
之间在视图模板中的分隔符
return $this->fetch('edit');
表示调用当前控制器下面的edit模板
return $this->fetch('member/read');
表示调用Member控制器下面的read模板。
return $this->fetch('admin@member/edit');
跨模块渲染模板
渲染输出不需要写模板文件的路径和后缀。这里面的控制器和操作并不一定需要有实际对应的控制器和操作,只是一个目录名称和文件名称而已,例如,你的项目里面可能根本没有Public控制器,更没有Public控制器的menu操作,但是一样可以使用
return $this->fetch('public/menu');
输出这个模板文件。理解了这个,模板输出就清晰了。
fetch方法支持在渲染输出的时候传入模板变量,例如:
return $this->fetch('read', ['a'=>'a','b'=>'b']);
V5.0.4+版本开始,支持从视图根目录开始读取模板,例如:
$this->fetch('/menu');
表示读取的模板是:当前模块/默认视图目录/menu.html
如果你的控制器类没有继承系统的控制器基类,请使用系统提供的助手函数view进行渲染输出。
1.5.1.2 6.0以上
默认情况下,框架会自动定位模板文件路径,优先定位应用目录下的view目录
,这种方式的视图目录下就是应用的控制器目录。
单应用模式
├─app
│ └─view(视图目录)
│ ├─index index控制器目录
│ │ └─index.html index模板文件
│ └─ ... 更多控制器目录
多应用模式
├─app
│ ├─app1 (应用1)
│ │ └─view(应用视图目录)
│ │ ├─index index控制器目录
│ │ │ └─index.html index模板文件
│ │ └─ ... 更多控制器目录
│ │
│ └─ app2... (更多应用)
第二种方式是视图文件和应用类库文件完全分离,统一放置在根目录下的view目录。
单应用模式
├─view 视图文件目录
│ ├─index index控制器目录
│ │ └─index.html index模板文件
│ └─ ... 更多控制器目录
多应用模式
如果是多应用模式的话,这种方式下view目录
下面首先是应用子目录。
├─view 视图文件目录
│ ├─index(应用视图目录)
│ │ ├─index index控制器目录
│ │ │ └─index.html index模板文件
│ │ └─ ... 更多控制器目录
如果需要自定义view目录
名称,可以通过设置view_dir_name
配置参数:'view_dir_name' => 'template'
模板渲染的最典型用法是直接使用fetch方法,不带任何参数:
<?php
namespace app\index\controller;
use think\facade\View;
class Index
{
public function index()
{
// 不带任何参数 自动定位当前操作的模板文件
return View::fetch();
}
}
表示系统会按照默认规则自动定位视图目录下的模板文件,其规则是:控制器名(小写+下划线)/操作名.html
默认的模板文件名规则改为实际操作方法名的小写+下划线写法
。但可以配置auto_rule参
数的值来改变当前操作的自动渲染规则。
auto_rule
配置:
1
:操作方法的小写+下划线2
:操作方法全部转换小写3
:保持和操作方法一致
如果没有按照模板定义规则来定义模板文件(或者需要调用其他控制器下面的某个模板),可以使用:
指定模板输出
return View::fetch('edit');
表示调用当前控制器下面的edit模板
return View::fetch('member/read');
表示调用Member控制器下面的read模板。
跨应用渲染模板
return View::fetch('admin@member/edit');
支持从视图根目录开始读取模板,例如:
return View::fetch('/menu');
表示读取的模板是 menu.html
如果模板文件位置比较特殊或者需要自定义模板文件的位置,可以采用下面的方式处理。
return View::fetch('../template/public/menu.html');
这种方式需要带模板路径和后缀指定一个完整的模板文件位置,这里的../template/public目录是相对于当前项目入口文件位置。如果是其他的后缀文件,也支持直接输出,例如:
return View::fetch('../template/public/menu.tpl');
只要../template/public/menu.tpl是一个实际存在的模板文件。
1.5.2 模板渲染
在控制器方法中,使用assign
方法进行模板赋值,使用fetch
方法进行模板渲染。
使用助手函数view()
,进行模板渲染并赋值。
注意
:模板中输出变量值: {$模板变量名}