远古框架 ThinkPHP3.2

因为工作需要,要重新捡起远古框架ThinKPHP3.2

https://www.kancloud.cn/manual/thinkphp/1679

基础

安装ThinkPHP3.2

1
composer create-project topthink/thinkphp ThinkPHP32

环境要求

  • PHP5.3+

目录结构

1
2
3
4
5
6
www  WEB部署目录(或者子目录)
├─index.php 入口文件
├─README.md README文件
├─Application 应用目录
├─Public 资源文件目录
└─ThinkPHP 框架目录
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
├─ThinkPHP 框架系统目录(可以部署在非web目录下面)
│ ├─Common 核心公共函数目录
│ ├─Conf 核心配置目录
│ ├─Lang 核心语言包目录
│ ├─Library 框架类库目录
│ │ ├─Think 核心Think类库包目录
│ │ ├─Behavior 行为类库目录
│ │ ├─Org Org类库包目录
│ │ ├─Vendor 第三方类库目录
│ │ ├─ ... 更多类库目录
│ ├─Mode 框架应用模式目录
│ ├─Tpl 系统模板目录
│ ├─LICENSE.txt 框架授权协议文件
│ ├─logo.png 框架LOGO文件
│ ├─README.txt 框架README文件
│ └─ThinkPHP.php 框架入口文件

控制器

我们可以在自动生成的Application/Home/Controller目录下面找到一个 IndexController.class.php 文件,这就是默认的Index控制器文件。

  • 控制器类的命名方式是:控制器名(驼峰法,首字母大写)+Controller
  • 控制器文件的命名方式是:类名+class.php(类文件后缀)

开发规范

使用ThinkPHP开发的过程中应该尽量遵循下列命名规范:

  • 类文件都是以.class.php为后缀(这里是指的ThinkPHP内部使用的类库文件,不代表外部加载的类库文件),使用驼峰法命名,并且首字母大写,例如 DbMysql.class.php
  • 类的命名空间地址和所在的路径地址一致,例如 Home\Controller\UserController类所在的路径应该是 Application/Home/Controller/UserController.class.php
  • 函数、配置文件等其他类库文件之外的一般是以.php为后缀(第三方引入的不做要求);
  • 函数的命名使用小写字母和下划线的方式,例如 get_client_ip
  • 方法的命名使用驼峰法,并且首字母小写或者使用下划线“_”,例如 getUserName_parseType,通常下划线开头的方法属于私有方法;
  • 属性的命名使用驼峰法,并且首字母小写或者使用下划线“_”,例如 tableName_instance,通常下划线开头的属性属于私有属性;
  • 以双下划线“__”打头的函数或方法作为魔法方法,例如 __call__autoload
  • 常量以大写字母和下划线命名,例如 HAS_ONEMANY_TO_MANY
  • 配置参数以大写字母和下划线命名,例如 HTML_CACHE_ON
  • 语言变量以大写字母和下划线命名,例如MY_LANG,以下划线打头的语言变量通常用于系统语言变量,例如 _CLASS_NOT_EXIST_

配置

在ThinkPHP中,一般来说应用的配置文件是自动加载的,加载的顺序是:

惯例配置->应用配置->模式配置->调试配置->状态配置->模块配置->扩展配置->动态配置

  • 惯例配置

惯例重于配置是系统遵循的一个重要思想,框架内置有一个惯例配置文件(位于ThinkPHP/Conf/convention.php),按照大多数的使用对常用参数进行了默认配置

  • 应用配置

应用配置文件也就是调用所有模块之前都会首先加载的公共配置文件(默认位于Application/Common/Conf/config.php)。

  • 模式配置(可选)

如果使用了普通应用模式之外的应用模式的话,还可以为应用模式(后面会有描述)单独定义配置文件,文件命名规范是: Application/Common/Conf/config_应用模式名称.php(仅在运行该模式下面才会加载)。

  • 调试配置(可选)

