实践学习php,thinkphp,Redis,vue,uni-app等技术,推荐开源电商系统likeshop,可以借鉴思路,可去版权免费商用,gitee下载地址:
点击进项目地址
国产 PHP web 框架
ThinkPHP5的运行环境要求PHP5.6以上,兼容PHP8.0
开发基础手册
安装
使用composer安装
composer create-project topthink/think=5.1.* tp5
启动服务
cd tp
php think run
然后就可以在浏览器中访问
http://localhost:8000
更新框架
composer update topthink/framework
采用 Composer 和 git 方式下载
github 地址
https://github.com/top-think/think/releases/tag/v5.1.41
目录结构
初始的目录结构如下:
www WEB部署目录(或者子目录)
├─application 应用目录
│ ├─common 公共模块目录(可以更改)
│ ├─module_name 模块目录
│ │ ├─common.php 模块函数文件
│ │ ├─controller 控制器目录
│ │ ├─model 模型目录
│ │ ├─view 视图目录
│ │ └─ ... 更多类库目录
│ │
│ ├─command.php 命令行定义文件
│ ├─common.php 公共函数文件
│ └─tags.php 应用行为扩展定义文件
│
├─config 应用配置目录
│ ├─module_name 模块配置目录
│ │ ├─database.php 数据库配置
│ │ ├─cache 缓存配置
│ │ └─ ...
│ │
│ ├─app.php 应用配置
│ ├─cache.php 缓存配置
│ ├─cookie.php Cookie配置
│ ├─database.php 数据库配置
│ ├─log.php 日志配置
│ ├─session.php Session配置
│ ├─template.php 模板引擎配置
│ └─trace.php Trace配置
│
├─route 路由定义目录
│ ├─route.php 路由定义
│ └─... 更多
│
├─public WEB目录(对外访问目录)
│ ├─index.php 入口文件
│ ├─router.php 快速测试文件
│ └─.htaccess 用于apache的重写
│
├─thinkphp 框架系统目录
│ ├─lang 语言文件目录
│ ├─library 框架类库目录
│ │ ├─think Think类库包目录
│ │ └─traits 系统Trait目录
│ │
│ ├─tpl 系统模板目录
│ ├─base.php 基础定义文件
│ ├─console.php 控制台入口文件
│ ├─convention.php 框架惯例配置文件
│ ├─helper.php 助手函数文件
│ ├─phpunit.xml phpunit配置文件
│ └─start.php 框架入口文件
│
├─extend 扩展类库目录
├─runtime 应用的运行时目录(可写,可定制)
├─vendor 第三方类库目录(Composer依赖库)
├─build.php 自动生成定义文件(参考)
├─composer.json composer 定义文件
├─LICENSE.txt 授权说明文件
├─README.md README 文件
├─think 命令行入口文件
可以使用php自带webserver快速测试切换到根目录后,启动命令:php think run
命名规范
ThinkPHP5 遵循PSR-2命名规范和PSR-4自动加载规范,并且注意如下规范:
目录和文件
- 目录不强制规范,驼峰和小写+下划线模式均支持;
- 类库、函数文件统一以
.php
为后缀; - 类的文件名均以命名空间定义,并且命名空间的路径和类库文件所在路径一致;
- 类名和类文件名保持一致,统一采用驼峰法命名(首字母大写);
函数和类、属性命名
- 类的命名采用驼峰法,并且首字母大写,例如
User
、UserType
,默认不需要添加后缀,例如UserController
应该直接命名为User
; - 函数的命名使用小写字母和下划线(小写字母开头)的方式,例如
get_client_ip
; - 方法的命名使用驼峰法,并且首字母小写,例如
getUserName
; - 属性的命名使用驼峰法,并且首字母小写,例如
tableName
、instance
; - 以双下划线“__”打头的函数或方法作为魔法方法,例如
__call
和__autoload
;
常量和配置
- 常量以大写字母和下划线命名,例如
APP_PATH
和THINK_PATH
; - 配置参数以小写字母和下划线命名,例如
url_route_on
和url_convert
;
数据表和字段
- 数据表和字段采用小写加下划线方式命名,并注意字段名不要以下划线开头,例如
think_user
表和user_name
字段,不建议使用驼峰和中文作为数据表字段命名。
URL解析模式
http://serverName/index.php/模块/控制器/操作/参数/值
url 重写模式
如果没有开启伪静态,只能使用 PATH_INFO 模式
开启方式:apache
-
httpd.conf文件,加载 mod_rewrite.so ,去掉前面的 # 号即可
D:\phpstudy_pro\Extensions\Apache2.4.39\conf
-
index.php 同级目录下 .htaccess 文件(框架已做好,重启环境即可)
设计模式
多模块,单模块
默认是多模式
单模块
// thinkphp/index.php
Container::get('app')->bind('test')->run()->send();
config/app.php 模块设置中设置
// 默认的空模块名
'empty_module' => ''
用途:如果发生错误可以跳转到指定页面
空模块
通过环境变量设置空目录,将不存在的目录统一指向指定目录
config/app.php 模块设置中设置
URL 地址 public/index/one,即:控制器/操作
单一模块的命名空间也变更为:app/controller
空模块只有在多模块开启,且没有绑定模块的情况下生效
环境变量
控制器定义
-
控制器,即 controller,控制器文件存放在 controller 目录下
-
类名和文件名大小写保持一致,采用驼峰法()
-
如果类名是 双字母组合,比如 class HelloWorld,url 访问时必须用:hello_world;
想要原样方式访问 URL,则需要关闭配置文件中的自动转换
‘url_convert’ => false;
-
如果想要改变命名空间 app 为其他,可以在根目录下创建 .env 文件
写上键值对即可
app_namespace=application
渲染输出
-
直接 return
-
json输出,使用 json 函数,数组可以使用此种方式
class HelloWorld { public function eat($who='xiaoli') { $data=array('1'=>'one','2'=>'second'); return json($data); } } # output {"1":"one","2":"second"}
-
使用 view 输出模板
初始化
如果继承了基类控制器,可以定义控制器初始化方法:initialize()
initialize() 方法会在调用控制器方法之前执行:
<?php
namespace app\test\controller;
use think\Controller;
class HelloWorld extends Controller
{
protected function initialize()
{
parent::initialize(); // TODO: Change the autogenerated stub
}
}
initialize() 方法不需要返回任何值,输出用 PHP 方式,return 无效
控制器操作
前置操作
<?php
namespace app\test\controller;
use think\Controller;
class HelloWorld extends Controller
{
protected $beforeActionList = [
# 每次都调用first
'first',
# 除了调用 one 时不调用 second
'second' => ['except' => 'one'],
# 只有调用 one 和 two 时调用 third
'third' => ['only' => 'one','two']
];
protected function first()
{
echo 'first<br>';
}
protected function second()
{
echo 'second<br>';
}
protected function third()
{
echo 'third<br>';
}
public function index()
{
echo 'index';
}
public function one()
{
echo 'one';
}
public function two()
{
echo 'two';
}
}
跳转和重定向
controller 类提供了两个跳转方法
success(msg,url)
error(msg)
不指定 url 默认跳转 $_SERVER[‘HTTP_REFERER’]
成功或者错误有一个固定的页面模板:‘thinkphp/tpl/dispatch_jump.tpl’;
在 app.php 配置文件中,可以更改跳转页面
‘dispatch_success_tmpl’=> Env::get(‘think_path’)
<?php
namespace app\test\controller;
use think\Controller;
class HelloWorld extends Controller
{
protected $flag = false;
public function index()
{
if ($this->flag) {
$this->success('注册成功', '../');
# 没有url,他会死循环
} else {
$this->error('失败');
}
return 'index';
}
}
空方法和空控制器
空方法
当访问一个不存在的方法时,系统会报错,可以使用 _empty() 来拦截
class HelloWorld extends Controller
{
public function _empty($name)
{
return '不存在当前方法:' . $name;
}
}
# output
不存在当前方法:two
空控制器
当访问一个不存在的控制器时,系统也会报错,使用 Error 类来拦截
<?php
namespace app\test\controller;
use think\Request;
class Error
{
public function index(Request $request)
{
return '当前控制器不存在:'.$request->controller();
}
}
系统默认为 Error 类,自定义可以在 app.php 配置文件中修改:
‘empty_controller’=>‘Error’
数据库与模型
ThinkPHP 采用内置抽象层将不同的数据库操作进行封装处理
数据抽象层基于 PDO 模式,无需针对不同的数据库编写相应代码
使用
连接数据库
config/database.php ,配置连接信息
简单实例:
class HelloWorld
{
public function show()
{
$data = Db::name('admin')->select();
// 如果设置了表前缀,使用 name 不需要加前缀
$data = Db::table('admin')->select();
// 如果设置了表前缀,使用 table 需要加前缀
return json($data);
}
}
模型
# 可以在 config/app.php,开启sql语句显示
'app_trace' => true,
基本查询
$data1 = Db::table('admin')->find();
// 查询一条数据使用find
// return Db::getLastInsID();
// 得到最近的一条 sql 查询的原生语句
$data2 = Db::table('admin')->where('uid', '3')->find();
// var_dump($data2);
// 没有查到任何值,返回 null
$data3 = Db::table('admin')->where('uid', '3')->findOrFail();
// 查询一条数据,没有数据时抛出异常
$data4 = Db::table('admin')->where('uid', '3')->findOrEmpty();
// 查询一条数据,没有数据时抛出一个空数组
$data5 = Db::table('admin')->select();
// 查询多列数据
// selectOrEmpty,selectOrFail
$data6 = \db('admin')->select();
// 助手函数 db,更方便的查询
$data7 = Db::name('admin')->where('uid','1')->value('pass');
// 查询 admin 表下,uid=1 的 pass 字段的值,没有数据返回 null
$data8 = Db::name('admin')->column('pass');
// 查询指定列的值,没有数据返回空数组
$data9 = Db::name('admin')->column('name','uid');
// 指定 uid 作为列值的索引,即按 uid 的值进行排序
return json($data9);
链式查询
对象实例化
public function show()
{
$user = Db::name('admin');
$user -> select();
// 对象实例保存
// 当同一个对象实例第二次查询后,会保留第一次查询的值
$data1 = $user->order('uid')->select();
$data2 = $user->select();
// return json($data2);
// SELECT * FROM `admin` ORDER BY `uid`
// 使用 removeOption() 方法,清理掉上一次查询的保留值
$data3 = $user->removeOption('order')->select();
// SELECT * FROM `admin`
return Db::getLastSql();
}
增删改查操作
查询表达式
比较查询
class Search
{
public function index()
{
$result = Db::name('admin')->where("uid",'<>','1')->select();
return json($result);
}
}
<>,>,<,=,<=,>=
区间查询
class Search
{
public function index()
{
// 模糊查询
$result = Db::name('admin')->where('name','like','ad%')->select();
return json($result);
// 数组传递
$result01 = Db::name('admin')->where('name','like',['ad%,b%'])->select()
// 快捷方式
$result01 = Db::name('admin')->whereLike('name',['ad%,b%'])->select()
$result01 = Db::name('admin')->whereNotLike('name',['ad%,b%'])->select()
$result01 = Db::name('admin')->whereBetween('name',[2,3])->select()
$result01 = Db::name('admin')->whereNotBetween('name',[2,3])->select()
$result01 = Db::name('admin')->whereIn('name','1,2,3')->select()
$result01 = Db::name('admin')->whereNotIn('name','1,2,3')->select()
$result01 = Db::name('admin')->whereNull('name')->select()
$result01 = Db::name('admin')->whereNotNull('name')->select()
}
}
时间查询
聚合、原生、子查询
设置主键
<?php
namespace app\test\model;
use think\Model;
class Admin extends Model
{
protected $pk='uid';
}
初始化
protected static function init()
{
// parent::init(); // TODO: Change the autogenerated stub
echo '初始化';
}
模型操作数据和数据库操作一样,只不过不需要指定表了
查询
UserModel::select();
删除
UserModel::destory
数据库操作返回列表是一个二维数组 [[ ]] ,模型返回结果集 [{ }]
<?php
namespace app\test\controller;
use \app\test\model\Admin as AdminModel;
// 避免重名
class Search
{
public function index()
{
$result = AdminModel::select();
return json($result);
}
}
添加和删除
public function insert()
{
// 实例化
$user = new AdminModel();
$user->name='xiaoming';
$user->pass='12333333';
$user->save();
}
public function delete()
{
$user = new AdminModel();
// 数据删除
// 通过主键id查询
$user =AdminModel::get(1);
// 再通过delete方法,将数据删除,返回布尔值
$user->delete();
// 直接使用静态方法调用 destory()
AdminModel::destroy(1);
// 也可以使用条件查询
}
}
。。。。。
。。。。。
模板视图
模板引擎
模板引擎分为两种,一种是内置的,一种作为插件引入,一般使用内置即可
内置的模板引擎的配置文件是 config/template.php
// 模板路径
'view_path' => '',
默认就是 view 目录
视图渲染
See.php
<?php
namespace app\test\controller;
use think\Controller;
class See extends Controller
{
public function index()
{
// 自动定位
return $this->fetch();
// 指定模板
return $this->fetch('edit');
// D:\phpstudy_pro\WWW\thinkphp\tp5\application\test\view\see\edit.html
//指定目录下的模板
return $this->fetch('public/edit');
// D:\phpstudy_pro\WWW\thinkphp\tp5\application\test\view\public\edit.html
// 指定模块下的模板,适用于多模块
return $this->fetch('admin@public/edit');
// D:\phpstudy_pro\WWW\thinkphp\tp5\application\admin\view\public\edit.html
// view_path 下的模块
return $this->fetch('/edit');
// D:\phpstudy_pro\WWW\thinkphp\tp5\application\test\view\edit.html
// 如果没有继承 Controller 模块的话,可以使用助手函数 view() 方法,具体使用方法同上
return view();
}
}
视图赋值
-
在继承控制器基类的情况下,可以使用 assign() 方法进行赋值
// See.php class See extends Controller { public function index() { $this->assign('name','hello'); return $this->fetch('index'); } } // view/see/index.html {$name}
-
通过数组的方式,进行多个变量的赋值
// See.php $this->assign(['name' => 'hello', 'sex' => 'male', 'mail' => '2333@qq.com']); return $this->fetch('index'); // view/see/index.html {$name}.{$sex}.{$mail}
-
assign() 和 fetch() 方法合二为一
return $this->fetch('index',['name'=>'xiaoli','sex'=>'male','mail'=>'wwww@qq.com']);
-
使用 display() 方法,可以不通过模板直接解析变量
$content='{$name}.{$sex}.{$mail}'; return $this->display($content,['name'=>'xiaoli','sex'=>'male','mail'=>'wwww@qq.com']);
-
使用 view() 助手函数实现渲染并赋值操作
1. $this->assign(['name' => 'hello', 'sex' => 'male', 'mail' => '2333@qq.com']); return view('index'); 2. return view('index',['name' => 'hello', 'sex' => 'male', 'mail' => '2333@qq.com']); 3. return view('index')->assign(['name' => 'hello', 'sex' => 'male', 'mail' => '2333@qq.com']);
-
使用 View::share() 静态方法,可以在系统任意位置做全局变量赋值
// public/static/index.php \think\facade\View::share('key','value'); // view/see/index.html {$name}.{$sex}.{$mail}.{$key}
视图过滤
-
可以使用 filter() 方法,对模板页面输出的变量进行过滤
class See extends Controller { public function index() { $this->assign(['name' => 'hello1', 'sex' => 'male1', 'mail' => '2333@qq.com']); return $this->filter(function ($content) { return str_replace('1', '<br>', $content); })->fetch(); // $content 表示所有的模板变量 } }
-
如果控制器有N个方法,都需要过滤,可以在初始化中全局过滤
class See extends Controller { public function initialize() { return $this->filter(function ($content) { return str_replace('1', '<br>', $content); }); } public function index() { $this->assign(['name' => 'hello1', 'sex' => 'male1', 'mail' => '2333@qq.com']); return $this->fetch(); } }
-
也可以使用助手函数实现模板变量的过滤
class See extends Controller { public function index() { $this->assign(['name' => 'hello1', 'sex' => 'male1', 'mail' => '2333@qq.com']); return view('index')->filter( function ($content) { return str_replace('1', '<br>', $content); } ); } }
模板变量输出
模板变量的输出方式,控制器实现赋值
$this->assign('name','ThinkPHP');
当模板位置创建好后,输出控制器的赋值变量时用花括号和$符号
{$name}
当程序在运行的时候,会在 runtime/temp 目录下生成一个编译文件
<?php echo htmlentities($name); ?>
- 如果传递的是数组,也会对应
// controller/See.php
$data=['name' => 'hello1', 'sex' => 'male1', 'mail' => '2333@qq.com'];
$this->assign('user',$data); // user是名字
return $this->fetch();
// view/see/index.php
{$user.name}.{$user.sex}.{$user['mail']}
// runtime/temp/
<?php echo htmlentities($user['name']); ?>.<?php echo htmlentities($user['sex']); ?>.<?php echo htmlentities($user['mail']); ?>
- 对象
// controller/See.php
$obj=new \stdClass();
$obj->username='xiaoli';
$obj->mail='oooo@qq.com';
$this->assign('obj',$obj);
return $this->fetch('index');
// view/see/index.php
{$obj->username}.{$obj->mail} // 只能用指向符号
// runtime/temp/
<?php echo htmlentities($obj->username); ?>.<?php echo htmlentities($obj->mail); ?>
- 其他输出
1.如果输出的变量没有值可以直接设置默认值代替
// controller/See.php
$obj=new \stdClass();
$obj->username='';
$obj->mail='oooo@qq.com';
$this->assign('obj',$obj);
return $this->fetch('index');
// view/see/index.php
{$obj->username|default='nodata'}.{$obj->mail}
2.使用 $Think.xxx.yyy 方式,可以输出系统的变量及常量
// 变量
系统的变量有:$_SERVER $_ENV $_GET $_POST $_REQUEST $_SESSION 和 $_COOKIE
{$Think.get.name} # 下图
// 常量
{$Think.const.PHP_VERSION}
或
{$Think.PHP_VERSION}
3.系统配置也可以在模板输出,配置参数可以在 config 文件下
{$Think.config.default_return_type}
函数
1.模板 md5 加密
// controller/See.php
$this->assign('password','123456');
return $this->fetch();
// view/see/index.php
{$password|md5}
2.系统默认在编译时会采用 htmlentities (HTML实体化转义)过滤函数防止 XSS 跨站脚本攻击
<?php echo htmlentities(md5($password)); ?>
更换过滤函数,可以在配置文件中设置
// config/template.php
'default_filter' => 'htmlspecialchars'
如果不需要转义,可以使用 raw 过滤方法
ThinkPHP 提供的其他过滤方法
3.可以使用 substr 进行切片
4.在模板中支持多个函数进行操作,用 | 号隔开即可,函数从左到右依次执行
// view/see/index.php
{$password|md5|upper|substr=0,3}
#### 运算符
在模板中的运算符有 + - * / % ++ –
如果模板中有运算符,则函数方法则不再支持
# 错误 {$password1 + $password2|upper|substr=0,3}
模板中可以实现三元运算,包括其他写法
// view/see/index.php
{$password ? 'true':'false'}
<!-- password 为 true 返回 字符串true,否则返回false-->
{$password ?= 'true'}
<!-- password 为 true 返回 字符串true-->
{$Think.get.name ?? 'not exist'}
<!-- 用于系统变量,没有值时输出 -->
{$password ?: 'not exist'}
<!-- 用于普通变量,没有值时输出 -->
<!-- runtime/temp -->
<?php echo !empty($password) ? 'true' : 'false'; ?>
<!-- password 为 true 返回 字符串true,否则返回false-->
<?php if(!empty($password)) echo 'true'; ?>
<!-- password 为 true 返回 字符串true-->
<?php echo (htmlentities(app('request')->get('name'))) ? htmlentities(app('request')->get('name')) : 'not exist'; ?>
<!-- 用于系统变量,没有值时输出 -->
<?php echo !empty($password) ? htmlentities($password) : 'not exist'; ?>
<!-- 用于普通变量,没有值时输出 -->
模板循环标签
foreach
1.控制前端先通过模型把对应的数据列表给筛选出来
$data=AdminModel::all();
$this->assign('list',$data);
return $this->fetch();
2.前端使用 foreach 进行循环
{foreach $list as $key=>$value}
{$key}{$value.name}{$value.pass}</br>
{/foreach}
// list 是数据集,key是索引,value是对象,key和value的名字不是绝对的
3.可以在模板中直接执行模型数据调用,而不需要在控制器中设置
{foreach :model('admin')->all() as $key=>$value}
{$key}{$value.name}{$value.pass}</br>
{/foreach}
volist
{volist name='list' id='obj'} // 不用加 $
{$key}{$obj.name}{$obj.pass}</br>
{/volist}
// name 属性表示数据总集,id 属性表示当前循环的数据单条集
- offset 和 length 属性表示从第 offset 条开始显示 length 条数据,下标从 0 开始
{volist name='list' id='obj' offset='2' length='3'}
{$key}{$obj.name}{$obj.pass}</br>
{/volist}
//
3user11233333
4user11233333
5user11233333
- eq 标签
mod
// 实现奇偶判断
{volist name='list' id='obj' mod='2'}
{eq name='mod' value='0'}
{$key}{$obj.name}{$obj.pass}</br>
{/eq}
{/volist}
// config/template.php
foreach($__LIST__ as $key=>$obj): $mod = ($i % 2 );++$i;if($mod == '0'):
//
0user11233333
2user11233333
4user11233333
6user11233333
8xiaoming12333333
empty
// 如果为空就返回 nodata
{volist name=':model("admin")->where("uid","100")->all()' id='obj' empty='nodata'}
{$key}{$value.name}{$value.pass}</br>
{/volist}
key
// $key 默认从0开始计数,$i 默认从1开始计数
{volist name='list' id='obj' }
{$i}-{$key}-{$value.name}-{$value.pass}</br>
{/volist}
//
1-0-xiaoming-12333333
2-1-xiaoming-12333333
3-2-xiaoming-12333333
key='k' 则不需要指定 {$i},$i失效
{volist name='list' id='obj' key='k'}
{$k}-{$key}-{$value.name}-{$value.pass}</br>
{/volist}
for
{for start='1' end='10' comparison='<' name='i'} //i可以换
{$i}
{/for}
1 2 3 4 5 6 7 8 9
比较标签
- eq
{eq name='$name' value='siri1'} // name后加可以加$,也可以不加,value如果是字符串不加$,如果是变量则需要加$
equal
{else/}
not equal
{/eq}
其他比较标签
{gt}(>)
{egt}(>=)
{lt}(<)
{elt}(<=)
{heq}(===)
{nheq}(!==)
- compare
所有的标签都可以使用 compare 来代替
{compare type='eq' name='name' value='siri'}
equal
{/compare}
定义标签
1.定义变量:使用 {assign} 标签
{assign name='var' value='123'}
{$var}
2.定义常量:使用 {define} 标签
{define name='PI' value='3.14'}
{$Think.const.PI}
3.PHP原生编码:使用 {php} 标签
{php}
echo '原生防止脱发'
{/php}
原生编码就是 PHP 编码,不能再使用模板引擎的特殊编码方式,不支持 eq 等标签语法
4.标签嵌套
{foreach $list as $key=>$value}
{eq name='value.name' value='xiaoming'}
{$key}{$value.name}{$value.pass}
{/eq}
{/foreach}
条件判断标签
- switch
<?php
namespace app\test\controller;
use think\Controller;
class See extends Controller
{
public function index()
{
$this->assign(['number'=>'10','cond'=>'10']);
return $this->fetch('index');
}
}
{switch $number}
{case 1}1{/case}
{case 10|20|30}10/20/30{/case}
<!--支持多个条件判断,使用 | 分隔-->
{case $cond}equal{/case}
<!--case 后面也可以是变量,设置变量后不可以使用|线-->
{default/}default
{/switch}
- if
1.
{if $number>10}
>10
{/if}
2.
{if ($number>10) OR ($cond<5) }
<!--最好加括号-->
true
{/if}
3.
{if $number>10 }
number>10 true
{else/}
number>10 False
{/if}
4.
{if $number>100 }
number>100 true
{elseif $number>50}
number>50 true
{else/}
number>0 true
{/if}
5.{if 标签里的条件判断支持 PHP 写法,不支持 TP 函数}
// See.php
class See extends Controller
{
public function index()
{
$man=new \stdClass();
$man->name='Lee';
$this->assign('man',$man);
return $this->fetch('index');
}
}
// index.html
{if strtoupper($man->name)=='LEE'}
Lee
{/if}
范围标签
- in
1.in
{in name='$number' value='10,20,30'}
{$number} in array
{/in}
//10 in array
2.notin
{notin name='$number' value='10,20,30'}
{$number} not in array
{/notin}
//11 not in array
3.in else
{in name='$number' value='10,20,30'}
{$number} in array
{else/}
{$number} not in array
{/in}
//11 not in array
4.notin else
- between
1. between
{between name='$number' value='10,20'}
{$number} in this area
{/between}
//11 in this area
2.notbetween
{notbetween name='$number' value='15,20'}
{$number} not in this area
{/notbetween}
//11 not in this area
value 只能有两个值,表示一个区间,第三个值无效,区间也可以用字母,比如 a-z
3.
{between name='$number' value='a,z'}
{$number} in this area
{/between}
//b in this area
-
present
判断变量是否已经定义,是否存在
1.present
// See.php
$this->assign('number','');
// index.html
{present name='$number'}
$number is exist
{else/}
$number is not exist
{/present}
// $number is exist
2.notpresent
{notpresent name='$num'}
$num is not exist
{/notpresent}
// num is not exist
- empty
1.empty
// See.php
$this->assign('number','');
// index.html
{empty name='$number'}
$number is empty
{else/}
$number is not empty
{/empty}
//$number is empty
2.notempty
-
defined
判断常量是否定义(是否存在)
模板的加载包含输出
{include fil e='public/header,public/nav'}
<!--如果写header.php则需要完整绝对路径-->
<!--{include file='../application/view/public/header.html'}-->
index
{include file='public/footer'}
调用数据
<!--block/index.html-->
{include file='public/header,public/nav' title='template' keyword='this is a temp!'}
index
{include file='public/footer'}
<!--public/header.html-->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>[title]</title>
</head>
<body>
header
[keyword]
<br>
替换文件
有事需要调用静态文件
可以将静态文件存放在根目录 public/static/css
如果直接写完整目录,比较繁长,可以将路径整理打包
在目前二级目录下,template.php 中,配置新增一个参数
'tpl_replace_string'=>[
'__JS__'=>'static/js',
'__CSS__'=>'static/css',
]
// 配置文件修改后,需要删除缓存编译文件,重新创建
如果在顶级域名下,直接改成 /static/css 即可,加一个反斜杠
html 文件调用端,直接通过 __CSS__(__JS)__
配置的魔术方法调用即可
文件加载
-
传统方式调用 CSS 或者 JS 文件时,采用 link 和 script 标签实现
-
系统提供了更加智能的加载方式,方便加载 CSS 和 JS 等文件
-
使用 {load} 标签和 href 属性来链接,不需要设置任何其他参数
{load href='__CSS__/basic.css' /} {load href='__JS__/basic.js' /} {load href='__CSS__/basic.css,__JS__/basic.js' /}
-
还提供了两个别名 {js}、{css} 来更好地实现可读性
{js href='__JS__/basic.js'} {css href='__CSS__/basic.css'}
{js} 和 {css} 只是别名而已,php 是更具后缀来识别的
模板的布局和继承
模板布局
- 第一种方法
默认情况下,不支持模板布局功能,需要在配置文件中开启
在配置文件 template.php 中,配置开始模板布局功能
'layout_on' => true,
# 配置 layout 的位置,文件名
'layout_name' => 'public/layout',
使用{__CONTENT__}
类似魔法方法的标签来引入 index.html '主体’内容
如果需要更改 {__CONTENT__}
,可以在配置文件中配置
'layout_item'=>'{__REPLACE__}'
注意:如果更改了配置文件,需要删除 temp 下的编译文件再刷新
- 第二种方法
只要在 index.html 的最上面加上如下代码,可实现模板布局
{layout name='public/layout' replace='[__CONTENT__]'}
#标签注释
{/*layout name='public/layout' replace='[__CONTENT__]'*/}
```{/*layout name='public/layout' replace='[__CONTENT__]'*/}
- 第三种方法
直接在控制器端执行 layout(true) 方法即可,false 表示临时关闭
$this->view->engine->layout(true);
这种方法不过不用默认的路径,还是要配置路径
template.php
'layout_name' => 'public/layout',
模板继承
类似于 flask 继承
首先创建基文件 public/base.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>base</title>
</head>
<body>
<h1>base</h1>
{$name}
<!--传递变量-->
{block name='nav'}
{include file='public/nav'}
{/block}
<!--挖坑-->
</body>
</html>
block/extend.html
{extend name='public/base'}
or
{extend name='public:base'}
{block name='nav'}
{/block}
# 默认继承过来没有内容,如果需要原来的内容要加 {__block__}
{block name='nav'}
{__block__}
{/block}
模板中的一些杂项
- 模板标签原样输出
{literal}
{$name}
{/literal}
- 模板注释
html 注释只是不显示,还是会解析
# controller/see.php
$this->assign('name','lihua');
# view/see/other.html
<!--{$name}-->
正确注释
# 单行注释
{//name}
# 多行注释
{/*
*/}
注意:注释和 { 符号之间不能有空格,否则无法实现注释隐藏
生成编译文件后,注释的内容会被自动删除,不会显示
- 标签扩展
路由
内置服务器:php think run
test/controller/Address.php
class Address extends Controller
{
public function detail($id)
{
return 'detail'.$id;
}
}
5.html 会被解析成变量 5,其余后缀名不可以
添加路由
# route/route.php
think\facade\Route::get('details/:id','test/Address/detail');
# 注意:被替换的 url 开头不需要加 /
test 是模块名
Address 是控制器名
detail 是操作名
url 写法变为
选择 HTTP methods
think\facade\Route::get('details/:id','test/Address/detail',['GET']);
think\facade\Route::get('details/:id','test/Address/detail',['POST']);
think\facade\Route::get('details/:id','test/Address/detail',['GET|POST']);
路由分类
// 静态
think\facade\Route::get('static','test/Address/staticfunc');
// 动态
think\facade\Route::get('details/:id','test/Address/detail');
// 多参数动静态结合,url 可以输多个变量
think\facade\Route::get('double/:id/:uid','test/Address/double',['GET']);
// 规则完全匹配,只能有两个变量 也可以开启完全匹配,在 app.php 中配置
think\facade\Route::get('double/:id/:uid$','test/Address/double',['GET']);
// 多参数动静态结合,uid可选
think\facade\Route::get('choose/:id/[:uid]','test/Address/double',['GET']);
// 全动态地址,不限制 search 是否固定
think\facade\Route::get(':search/:id/:uid','test/Address/double',['GET']);
class Address extends Controller
{
public function staticfunc()
{
return 'staticfunc';
}
public function detail($id)
{
return 'detail'.$id;
}
public function double($id,$uid='')
{
return 'detail'.$id.'uid'.$uid;
}
}
控制使用路由地址
类似于 flask endpoint
- 通过 url() 方法来实现
# Address.php
class Address extends Controller
public function index()
{
return url('test/Address/index',['id'=>10]);
}
}
# route/route.php
think\facade\Route::get('index','test/Address/index',['GET']);
- 定义标识,起别名
# Address.php
class Address extends Controller
public function index()
{
return url('index',['id'=>10]);
}
}
# route/route.php
think\facade\Route::get('index','test/Address/index',['GET'])->name('index');
路由的变量规则
系统的默认路由规则为:\W+ 字母、数字、下划线
单个限制
# route/route.php
think\facade\Route::get('details/:id','test/Address/detail')->pattern('id','\d+');
pattern rule 为正则表达式
全部限制
# route/route.php
\think\facade\Route::pattern([
'id'=>'\d+',
'uid'=>'\w+',
]);
think\facade\Route::get('details/:id','test/Address/detail');
think\facade\Route::get('double/:id/:uid','test/Address/double');
组合变量规则
# route/route.php
think\facade\Route::get('double-:id-:uid','test/Address/double');
之间的分隔符可以换成 - _ 等
动态组合拼装
如果地址和参数都是模糊动态的,可以使用如下方法
# route/route.php
think\facade\Route::get('dynmic-:name-:id','test/Hello_:name/index');
think\facade\Route::get('dynmic-:name-:id','test/Hello_<name>/index');
# test/controller/HelloWorld.php
public function index($id)
{
return 'index'.$id;
}
闭包
路由直接返回函数
Route::get('think', function () {
return 'hello,ThinkPHP5!';
});
Route::get('bibao/:name', function ($name) {
return 'hello!'.$name;
});
路由地址
- 路由地址一般为:控制器/方法,如果多模块则是:模块/控制器/方法
- 支持多级控制器
# test/controller/group/Address.php
<?php
namespace app\test\controller\group;
use think\Controller;
class Address extends Controller
{
public function detail($id)
{
return 'detail'.$id;
}
}
# route/route.php
think\facade\Route::get('gdetails/:id','test/group.Address/detail');
- 支持动态路由地址以及额外参数地址
# test/controller/Address.php
class Address extends Controller
{
public function param()
{
echo $this->request->param('flag');
}
}
# route/route.php
think\facade\Route::get('param/:id','test/Address/param?flag=aaaa');
- 静态方法
# test/controller/Address.php
class Address extends Controller
{
public static function stat($id){
return 'static function'.$id;
}
}
# route/route.php
think\facade\Route::get('stat/:id','app\test\controller\Address::stat');
使用 命名空间
- 路由对模板传值
# test/view/see/other.html
<body>
{$name}
<br>
{$email}
</body>
# route/route.php
//\think\facade\Route::view('see/:name','test@See/other');
\think\facade\Route::view('see/:name','test@See/other',['email'=>'2222@qq.com']);
重定向
think\facade\Route::get('details/:id','http://www.ocean888.cn')->status(302);
think\facade\Route::redirect('details/:id','http://www.ocean888.cn',302);
路由缓存
解析之后保存,提高效率,需要在部署环境下生效,在 app.php 开启
'route_check_cache' => true,
# 关闭调试模式
'app_debug' => true,
删除缓存
php think clear
路由参数
设置路由的时候,可以设置点三个数组参数,主要实施匹配检测和行为执行
- ext 参数作用是检测 URL 后缀,比如,强制所有 URL 后缀为 .html
\think\facade\Route::get('yyds/:id','test/Address/detail',['ext'=>'html']);
# 第三组参数也可以作为对象的方法存在
\think\facade\Route::get('yyds/:id','test/Address/detail')->ext('html');
- https 参数作用是检测是否为 https 请求
- 全局统一配置
app.php
'url_html_suffix'='html'
- 禁止某些后缀
denyExt('')
['denyExt'=>'']
- filter对额外参数进行检测
filter('id',10)
- model 绑定到模型,第三方参数设置 false 避免异常,也可以多参数
# test/controller/Address.php
class Address extends Controller
{ # 数据注入
public function search(\app\test\model\Admin $user)
{
return json($user);
}
}
# route/route.php
# 默认参数是id
\think\facade\Route::get('model/:uid','test/Address/search')->model('app\test\model\Admin');
\think\facade\Route::get('model/:uid','test/Address/search')->model('uid','app\test\model\Admin');
# 加第三个参数 false 忽略报错
\think\facade\Route::get('model/:uid','test/Address/search')->model('uid','app\test\model\Admin',false);
- option 参数作用是全局的路由进行配置,且可以多次调用
\think\facade\Route::option('ext','html')->option('https','true');
快捷路由
快捷路由可以快速给控制器注册路由,还可以以不同的请求类型设置前缀
快捷路由控制器和方法编写规则:给方法前面加上 get 或 post 等代表对应请求类型
就是更具不同的请求类型,返回对应的函数
# test/controller/Short.php
class Short extends Controller
{
public function index()
{
return 'index';
}
public function getInfo()
{
echo 'getinfo';
}
public function postInfo()
{
echo 'postinfo';
}
}
# route/route.php
\think\facade\Route::controller('short','test/Short');
路由分组
将前缀相同的路由进行合并分组,以简化路由定义,提高匹配效率
- 使用 group() 方法,来进行分组路由的注册
# test/controller/collect.php
class Collect extends Controller
{
public function index()
{
return 'index';
}
public function read($id)
{
return 'read is' . $id;
}
public function who($name)
{
return 'name is'.$name;
}
}
# route/route.php
\think\facade\Route::group('col',[
'index'=>'test/Collect/index',
':id'=>'test/Collect/read',
':name'=>'test/Collect/who'
])->ext('html')->pattern(['id'=>'\d+$','name'=>'\w+$']);
由于限制了 ext 后缀名,所以必须加 .html
- 使用 group() 方法,并采用闭包的形式进行注册
\think\facade\Route::group('col', function () {
\think\facade\Route::get(':id','test/Collect/read');
\think\facade\Route::get(':name','test/Collect/who');
})->ext('html')->pattern(['id'=>'\d+$','name'=>'\w+$']);
- prefix 简化路由
# route/route.php
\think\facade\Route::group('col',[
'index'=>'index',
':id'=>'read',
':name'=>'who'
])->prefix('test/Collect/')->ext('html')->pattern(['id'=>'\d+$','name'=>'\w+$']);
- append() 方法,可以传入额外参数,用 request 获取
# test/controller/collect.php
public function read($id)
{
echo $this->request->param('flag');
return 'read is' . $id;
}
# route/route.php
\think\facade\Route::group('col',[
'index'=>'index',
':id'=>'read',
':name'=>'who'
])->prefix('test/Collect/')->ext('html')->pattern(['id'=>'\d+$','name'=>'\w+$'])->append(['flag'=>1]);
- 路由规则(主要是分组和域名路由)定义的文件,加载时会解析消耗较多的资源,尤其是规则特别庞大的时候,开启延迟解析只有在匹配的时候才会注册解析
# config/app.php
// 是否开启路由延迟解析
'url_lazy_route' => true,
注解路由
可以在注释中直接创建路由,默认为关闭
开启路由注解
// config/app.php
// 使用注解路由
'route_annotation' => false,
使用
在要加入注解的位置右击,选择 generate
MISS
1.全局 MISS 类似开启强制路由功能,匹配不到相应规则时会自动跳转到 MISS
# route/route.php
\think\facade\Route::miss('test/See/miss');
# test/controller/See.php
public function miss()
{
return '404 not found!';
}
2.分组 MISS 可以在路由分组中使用 miss 方法,当不满足匹配规则时跳转到这里
# route/route.php
\think\facade\Route::group('col', function () {
\think\facade\Route::get(':id','test/Collect/read');
\think\facade\Route::miss('test/See/miss');
})->ext('html')->pattern(['id'=>'\d+$','name'=>'\w+$']);
跨域请求
# route/route.php
\think\facade\Route::miss('test/See/miss')->header('Access-Control-Allow-Origin','www.ocean888.cn')->allowCrossDomain();
allowCrossDomain() 允许跨域请求
header('Access-Control-Allow-Origin','www.ocean888.cn') 限制只能来自 www.ocean888.cn 的跨域请求
绑定
路由绑定可以简化 URL 和路由规则的定义,可以绑定到模块/控制器/操作
由于本身不是规则,需要关闭强制路由后测试,本身绑定并不是定义路由
未绑定(默认绑定 index )
绑定后
\think\facade\Route::bind('test');
可以绑定到模块、控制器、操作
别名
给一个控制器起一个别名,可以通过别名自动生成一系列规则
例:
\think\facade\Route::alias('index','test/See/index');
也支持别名设置限定条件
\think\facade\Route::alias('index','test/See/index',['ext'=>'html']);
别名路由和快捷路由在 PHP6 已经废弃
资源路由
1.资源路由,采用固定的常用方法来实现简化 URL 的功能
2.系统提供了一个命令,方便开发者快速生成一个资源控制器
php think make:controller index/Blog # index 模块下生成 Blog
# 单模块不需要加模块名,根据
php think make:controller Blog
Controller created successfully.
3.从生成的多个方法,包含了显示、增删改查等多个操作方法
4.在路由 route.php 文件下创建一个资源路由,资源名称可自定义
\think\facade\Route::resource('blog','Blog');
# ('资源名','资源路径')
5.资源路由注册成功后,会自动提供以下方法(不能自己添加),无须手动注册
# GET 访问模式下:
index(blog),create(blog/create),read(blog/:id),edit(blog:id/edit)
# POST 访问模式下:
save(blog)
# PUT 访问模式下:
update(blog/:id)
# DELETE 访问模式下
delete(blog/:id)
post 一般是表单提交,put 和 delete 用 ajax 访问
# public/test/test.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>test</title>
</head>
<body>
<div>
<input type="submit" id="button" value="confirm">
</div>
</body>
<script>
$('#button').click(function (){
$.ajax({
type:'DELETE',
url:'http://localhost:8000/blog/10',
success:function(res){
console.log(res);
}
})
})
</script>
</html>
6.默认的参数采用 id 名称,如果需要更换使用 var() 方法
\think\facade\Route::resource('blog','Blog')->vars(['blog'=>'blog_id']);
7.only() 方法限定访问方法
\think\facade\Route::resource('blog','Blog')->only(['index','read','edit']);
8.except() 方法排除系统提供的资源方法
\think\facade\Route::resource('blog','Blog')->except(['update']);
9.使用 reset() 方法,更改系统给予的默认方法,1.请求地址;2.地址;3.操作
\think\facade\Route::rest([
'save'=>['POST','','store']
]);
\think\facade\Route::resource('blog','Blog')->except(['update']);
10.使用嵌套资源路由,让上级资源对下级资源进行操作
# comment.php
<?php
namespace app\controller;
use think\Controller;
class Comment extends Controller
{
public function read($id, $blog_id)
{
return 'read comment id is :'.$id.' and blog id is:'.$blog_id;
}
}
# route/route.php
\think\facade\Route::resource('blog','Blog')->except(['update']);
\think\facade\Route::resource('blog.comment','Comment');
使用嵌套路由
域名路由
如果使用需要域名路由,首先在本地 hosts 文件来映射
127.0.0.1 ocean.com
# route/route.php
# 闭包方法
\think\facade\Route::domain('ocean.com',function (){
\think\facade\Route::get('edit/:id','test/Collect/read');
});
# 普通方法
\think\facade\Route::domain('ocean.com',
['edit/:id' => 'test/Collect/read',]
);
绑定多个三级域名
\think\facade\Route::domain(['open','live'],
['edit/:id' => 'test/Collect/read',]
);
使用通配符
URL 生成
之前所有的 URL,都是手动键入的,路由提供了一套生成方式
Url:build('地址表达式'.['参数'],['URL 后缀'],['域名'])
url('地址表达式',['参数'],['URL 后缀'],['域名'])
可以使用助手函数
iv>
[外链图片转存中…(img-T5c7ZZit-1615809818891)]
[外链图片转存中…(img-kbr45H5G-1615809818892)]
6.默认的参数采用 id 名称,如果需要更换使用 var() 方法
\think\facade\Route::resource('blog','Blog')->vars(['blog'=>'blog_id']);
7.only() 方法限定访问方法
\think\facade\Route::resource('blog','Blog')->only(['index','read','edit']);
[外链图片转存中…(img-1mbLYl9x-1615809818893)]
[外链图片转存中…(img-AkXLsto2-1615809818894)]
8.except() 方法排除系统提供的资源方法
\think\facade\Route::resource('blog','Blog')->except(['update']);
9.使用 reset() 方法,更改系统给予的默认方法,1.请求地址;2.地址;3.操作
\think\facade\Route::rest([
'save'=>['POST','','store']
]);
\think\facade\Route::resource('blog','Blog')->except(['update']);
10.使用嵌套资源路由,让上级资源对下级资源进行操作
[外链图片转存中…(img-Me0yw3Zm-1615809818895)]
# comment.php
<?php
namespace app\controller;
use think\Controller;
class Comment extends Controller
{
public function read($id, $blog_id)
{
return 'read comment id is :'.$id.' and blog id is:'.$blog_id;
}
}
# route/route.php
\think\facade\Route::resource('blog','Blog')->except(['update']);
\think\facade\Route::resource('blog.comment','Comment');
使用嵌套路由
[外链图片转存中…(img-kNJymzC4-1615809818895)]
[外链图片转存中…(img-zXpKEmR4-1615809818896)]
域名路由
如果使用需要域名路由,首先在本地 hosts 文件来映射
127.0.0.1 ocean.com
# route/route.php
# 闭包方法
\think\facade\Route::domain('ocean.com',function (){
\think\facade\Route::get('edit/:id','test/Collect/read');
});
# 普通方法
\think\facade\Route::domain('ocean.com',
['edit/:id' => 'test/Collect/read',]
);
[外链图片转存中…(img-xKbgSjGQ-1615809818897)]
绑定多个三级域名
\think\facade\Route::domain(['open','live'],
['edit/:id' => 'test/Collect/read',]
);
使用通配符
[外链图片转存中…(img-ZnqSe804-1615809818898)]
URL 生成
之前所有的 URL,都是手动键入的,路由提供了一套生成方式
Url:build('地址表达式'.['参数'],['URL 后缀'],['域名'])
url('地址表达式',['参数'],['URL 后缀'],['域名'])
可以使用助手函数
方法很多…