如果开启调试模式的话,则会自动加载框架的调试配置文件(位于ThinkPHP/Conf/debug.php)和应用调试配置文件(位于Application/Common/Conf/debug.php

  • 状态配置(可选)
1
2
3
4
5
6
7
8
// 在公司环境中
define('APP_STATUS','office');
// 那么就会自动加载该状态对应的配置文件(位于Application/Common/Conf/office.php)。


// 回家后
define('APP_STATUS','home');
// 那么就会自动加载该状态对应的配置文件(位于Application/Common/Conf/home.php)。

读取配置

无论何种配置文件,定义了配置文件之后,都统一使用系统提供的C方法(可以借助Config单词来帮助记忆)来读取已有的配置。

  • C(‘参数名称’)

例如,读取当前的URL模式配置参数:

1
2
3
$model = C('URL_MODEL');
// 由于配置参数不区分大小写,因此下面的写法是等效的
// $model = C('url_model');

动态配置

  • C(‘参数名称’,’新的参数值’)
1
2
// 动态改变缓存有效期
C('DATA_CACHE_TIME',60);

也可以支持二维数组的读取和设置,使用点语法进行操作,如下:

1
2
3
4
// 获取已经设置的参数值
C('USER_CONFIG.USER_TYPE');
// 设置新的值
C('USER_CONFIG.USER_TYPE',1);

架构

多层MVC

ThinkPHP基于MVC(Model-View-Controller,模型-视图-控制器)模式,并且均支持多层(multi-Layer)设计。

模型(Model)层

例如在某个项目设计中需要区分数据层、逻辑层、服务层等不同的模型层,我们可以在模块目录下面创建Model、Logic和Service目录,把对用户表的所有模型操作分成三层:

  1. 数据层:Model/UserModel 用于定义数据相关的自动验证和自动完成和数据存取接口
  2. 逻辑层:Logic/UserLogic 用于定义用户相关的业务逻辑
  3. 服务层:Service/UserService 用于定义用户相关的服务接口等

视图(View)层

视图层由模板和模板引擎组成,在模板中可以直接使用PHP代码,模板引擎的设计会在后面讲述,通过驱动也可以支持其他第三方的模板引擎

控制器(Controller)层

ThinkPHP的控制器层由核心控制器业务控制器组成,核心控制器由系统内部的App类完成,负责应用(包括模块、控制器和操作)的调度控制,包括HTTP请求拦截和转发、加载配置等

CBD模式

ThinkPHP引入了全新的CBD(核心Core+行为Behavior+驱动Driver)架构模式。

Core(核心)

ThinkPHP的核心部分包括核心函数库、惯例配置、核心类库(包括基础类和内置驱动及核心行为),这些是ThinkPHP必不可少的部分。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
ThinkPHP/Common/functions.php // 核心函数库
ThinkPHP/Conf/convention.php // 惯例配置文件
ThinkPHP/Conf/debug.php // 惯例调试配置文件
ThinkPHP/Mode/common.php // 普通模式定义文件
ThinkPHP/Library/Think // 核心类库包
ThinkPHP/Library/Behavior // 系统行为类库
ThinkPHP/Library/Think/App.class.php // 核心应用类
ThinkPHP/Library/Think/Cache.class.php // 核心缓存类
ThinkPHP/Library/Think/Controller.class.php // 基础控制器类
ThinkPHP/Library/Think/Db.class.php // 数据库操作类
ThinkPHP/Library/Think/Dispatcher.class.php // URL解析调度类
ThinkPHP/Library/Think/Exception.class.php // 系统基础异常类
ThinkPHP/Library/Think/Hook.class.php // 系统钩子类
ThinkPHP/Library/Think/Log.class.php // 系统日志记录类
ThinkPHP/Library/Think/Model.class.php // 系统基础模型类
ThinkPHP/Library/Think/Route.class.php // 系统路由类
ThinkPHP/Library/Think/Storage.class.php // 系统存储类
ThinkPHP/Library/Think/Template.class.php // 内置模板引擎类
ThinkPHP/Library/Think/Think.class.php // 系统引导类
ThinkPHP/Library/Think/View.class.php // 系统视图类

Behavior (行为)

Behavior目录下面是系统内置的一些行为类库,内置驱动则分布在各个不同的驱动目录下面(参考下面的驱动部分)。

行为(Behavior)是ThinkPHP扩展机制中比较关键的一项扩展,行为既可以独立调用,也可以绑定到某个标签(位)中进行侦听。

行为类的定义方式如下:

1
2
3
4
5
6
7
8
9
10
11
12
namespace Home\Behavior;

class TestBehavior
{
// 行为扩展的执行入口必须是run
public function run(&$params)
{
if(C('TEST_PARAM')) {
echo 'RUNTEST BEHAVIOR '.$params;
}
}
}

Driver(驱动)

1
2
3
4
5
6
7
ThinkPHP/Library/Think/Cache/Driver // 缓存驱动类库
ThinkPHP/Library/Think/Db/Driver // 数据库驱动类库
ThinkPHP/Library/Think/Log/Driver // 日志记录驱动类库
ThinkPHP/Library/Think/Session/Driver // Session驱动类库
ThinkPHP/Library/Think/Storage/Driver // 存储驱动类库
ThinkPHP/Library/Think/Template/Driver // 第三方模板引擎驱动类库
ThinkPHP/Library/Think/Template/TagLib // 内置模板引擎标签库扩展类库

自动加载

自动加载的优先级

在实际的应用类库加载过程中,往往会涉及到自动加载的优先级问题,以Test\MyClass类为例,自动加载的优先顺序如下:

  1. 判断是否有注册了Test\MyClass类库映射,如果有则自动加载类库映射定义的文件;
  2. 判断是否存在Library/Test目录,有则以该目录为初始目录加载;
  3. 判断是否有注册Test根命名空间,有则以注册的目录为初始目录加载;
  4. 如果以上都不成立,则以Test为模块目录进行初始目录加载;

手动加载第三方类库

如果要加载第三方类库,包括不符合命名规范和后缀的类库,以及没有使用命名空间或者命名空间和路径不一致的类库,或者你就是想手动加载类库文件,我们都可以通过手动导入的方式加载。

我们可以使用import方法导入任何类库,用法如下:

1
2
3
4
5
6
7
8
// 导入Org类库包 Library/Org/Util/Date.class.php类库
import("Org.Util.Date");
// 导入Home模块下面的 Application/Home/Util/UserUtil.class.php类库
import("Home.Util.UserUtil");
// 导入当前模块下面的类库
import("@.Util.Array");
// 导入Vendor类库包 Library/Vendor/Zend/Server.class.php
import('Vendor.Zend.Server');

系统流程

ThinkPHP框架开发的应用的标准执行流程如下:

  1. 用户URL请求
  2. 调用应用入口文件(通常是网站的index.php
  3. 载入框架入口文件(ThinkPHP.php
  4. 记录初始运行时间和内存开销
  5. 系统常量判断及定义
  6. 载入框架引导类(Think\Think)并执行Think::start方法进行应用初始化
  7. 设置错误处理机制和自动加载机制
  8. 调用Think\Storage类进行存储初始化(由STORAGE_TYPE常量定义存储类型)
  9. 部署模式下如果存在应用编译缓存文件则直接加载(直接跳转到步骤22)
  10. 读取应用模式(由APP_MODE常量定义)的定义文件(以下以普通模式为例说明)
  11. 加载当前应用模式定义的核心文件(普通模式是 ThinkPHP/Mode/common.php
  12. 加载惯例配置文件(普通模式是 ThinkPHP/Conf/convention.php
  13. 加载应用配置文件(普通模式是 Application/Common/Conf/config.php
  14. 加载系统别名定义
  15. 判断并读取应用别名定义文件(普通模式是 Application/Common/Conf/alias.php
  16. 加载系统行为定义
  17. 判断并读取应用行为定义文件(普通模式是 Application/Common/Conf/tags.php
  18. 加载框架底层语言包(普通模式是 ThinkPHP/Lang/zh-cn.php
  19. 如果是部署模式则生成应用编译缓存文件
  20. 加载调试模式系统配置文件(ThinkPHP/Conf/debug.php
  21. 判断并读取应用的调试配置文件(默认是 Application/Common/Conf/debug.php
  22. 判断应用状态并读取状态配置文件(如果APP_STATUS常量定义不为空的话)
  23. 检测应用目录结构并自动生成(如果CHECK_APP_DIR配置开启并且RUNTIME_PATH目录不存在的情况下)
  24. 调用Think\App类的run方法启动应用
  25. 应用初始化(app_init)标签位侦听并执行绑定行为
  26. 判断并加载动态配置和函数文件
  27. 调用Think\Dispatcher::dispatch方法进行URL请求调度
  28. 自动识别兼容URL模式和命令行模式下面的$_SERVER['PATH_INFO']参数
  29. 检测域名部署以及完成模块和控制器的绑定操作(APP_SUB_DOMAIN_DEPLOY参数开启)
  30. 分析URL地址中的PATH_INFO信息
  31. 获取请求的模块信息
  32. 检测模块是否存在和允许访问
  33. 判断并加载模块配置文件、别名定义、行为定义及函数文件
  34. 判断并加载模块的动态配置和函数文件
  35. 模块的URL模式判断
  36. 模块的路由检测(URL_ROUTER_ON开启)
  37. PATH_INFO处理(path_info)标签位侦听并执行绑定行为
  38. URL后缀检测(URL_DENY_SUFFIX以及URL_HTML_SUFFIX处理)
  39. 获取当前控制器和操作,以及URL其他参数
  40. URL请求调度完成(url_dispatch)标签位侦听并执行绑定行为
  41. 应用开始(app_begin)标签位侦听并执行绑定行为
  42. 调用SESSION_OPTIONS配置参数进行Session初始化(如果不是命令行模式)
  43. 根据请求执行控制器方法
  44. 如果控制器不存在则检测空控制器是否存在
  45. 控制器开始(action_begin)标签位侦听并执行绑定行为
  46. 默认调用系统的ReadHtmlCache行为读取静态缓存(HTML_CACHE_ON参数开启)
  47. 判断并调用控制器的_initialize初始化方法
  48. 判断操作方法是否存在,如果不存在则检测是否定义空操作方法
  49. 判断前置操作方法是否定义,有的话执行
  50. Action参数绑定检测,自动匹配操作方法的参数
  51. 如果有模版渲染(调用控制器display方法)
  52. 视图开始(view_begin)标签位侦听并执行绑定行为
  53. 调用Think\Viewfetch方法解析并获取模版内容
  54. 自动识别当前主题以及定位模版文件
  55. 视图解析(view_parse)标签位侦听并执行绑定行为
  56. 默认调用内置ParseTemplate行为解析模版(普通模式下面)
  57. 模版引擎解析模版内容后生成模版缓存
  58. 模版过滤替换(template_filter)标签位侦听并执行绑定行为
  59. 默认调用系统的ContentReplace行为进行模版替换
  60. 输出内容过滤(view_filter)标签位侦听并执行绑定行为
  61. 默认调用系统的WriteHtmlCache行为写入静态缓存(HTML_CACHE_ON参数开启)
  62. 调用Think\View类的render方法输出渲染内容
  63. 视图结束(view_end)标签位侦听并执行绑定行为
  64. 判断后置操作方法是否定义,有的话执行
  65. 控制器结束(action_end)标签位侦听并执行绑定行为
  66. 应用结束(app_end)标签位侦听并执行绑定行为
  67. 执行系统的ShowPageTrace行为(SHOW_PAGE_TRACE参数开启并且不是AJAX请求)
  68. 日志信息存储写入

如果是部署模式下面的第二次请求的话,上面的流程中的步骤10~21是可以省略的。

路由

规则路由

规则表达式

1
2
3
4
'my'         => 'Member/myinfo', // 静态地址路由
'blog/:id' => 'Blog/read', // 静态地址和动态地址结合
'new/:year/:month/:day'=>'News/read', // 静态地址和动态地址结合
':user/:blog_id' =>'Blog/read',// 全动态地址

实例说明

假设我们定义了News控制器如下(代码实现仅供参考):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
<?php

namespace Home\Controller;

use Think\Controller;

class NewsController extends Controller
{

public function read()
{
$New = M('New');
if(isset($_GET['id'])) {
// 根据id查询结果
$data = $New->find($_GET['id']);
} elseif (isset($_GET['name'])){
// 根据name查询结果
$data = $New->getByName($_GET['name']);
}
$this->data = $data;
$this->display();
}

public function archive(){
$New = M('New');
$year = $_GET['year'];
$month = $_GET['month'];
$begin_time = strtotime($year . $month . "01");
$end_time = strtotime("+1 month", $begin_time);
$map['create_time'] = array(array('gt',$begin_time),array('lt',$end_time));
$map['status'] = 1;
$list = $New->where($map)->select();
$this->list = $list;
$this->display();
}
}

定义路由规则如下:

1
2
3
4
5
6
'URL_ROUTER_ON'   => true, //开启路由
'URL_ROUTE_RULES' => array( //定义路由规则
'new/:id\d' => 'News/read',
'new/:name' => 'News/read',
'new/:year\d/:month\d' => 'News/archive',
),

控制器

前置和后置操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<?php

namespace Home\Controller;

use Think\Controller;

class IndexController extends Controller
{
//前置操作方法
public function _before_index()
{
echo 'before<br/>';
}

public function index()
{
echo 'index<br/>';
}

//后置操作方法
public function _after_index()
{
echo 'after<br/>';
}
}

伪静态

URL伪静态通常是为了满足更好的SEO效果,ThinkPHP支持伪静态URL设置,可以通过设置URL_HTML_SUFFIX参数随意在URL的最后增加你想要的静态后缀,而不会影响当前操作的正常执行。例如,我们设置:

1
'URL_HTML_SUFFIX'=>'shtml'

默认情况下,伪静态的设置为html,如果我们设置伪静态后缀为空,

1
'URL_HTML_SUFFIX'=>''

则可以支持所有的静态后缀,并且会记录当前的伪静态后缀到常量 __EXT__ ,但不会影响正常的页面访问。

如果希望支持多个伪静态后缀,可以直接设置如下:

1
2
// 多个伪静态后缀设置 用|分割
'URL_HTML_SUFFIX' => 'html|shtml|xml'

可以设置禁止访问的URL后缀,例如:

1
'URL_DENY_SUFFIX' => 'pdf|ico|png|gif|jpg', // URL禁止访问的后缀设置

注意:
URL_DENY_SUFFIX的优先级比URL_HTML_SUFFIX要高。

URL生成

为了配合所使用的URL模式,我们需要能够动态的根据当前的URL设置生成对应的URL地址,为此,ThinkPHP内置提供了U方法,用于URL的动态生成,可以确保项目在移植过程中不受环境的影响。

  • U(‘地址表达式’,[‘参数’],[‘伪静态后缀’],[‘显示域名’])
1
2
3
U('User/add') // 生成User控制器的add操作的URL地址
U('Blog/read?id=1') // 生成Blog控制器的read操作 并且id为1的URL地址
U('Admin/User/select') // 生成Admin模块的User控制器的select操作的URL地址

AJAX返回

ThinkPHP可以很好的支持AJAX请求,系统的\Think\Controller类提供了ajaxReturn方法用于AJAX调用后返回数据给客户端。并且支持JSONJSONPXMLEVAL四种方式给客户端接受数据,并且支持配置其他方式的数据格式返回。

1
2
3
4
5
6
7
$data = 'ok';
$this->ajaxReturn($data);

// 支持返回数组数据:
$data['status'] = 1;
$data['content'] = 'content';
$this->ajaxReturn($data);

默认配置采用JSON格式返回数据(通过配置DEFAULT_AJAX_RETURN进行设置),我们可以指定格式返回,例如:

1
2
3
4
// 指定XML格式返回数据
$data['status'] = 1;
$data['content'] = 'content';
$this->ajaxReturn($data,'xml');

跳转和重定向

页面跳转

1
2
3
4
5
6
7
8
9
$User = M('User'); //实例化User对象
$result = $User->add($data);
if($result){
//设置成功后跳转页面的地址,默认的返回页面是$_SERVER['HTTP_REFERER']
$this->success('新增成功', '/User/index');
} else {
//错误页面的默认跳转页面是返回前一页,通常不需要设置
$this->error('新增失败');
}

跳转地址是可选的,success方法的默认跳转地址是$_SERVER["HTTP_REFERER"]error方法的默认跳转地址是javascript:history.back(-1);。

默认的等待时间success方法是1秒,error方法是3秒

重定向

1
2
//重定向到New模块的Category操作
$this->redirect('New/category', array('cate_id' => 2), 5, '页面跳转中...');

输入变量

获取变量

1
2
3
4
5
$id    =  $_GET['id']; // 获取get变量
$name = $_POST['name']; // 获取post变量
$value = $_SESSION['var']; // 获取session变量
$name = $_COOKIE['name']; // 获取cookie变量
$file = $_SERVER['PHP_SELF']; // 获取server变量

但是我们不建议直接使用传统方式获取,因为没有统一的安全处理机制,后期如果调整的话,改起来会比较麻烦。所以,更好的方式是在框架中统一使用I函数进行变量获取和过滤。

  • I(‘变量类型.变量名/修饰符’,[‘默认值’],[‘过滤方法或正则’],[‘额外数据源’])

变量修饰符

  • I(‘变量类型.变量名/修饰符’)
1
2
3
I('get.id/d'); // 强制变量转换为整型
I('post.name/s'); // 强制转换变量为字符串类型
I('post.ids/a'); // 强制变量转换为数组类型

请求类型

  • IS_GET:判断是否是GET方式提交
  • IS_POST:判断是否是POST方式提交
  • IS_PUT:判断是否是PUT方式提交
  • IS_DELETE:判断是否是DELETE方式提交
  • IS_AJAX:判断是否是AJAX提交
  • REQUEST_METHOD:当前提交类型
1
2
3
4
5
6
7
8
9
10
11
12
13
14
    class UserController extends Controller
{
public function update()
{
if (IS_POST) {
$User = M('User');
$User->create();
$User->save();
$this->success('保存完成');
} else {
$this->error('非法请求');
}
}
}

空操作

空操作是指系统在找不到请求的操作方法的时候,会定位到空操作(_empty)方法来执行,利用这个机制,我们可以实现错误页面和一些URL的优化。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<?php

namespace Home\Controller;

use Think\Controller;

class CityController extends Controller
{
public function _empty($name)
{
//把所有城市的操作解析到city方法
$this->city($name);
}

//注意 city方法 本身是 protected 方法
protected function city($name)
{
//和$name这个城市相关的处理
echo '当前城市' . $name;
}
}

模型

模型定义

1
2
3
4
5
6
7
8
9
10
11
12
13
<?php

namespace Home\Model;

use Think\Model;

class CategoryModel extends Model
{
protected $tableName = 'categories';
protected $tablePrefix = 'top_';
protected $trueTableName = 'top_categories';
protected $dbName = 'top';
}

模型实例化

D方法实例化

1
2
3
4
5
6
<?php
//实例化模型
$User = D('User');
// 相当于 $User = new \Home\Model\UserModel();
// 执行具体的数据操作
$User->select();

切换数据库

如果我们已经在项目配置中定义了其他的数据库连接信息,例如:

1
2
3
4
5
6
7
8
9
10
11
//数据库配置1
'DB_CONFIG1' = array(
'db_type' => 'mysql',
'db_user' => 'root',
'db_pwd' => '1234',
'db_host' => 'localhost',
'db_port' => '3306',
'db_name' => 'thinkphp'
),
//数据库配置2
'DB_CONFIG2' => 'mysql://root:1234@localhost:3306/thinkphp';

我们就可以直接在db方法中调用配置进行连接了:

1
2
$this->db(1,"DB_CONFIG1")->query("查询SQL");
$this->db(2,"DB_CONFIG2")->query("查询SQL");

如果切换数据库之后,数据表和当前不一致的话,可以使用table方法指定要操作的数据表:

1
$this->db(1)->table("top_user")->find();

连贯操作

lock

Lock方法是用于数据库的锁机制,如果在查询或者执行操作的时候使用:

1
lock(true);

fetchSql

fetchSql用于直接返回SQL而不是执行查询,适用于任何的CURD操作方法。 例如:

1
$result = M('User')->fetchSql(true)->find(1);

token

token方法可用于临时关闭令牌验证,例如:

1
$model->token(false)->create();

strict

strict为3.2.3新增连贯操作,用于设置数据写入和查询是否严格检查是否存在字段。默认情况下不合法数据字段自动删除,如果设置了严格检查则会抛出异常。 例如:

1
$model->strict(true)->add($data);

index

index方法用于数据集的强制索引操作,例如:

1
$Model->index('user')->select();

查询语言

SQL查询

QUERY方法

1
2
$Model = new \Think\Model() // 实例化一个model对象 没有对应任何数据表
$Model->query("select * from think_user where status=1");

EXECUTE方法

1
2
$Model = new \Think\Model() // 实例化一个model对象 没有对应任何数据表
$Model->execute("update think_user set name='thinkPHP' where status=1");

动态查询

getBy动态查询

1
2
3
$user = $User->getByName('liu21st');
$user = $User->getByEmail('liu21st@gmail.com');
$user = $User->getByAddress('中国深圳');

getFieldBy动态查询

1
$userId = $User->getFieldByName('liu21st','id');

子查询

1、使用select方法 当select方法的参数为false的时候,表示不进行查询只是返回构建SQL,例如:

1
2
// 首先构造子查询SQL 
$subQuery = $model->field('id,name')->table('tablename')->group('field')->where($where)->order('status')->select(false);

当select方法传入false参数的时候,表示不执行当前查询,而只是生成查询SQL。

2、使用buildSql方法

1
$subQuery = $model->field('id,name')->table('tablename')->group('field')->where($where)->order('status')->buildSql(); 

调用buildSql方法后不会进行实际的查询操作,而只是生成该次查询的SQL语句(为了避免混淆,会在SQL两边加上括号),然后我们直接在后续的查询中直接调用。

1
2
// 利用子查询进行查询 
$model->table($subQuery.' a')->where()->order()->select()

自动验证

动态验证

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$rules = array(
array('verify','require','验证码必须!'), //默认情况下用正则进行验证
array('name','','帐号名称已经存在!',0,'unique',1), // 在新增的时候验证name字段是否唯一
array('value',array(1,2,3),'值的范围不正确!',2,'in'), // 当值不为空的时候判断是否在一个范围内
array('repassword','password','确认密码不正确',0,'confirm'), // 验证确认密码是否和密码一致
array('password','checkPwd','密码格式不正确',0,'function'), // 自定义函数验证密码格式
);

$User = M("User"); // 实例化User对象
if (!$User->validate($rules)->create()){
// 如果创建失败 表示验证没有通过 输出错误提示信息
exit($User->getError());
} else {
// 验证通过 可以进行其他数据操作
}

参数绑定

手动绑定

1
2
3
$Model = M('User');
$where['name'] = ':name';
$list = $Model->where($where)->bind(':name',I('name'))->select();

目前不支持 ? 方式进行占位符,统一使用 :var 方式进行占位符,驱动内部会自动进行处理。

自动绑定

1
2
3
4
$Model = M('User');
$Model->name = 'thinkphp';
$Model->email = 'thinkphp@qq.com';
$Model->add();

关联模型

关联关系

1
2
3
一对一关联 :ONE_TO_ONE,包括HAS_ONE 和 BELONGS_TO 
一对多关联 :ONE_TO_MANY,包括HAS_MANY 和 BELONGS_TO
多对多关联 :MANY_TO_MANY

HAS_ONE

HAS_ONE关联表示当前模型拥有一个子对象,例如,每个员工都有一个人事档案。我们可以建立一个用户模型UserModel,并且添加如下关联定义:

1
2
3
4
5
6
7
namespace Home\Model;
use Think\Model\RelationModel;
class UserModel extends RelationModel{
protected $_link = array(
'Profile'=> self::HAS_ONE,
);
}

BELONGS_TO

Belongs_to关联表示当前模型从属于另外一个父对象,例如每个用户都属于一个部门。我们可以做如下关联定义。

1
'Dept' => self::BELONGS_TO

HAS_MANY

HAS_MANY 关联表示当前模型拥有多个子对象,例如每个用户有多篇文章,我们可以这样来定义:

1
'Article' => self::HAS_MANY

MANY_TO_MANY

MANY_TO_MANY 关联表示当前模型可以属于多个对象,而父对象则可能包含有多个子对象,通常两者之间需要一个中间表类约束和关联。例如每个用户可以属于多个组,每个组可以有多个用户:

1
'Group' => self::MANY_TO_MANY

关联删除

1
2
3
4
//删除用户ID为3的记录的同时删除关联数据
$result = $User->relation(true)->delete("3");
// 如果只需要关联删除部分数据,可以使用
$result = $User->relation("Profile")->delete("3");

高级模型

字段过滤

1
2
3
protected $_filter = array(
'过滤的字段'=>array('写入过滤规则','读取过滤规则',是否传入整个数据对象),
);

序列化字段

1
2
3
protected $serializeField = array(
'info' => array('name', 'email', 'address'),
);

文本字段

1
Protected  $blobFields = array('content');

只读字段

1
protected $readonlyField = array('name', 'email');

悲观锁( Pessimistic Locking )

悲观锁,正如其名,它指的是对数据被外界(包括本系统当前的其他事务,以及来自外部系统的事务处理)修改持保守态度,因此,在整个数据处理过程中,将数据处于锁定状态。悲观锁的实现,往往依靠数据库提供的锁机制(也只有数据库层提供的锁机制才能真正保证数据访问的排他性,否则,即使在本系统中实现了加锁机制,也无法保证外部系统不会修改数据)。 通常是使用for update子句来实现悲观锁机制。

ThinkPHP支持悲观锁机制,默认情况下,是关闭悲观锁功能的,要在查询和更新的时候启用悲观锁功能,可以通过使用之前提到的查询锁定方法,例如:

1
$User->lock(true)->save($data);// 使用悲观锁功能

乐观锁( Optimistic Locking )

相对悲观锁而言,乐观锁机制采取了更加宽松的加锁机制。悲观锁大多数情况下依靠数据库的锁机制实现,以保证操作最大程度的独占性。但随之而来的就是数据库性能的大量开销,特别是对长事务而言,这样的开销往往无法承受。 如一个金融系统,当某个操作员读取用户的数据,并在读出的用户数据的基础上进行修改时(如更改用户帐户余额),如果采用悲观锁机制,也就意味着整个操作过程中(从操作员读出数据、开始修改直至提交修改结果的全过程,甚至还包括操作员中途去煮咖啡的时间),数据库记录始终处于加锁状态,可以想见,如果面对几百上千个并发,这样的情况将导致怎样的后果。乐观锁机制在一定程度上解决了这个问题。乐观锁,大多是基于数据版本( Version )记录机制实现。何谓数据版本?即为数据增加一个版本标识,在基于数据库表的版本解决方案中,一般是通过为数据库表增加一个 “version” 字段来实现。

ThinkPHP也可以支持乐观锁机制,要启用乐观锁,只需要继承高级模型类并定义模型的optimLock属性,并且在数据表字段里面增加相应的字段就可以自动启用乐观锁机制了。默认的optimLock属性是lock_version,也就是说如果要在User表里面启用乐观锁机制,只需要在User表里面增加lock_version字段,如果有已经存在的其它字段作为乐观锁用途,可以修改模型类的optimLock属性即可。如果存在optimLock属性对应的字段,但是需要临时关闭乐观锁机制,把optimLock属性设置为false就可以了。

数据分表

对于大数据量的应用,经常会对数据进行分表,有些情况是可以利用数据库的分区功能,但并不是所有的数据库或者版本都支持,因此我们可以利用ThinkPHP内置的数据分表功能来实现。帮助我们更方便的进行数据的分表和读取操作。

和数据库分区功能不同,内置的数据分表功能需要根据分表规则手动创建相应的数据表。
在需要分表的模型中定义partition属性即可。

1
2
3
4
5
6
protected $partition = array(
'field' => 'name',// 要分表的字段 通常数据会根据某个字段的值按照规则进行分表
'type' => 'md5',// 分表的规则 包括id year mod md5 函数 和首字母
'expr' => 'name',// 分表辅助表达式 可选 配合不同的分表规则
'num' => 'name',// 分表的数目 可选 实际分表的数量
);

定义好了分表属性后,我们就可以来进行CURD操作了,唯一不同的是,获取当前的数据表不再使用getTableName方法,而是使用getPartitionTableName方法,而且必须传入当前的数据。然后根据数据分析应该实际操作哪个数据表。因此,分表的字段值必须存在于传入的数据中,否则会进行联合查询。

Mongo模型

Mongo模型是专门为Mongo数据库驱动而支持的Model扩展,如果需要操作Mongo数据库的话,自定义的模型类必须继承Think\Model\MongoModel

Mongo模型为操作Mongo数据库提供了更方便的实用功能和查询用法,包括:

  1. MongoId对象和非对象主键的全面支持;
  2. 保持了动态追加字段的特性;
  3. 数字自增字段的支持;
  4. 执行SQL日志的支持;
  5. 字段自动检测的支持;
  6. 查询语言的支持;
  7. MongoCode执行的支持;

视图

模板赋值

1
2
3
4
$array['name']    =    'thinkphp';
$array['email'] = 'liu21st@gmail.com';
$array['phone'] = '12335678';
$this->assign($array);

模板渲染

1
2
// 不带任何参数 自动定位当前操作的模板文件
$this->display();

获取模板地址

  • T([资源://][模块@][主题/][控制器/]操作,[视图分层])
1
2
3
4
5
6
7
8
9
10
11
12
13
14
T('Public/menu');
// 返回 当前模块/View/Public/menu.html
T('blue/Public/menu');
// 返回 当前模块/View/blue/Public/menu.html
T('Public/menu','Tpl');
// 返回 当前模块/Tpl/Public/menu.html
T('Public/menu');
// 如果TMPL_FILE_DEPR 为 _ 返回 当前模块/Tpl/Public_menu.html
T('Public/menu');
// 如果TMPL_TEMPLATE_SUFFIX 为.tpl 返回 当前模块/Tpl/Public/menu.tpl
T('Admin@Public/menu');
// 返回 Admin/View/Public/menu.html
T('Extend://Admin@Public/menu');
// 返回 Extend/Admin/View/Public/menu.html (Extend目录取决于AUTOLOAD_NAMESPACE中的配置)

调试

调试模式

1
2
3
4
5
6
7
<?php
// 开启调试模式
define('APP_DEBUG', true);
// 定义应用目录
define('APP_PATH', './Application/');
// 加载框架入口文件
require './ThinkPHP/ThinkPHP.php';

异常处理

1
2
3
E('新增失败');
// 也可以支持异常代码(默认为0),例如:
E('信息录入错误',25);

异常模板中可以使用的异常变量有:

1
2
3
4
$e['file']异常文件名
$e['line'] 异常发生的文件行数
$e['message'] 异常信息
$e['trace'] 异常的详细Trace信息

日志记录

默认情况下只是在调试模式记录日志,要在部署模式开启日志记录,必须在配置中开启LOG_RECORD参数,以及可以在应用配置文件中配置需要记录的日志级别,例如:

1
2
'LOG_RECORD' => true, // 开启日志记录
'LOG_LEVEL' =>'EMERG,ALERT,CRIT,ERR', // 只记录EMERG ALERT CRIT ERR 错误

日志级别

  • EMERG 严重错误,导致系统崩溃无法使用
  • ALERT 警戒性错误, 必须被立即修改的错误
  • CRIT 临界值错误, 超过临界值的错误
  • ERR 一般性错误
  • WARN 警告性错误, 需要发出警告的错误
  • NOTICE 通知,程序可以运行但是还不够完美的错误
  • INFO 信息,程序输出信息
  • DEBUG 调试,用于调试信息
  • SQL SQL语句,该级别只在调试模式开启时有效

手动记录

  • Log::record() - 记录日志信息到内存
  • Log::save() - 把保存在内存中的日志信息(用指定的记录方式)写入
  • Log::write() - 实时写入一条日志信息
1
2
Think\Log::record('测试日志信息,这是警告级别','WARN',true);
Think\Log::write('测试日志信息,这是警告级别,并且实时写入','WARN');

页面Trace

1
2
// 显示页面Trace信息
'SHOW_PAGE_TRACE' =>true,

页面Trace的选项卡是可以定制和扩展的,默认的配置为:

1
2
3
4
5
6
7
8
'TRACE_PAGE_TABS'=>array(
'base'=>'基本',
'file'=>'文件',
'think'=>'流程',
'error'=>'错误',
'sql'=>'SQL',
'debug'=>'调试'
)

Trace方法

页面Trace只能用于有页面输出的情况,但是trace方法可以用在任何情况,而且trace方法可以用于AJAX等操作。

1
trace('变量','标签','级别','是否记录日志')

断点调试

凭借强大的页面Trace信息功能支持,ThinkPHP可以支持断点调试功能。 我们只需要在不同的位置对某个变量进行trace输出即可,例如:

1
2
3
4
5
$blog = D("Blog");
$vo = $blog->create();
trace($vo,'create vo');
$vo = $blog->find();
trace($vo,'find vo');

性能调试

开发过程中,有些时候为了测试性能,经常需要调试某段代码的运行时间或者内存占用开销,系统提供了G方法可以很方便的获取某个区间的运行时间和内存占用情况。 例如:

1
2
3
4
5
6
G('begin');
// ...其他代码段
G('end');
// ...也许这里还有其他代码
// 进行统计区间
echo G('begin','end').'s';

默认的统计精度是小数点后4位,如果觉得这个统计精度不够,还可以设置例如:

1
G('begin','end',6).'s';

如果你的环境支持内存占用统计的话,还可以使用G方法进行区间内存开销统计(单位为kb),例如:

1
echo G('begin','end','m').'kb';

错误调试

如果需要我们可以使用E方法输出错误信息并中断执行,例如:

1
2
//输出错误信息,并中止执行
E($msg);

模型调试

调试执行的SQL语句

在模型操作中 ,为了更好的查明错误,经常需要查看下最近使用的SQL语句,我们可以用getLastsql方法来输出上次执行的sql语句。

1
2
3
4
5
$User = M("User"); // 实例化User对象
$User->find(1);
echo $User->getLastSql();
// 3.2版本中可以使用简化的方法
echo $User->_sql();

调试数据库错误信息

1
2
3
4
5
$User = M("User"); // 实例化User对象
$result = $User->find(1);
if(false === $result){
echo $User->getDbError();
}

缓存

数据缓存

缓存初始化

1
2
// 缓存初始化
S(array('type'=>'xcache','expire'=>60));

缓存设置

1
2
// 设置缓存
S('name',$value);

缓存读取

1
2
// 读取缓存
$value = S('name');

缓存删除

1
2
// 删除缓存
S('name',null);

对象方式操作缓存

1
2
3
4
$cache = S(array('type'=>'xcache','prefix'=>'think','expire'=>600));
$cache->name = 'value'; // 设置缓存
$value = $cache->name; // 获取缓存
unset($cache->name); // 删除缓存

缓存队列

数据缓存可以支持缓存队列,简单的说就是可以限制缓存的数量,只需要在初始化的时候指定length参数:

1
S(array('type'=>'xcache','length'=>100,'expire'=>60));

快速缓存

如果你的存储数据没有有效期的需求,那么系统还提供了一个快速缓存方法F可以用来更快的操作。

F方法可以支持不同的存储类型,如果是文件类型的话,默认保存在DATA_PATH目录下面。

1
2
3
4
5
6
7
8
9
10
F('data',$Data);

// 快速缓存Data数据,保存到指定的目录
F('data',$Data,TEMP_PATH);

// 获取缓存数据
$Data = F('data');

// 删除缓存数据
F('data',NULL);

F方法支持自动创建缓存子目录,在DATA_PATH目录下面缓存data数据,如果User子目录不存在,则自动创建:

1
F('User/data',$Data);

查询缓存

1
2
3
4
$Model->cache(true)->where('status=1')->select();

// 指定Key
$Model->cache('cache_name')->select();

指定key的方式会让查询缓存更加高效。

静态缓存

要使用静态缓存功能,需要开启HTML_CACHE_ON参数,并且使用HTML_CACHE_RULES配置参数设置静态缓存规则文件 。

静态规则定义

1
2
3
4
5
6
7
8
9
'HTML_CACHE_ON'     =>    true, // 开启静态缓存
'HTML_CACHE_TIME' => 60, // 全局静态缓存有效期(秒)
'HTML_FILE_SUFFIX' => '.shtml', // 设置静态缓存文件后缀
'HTML_CACHE_RULES' => array( // 定义静态缓存规则
// 定义格式1 数组方式
'静态地址' => array('静态规则', '有效期', '附加规则'),
// 定义格式2 字符串方式
'静态地址' => '静态规则',
)

安全

输入过滤

使用I函数过滤

使用系统内置的I函数是避免输入数据出现安全隐患的重要手段,I函数默认的过滤方法是htmlspecialchars,如果我们需要采用其他的方法进行安全过滤,有两种方式:

  • 如果是全局的过滤方法,那么可以设置DEFAULT_FILTER,例如:
1
'DEFAULT_FILTER'        =>  'strip_tags',

当然,我们也可以设置多个过滤方法,例如:

1
'DEFAULT_FILTER'        =>  'strip_tags,stripslashes',
  • 如果是仅需要对个别数据采用特殊的过滤方法,可以在调用I函数的时候传入过滤方法,例如:
1
2
I('post.id', 0, 'intval'); // 用intval过滤$_POST['id']
I('get.title', '', 'strip_tags'); // 用strip_tags过滤$_GET['title']

写入数据过滤

1
$this->data($data)->filter('strip_tags')->add();

表单合法性检测

配置insertFieldsupdateFields属性

1
2
3
4
5
6
7
8
9
<?php

namespace Home\Model;

class UserModel extends \Think\Model
{
protected $insertFields = array('account','password','nickname','email');
protected $updateFields = array('nickname','email');
}

直接调用field方法

1
M('User')->field('account,password,nickname,email')->create();

表单令牌

要启用表单令牌功能,需要配置行为绑定,在应用或者模块的配置目录下面的行为定义文件tags.php中,添加:

1
2
3
4
5
6
return array(
// 添加下面一行定义即可
'view_filter' => array('Behavior\TokenBuild'),
// 如果是3.2.1以上版本 需要改成
// 'view_filter' => array('Behavior\TokenBuildBehavior'),
);

表示在view_filter标签位置执行表单令牌检测行为。

  • 表单令牌验证相关的配置参数有:
1
2
3
4
'TOKEN_ON'      =>    true,  // 是否开启令牌验证 默认关闭
'TOKEN_NAME' => '__hash__', // 令牌验证的表单隐藏字段名称,默认为__hash__
'TOKEN_TYPE' => 'md5', //令牌哈希验证规则 默认为MD5
'TOKEN_RESET' => true, //令牌验证出错后是否重置令牌 默认为true

如果开启表单令牌验证功能,系统会自动在带有表单的模板文件里面自动生成以TOKEN_NAME为名称的隐藏域,
其值则是TOKEN_TYPE方式生成的哈希字符串,用于实现表单的自动令牌验证。

如果个别页面输出不希望进行表单令牌验证,可以在控制器中的输出方法之前动态关闭表单令牌验证,例如:

1
2
C('TOKEN_ON',false);
$this->display();

模型类在创建数据对象的同时会自动进行表单令牌验证操作,如果你没有使用create方法创建数据对象的话,则需要手动调用模型的autoCheckToken方法进行表单令牌验证。
如果返回false,则表示表单令牌验证错误。例如:

1
2
3
4
5
$User = M("User"); // 实例化User对象
// 手动进行令牌验证
if (!$User->autoCheckToken($_POST)){
// 令牌验证错误
}

防止SQL注入

  • 要有效的防止SQL注入问题,我们建议:
  • 查询条件尽量使用数组方式,这是更为安全的方式;
  • 如果不得已必须使用字符串查询条件,使用预处理机制
  • 使用自动验证和自动完成机制进行针对应用的自定义过滤;
  • 如果环境允许,尽量使用PDO方式,并使用参数绑定。

查询条件预处理

where方法使用字符串条件的时候,支持预处理(安全过滤),并支持两种方式传入预处理参数,例如:

1
2
3
$Model->where("id=%d and username='%s' and xx='%f'",array($id,$username,$xx))->select();
// 或者
$Model->where("id=%d and username='%s' and xx='%f'",$id,$username,$xx)->select();

目录安全文件

为了避免某些服务器开启了目录浏览权限后可以直接在浏览器输入URL地址查看目录,系统默认开启了目录安全文件机制,会在自动生成目录的时候生成空白的index.html文件,
当然安全文件的名称可以设置,例如你想给安全文件定义为default.html可以在入口文件中添加:

1
2
3
define('DIR_SECURE_FILENAME', 'default.html');
define('APP_PATH','./Application/');
require './ThinkPHP/ThinkPHP.php';

还可以支持多个安全文件写入,例如你想同时写入index.htmlindex.htm两个文件,以满足不同的服务器部署环境,可以这样定义:

1
define('DIR_SECURE_FILENAME', 'index.html,index.htm');

默认的安全文件只是写入一个空白字符串,如果需要写入其他内容,可以通过DIR_SECURE_CONTENT参数来指定,例如:

1
define('DIR_SECURE_CONTENT', 'deny Access!');

注意:目录安全文件仅在第一次生成模块目录的时候生成。如果是3.2.1版本以上,则可以调用代码生成,例如:

1
2
// dirs变量是要生成安全文件的目录数组
\Think\Build::buildDirSecure($dirs);

上传安全

网站的上传功能也是一个非常容易被攻击的入口,所以对上传功能的安全检查是尤其必要的。

系统提供的上传类Think\Upload提供了安全方面的支持,包括对文件后缀、文件类型、文件大小以及上传图片文件的合法性检查,确保你已经在上传操作中启用了这些合法性检查。

防止XSS攻击

  • XSS(跨站脚本攻击) 可以用于窃取其他用户的Cookie信息,要避免此类问题,可以采用如下解决方案:
    • 直接过滤所有的JavaScript脚本;
    • 转义Html元字符,使用htmlentities、htmlspecialchars等函数;
    • 系统的扩展函数库提供了XSS安全过滤的remove_xss方法;
    • 新版对URL访问的一些系统变量已经做了XSS处理。

部署

PATH_INFO支持

如果发生在本地测试正常,但是一旦部署到服务器环境后会发生只能访问首页的情况,很有可能是你的服务器或者空间不支持PATH_INFO所致。

如果你的环境没有任何对应的系统变量,那么可以封装一个获取方法,例如:

1
2
3
4
function get_path_info(){
// 根据你的环境兼容获取PATH_INFO 具体代码略
return $path; // 直接返回获取到的PATH_INFO信息
}

然后我们修改下URL_PATHINFO_FETCH参数的配置值,改为:

1
'URL_PATHINFO_FETCH'     =>   ':get_path_info'

URL重写

[ Apache ]

  1. httpd.conf配置文件中加载了mod_rewrite.so模块
  2. AllowOverride None 将None改为 All
  3. 把下面的内容保存为.htaccess文件放到应用入口文件的同级目录下
1
2
3
4
5
6
<IfModule mod_rewrite.c>
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ index.php/$1 [QSA,PT,L]
</IfModule>

[ Nginx ]

在Nginx低版本中,是不支持PATHINFO的,但是可以通过在Nginx.conf中配置转发规则实现:

1
2
3
4
5
6
location / { // …..省略部分代码
if (!-e $request_filename) {
rewrite ^(.*)$ /index.php?s=$1 last;
break;
}
}

如果你的ThinkPHP安装在二级目录,Nginx的伪静态方法设置如下,其中youdomain是所在的目录名称。

1
2
3
4
5
location /youdomain/ {
if (!-e $request_filename){
rewrite ^/youdomain/(.*)$ /youdomain/index.php?s=$1 last;
}
}

替换入口

我们的建议是在生产环境中关闭调试模式后生成Lite文件。
注意,目前SAE平台不支持直接生成Lite文件。

生成Lite文件

要生成Lite文件,需要在入口文件中增加常量定义:

1
define('BUILD_LITE_FILE',true);

默认情况下,再次运行后会在Runtime目录下面生成一个lite.php文件。

如果你需要修改Lite文件的位置或者名称,可以在应用配置文件中增加配置如下:

1
'RUNTIME_LITE_FILE'=> APP_PATH.'lite.php'

配置后,生成的Lite文件的位置为 APP_PATH.'lite.php'

Lite文件的编译文件内容是系统默认的,如果希望改变或者增加其他的编译文件的话,可以在外部定义编译列表文件,
例如: 我们在应用配置目录下面增加lite.php定义如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
return array(
THINK_PATH.'Common/functions.php',
COMMON_PATH.'Common/function.php',
CORE_PATH . 'Think'.EXT,
CORE_PATH . 'Hook'.EXT,
CORE_PATH . 'App'.EXT,
CORE_PATH . 'Dispatcher'.EXT,
CORE_PATH . 'Model'.EXT,
CORE_PATH . 'Log'.EXT,
CORE_PATH . 'Log/Driver/File'.EXT,
CORE_PATH . 'Route'.EXT,
CORE_PATH . 'Controller'.EXT,
CORE_PATH . 'View'.EXT,
CORE_PATH . 'Storage'.EXT,
CORE_PATH . 'Storage/Driver/File'.EXT,
CORE_PATH . 'Exception'.EXT,
BEHAVIOR_PATH . 'ParseTemplateBehavior'.EXT,
BEHAVIOR_PATH . 'ContentReplaceBehavior'.EXT,
);

所有在lite.php文件中定义的文件都会纳入Lite文件的编译缓存中。你还可以对生成的lite文件进行修改。

如果你修改了框架文件和应用函数和配置文件的话,需要删除Lite文件重新生成。

替换入口

Lite文件生成后,就可以把原来的应用入口文件中的框架入口文件修改如下:

1
2
3
require './ThinkPHP/ThinkPHP.php';
// 改成
require './Runtime/lite.php';

替换应用入口文件

如果你的入口文件没有其他代码和逻辑的话,还可以直接把lite.php文件作为应用的入口文件访问。
lite.php文件复制到应用入口文件的相同目录,并直接改名为index.php即可和原来一样正常访问(原来的应用入口文件可以备份以备用于重新生成Lite文件的时候使用)。

注意:如果你的环境或者目录位置发生变化,以及更改了核心框架和应用函数、配置等文件后,则需要重新生成Lite文件。

专题

session初始化设置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// session赋值
session('name','value'); //设置session
session('user.user_id',10); //设置session

// session取值
$value = session('name');
// 获取所有的session 3.2.2版本新增
$value = session();
$value = session('user.user_id');

// session删除
session('name',null); // 删除name
session('user.user_id',null); // 删除session
session(null); // 清空当前的session

// session判断
// 判断名称为name的session值是否已经设置
session('?name');
session('?user.user_id');

// session管理
session('[操作名]');
session('[pause]'); // 暂停session写入
session('[start]'); // 启动session
session('[destroy]'); // 销毁session
session('[regenerate]'); // 重新生成session id

Cookie支持

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// Cookie设置
cookie('name','value'); //设置cookie
cookie('name','value',3600); // 指定cookie保存时间
cookie('name','value',array('expire'=>3600,'prefix'=>'think_'))
cookie('name','value','expire=3600&prefix=think_')

// Cookie获取
$value = cookie('name');
$value = $_COOKIE['name'];
$value = $_COOKIE['前缀+name'];
$value = cookie();
$value = $_COOKIE;

// Cookie删除
cookie('name',null);
cookie(null); // 清空当前设定前缀的所有cookie值
cookie(null,'think_'); // 清空指定前缀的所有cookie值

数据分页

利用Page类和limit方法分页

1
2
3
4
5
6
7
8
9
$User = M('User'); // 实例化User对象
$count = $User->where('status=1')->count();// 查询满足要求的总记录数
$Page = new \Think\Page($count,25);// 实例化分页类 传入总记录数和每页显示的记录数(25)
$show = $Page->show();// 分页显示输出
// 进行分页数据查询 注意limit方法的参数要使用Page类的属性
$list = $User->where('status=1')->order('create_time')->limit($Page->firstRow.','.$Page->listRows)->select();
$this->assign('list',$list);// 赋值数据集
$this->assign('page',$show);// 赋值分页输出
$this->display(); // 输出模板

分页类和page方法的实现分页

1
2
3
4
5
6
7
8
9
$User = M('User'); // 实例化User对象
// 进行分页数据查询 注意page方法的参数的前面部分是当前的页数使用 $_GET[p]获取
$list = $User->where('status=1')->order('create_time')->page($_GET['p'].',25')->select();
$this->assign('list',$list);// 赋值数据集
$count = $User->where('status=1')->count();// 查询满足要求的总记录数
$Page = new \Think\Page($count,25);// 实例化分页类 传入总记录数和每页显示的记录数
$show = $Page->show();// 分页显示输出
$this->assign('page',$show);// 赋值分页输出
$this->display(); // 输出模板

常见问题

  • [Composer\Downloader\TransportException]

Your configuration does not allow connections to http://packagi
st.phpcomposer.com/packages.json. See https://getcomposer.org/d
oc/06-config.md#secure-http for details.

解决:composer国内镜像不能使用

Powered by Hexo and Hexo-theme-hiker

Copyright © 2017 - 2023 Keep It Simple And Stupid All Rights Reserved.

访客数 : | 访问量 :