跳转至

ThinkPHP

约 2181 个字 249 行代码 预计阅读时间 10 分钟

简介

  • 国产、基于Apache 2.0协议开源,对商业用途友好
  • 基于PHP 5.3及以上版本(一系列新特性,如命名空间)
  • 核心可定制(应用模式和CBD架构)
  • 编译机制(压缩合并、模板编译,和Java的编译不是一个概念)

解压后在浏览器中访问页面(目录),然后更改./Application/Home/Controller/IndexController.class.phpIndexController -> index()中的内容,即可更改欢迎页面。

结构

./
├─Application/         应用目录(模块集合)
│  ├─*/                (除了 Runtime 外的其他目录)模块
│  │  ├─Common/        模块函数库
│  │  ├─Conf/          模块配置
│  │  ├─Controller/    控制器
│  │  ├─Model/         模型
│  │  ├─View/          视图
│  │  └─Conf/          惯例配置
│  ├─Common/           通用模块(不可以直接访问,优先于其他模块执行,内部结构见上)
│  ├─Home/             系统自动生成的模块(内部结构见上)
│  └─Runtime           缓存目录
├─Public/              公共资源目录(存放所有的静态资源,如样式表脚本、图片、字体)
├─ThinkPHP/            核心框架目录
│  ├─Common/           通用函数库
│  ├─Conf/             惯例配置
│  ├─Lang/             语言包
│  ├─Library/          类库
│  ├─Mode/             应用模式
│  ├─Tpl/              框架自带模板
│  └─ThinkPHP.php      框架入口文件(公共入口文件)
└─index.php            应用入口(应用对外提供的接口,所有请求都从这个开始(所以 ThinkPHP 可以是单入口的)引入了公共入口文件)

新增模块方式

  • ./Application/ 下新建目录
  • 在入口文件(./index.php)中定义:
    define('BIND_MODULE', 'mod');
    
    再打开框架的页面,系统会自动在 ./Application/ 下生成名为 mod 的模块。更改 ./Application/mod/Controller/IndexController.class.phpIndexController -> index() 中的内容,即可更改对应的页面。在入口文件中绑定模块后,默认访问的就是这个模块。

打印变量

dump($var)

MVC分层架构

  • 控制器(Controller):负责用户请求的调度、处理业务逻辑
  • 模型(Model):负责业务数据的处理、与数据库的交互
  • 视图(View):提供了展示数据的各种方式

优点:将业务逻辑、视图展示和数据处理分离开,降低设计、管理的难度,代码也更具结构性,更容易维护、重用。(合理分工带来的效率提升)

整个请求响应的过程类比

1
2
3
4
5
6
7
      用户
    C(服务员)
     ↕      ↕
M(厨师)↔ V(摆盘)
DB(仓库)
  • C 记录客人点了什么菜、要求;根据不同种类的菜,交给不同的 M;
  • M 根据订单到DB取原材料(与数据库交互);经过烹饪完成订单上的菜品,交给 V;
  • V根据相应菜品的摆盘方案,进行摆盘装饰(视图的渲染输出);
  • 由 C 给客人上菜。

配置

ThinkPHP框架配置文件自动加载顺序

  1. 惯例配置(./ThinkPHP/Conf/convention.php
  2. 应用配置(./Application/Common/Conf/config.php
  3. 模式配置
  4. 调试配置(./ThinkPHP/Conf/debug.php
  5. 状态配置
  6. 模块配置(./Application/*/Conf/config.php

采用合并覆盖机制,因此优先级从后到前。

支持配置格式

  • PHP
  • YAML
  • ini
  • XML
  • JSON

通过在入口文件./index.php)定义 CONF_EXT 常量指定格式。配置的格式不影响框架的惯例配置只对模块配置产生影响。

# ./Application/Home/Conf/config.yaml
YAML : yaml
1
2
3
4
// ./index.php
//...
define('CONF_EXT', '.yaml');
//...
1
2
3
4
5
6
// ./Application/Home/Controller/IndexController.class.php
// ...
    public function index(){
        $config = C('');
        dump($config);
// ...
// 输出中可以找到
['YAML'] => string(4) 'yaml'

配置读取

通过 C 函数读取配置:

读取全部配置项:

C('')

读取配置项名称为 name 的配置项:

C('name')

读取配置项名称为 name 的配置项,如未配置则返回 default

C('name', null, 'default')

读取二维数组配置,父子项之间以点号连接:

C('parent.sub')

配置名称大小写

配置名称不区分大小写,但在二维数组配置读取的参数中,parent严格区分大小写

动态配置

通过 C 函数进行动态配置,以在程序逻辑中临时改变配置。

设置配置项名称为 name 的配置项:

C('name', $val)

批量配置:

C($conf_array)

$conf_array 中键为配置项名称,值为配置值。

扩展配置

通过设置 LOAD_EXT_CONFIG 配置项的值来加载当前模块的自定义配置文件,如:

1
2
3
4
// ./Application/Home/Conf/user.php
return array(
  'USER_NAME' => 'haha'
);
1
2
3
4
// ./Application/Home/Conf/upload.php
return array(
  'UPLOAD_NAME' => 'gaga'
);
1
2
3
4
// ./Application/Home/Conf/config.php
return array(
  'LOAD_EXT_CONFIG' => 'user,upload'
);
1
2
3
4
5
6
// ./Application/Home/Controller/IndexController.class.php
// ...
    public function index(){
        $config = C('');
        dump($config);
// ...
1
2
3
// 输出中可以找到
['USER_NAME'] => string(4) 'haha'
['UPLOAD_NAME'] => string(4) 'gaga'

控制器

简介

  • 控制器是一个 PHP 类,需要继承 ThinkPHP 的核心类 Controller;类名以大写开头的驼峰命名法命名。
  • public 修饰的方法是操作方法,可从外部访问;以 protectedprivate 修饰的不能从外部访问;操作方法采用驼峰命名法命名。

前置、后置操作

在执行某个操作方法之前 / 之后会自动调用的方法。

// ./Application/Home/Controller/IndexController.class.php
//...
class IndexController extends Controller { // 控制器
    public function _before_index(){ //前置操作
        echo "index.before<br>";
    }
    public function index(){ //操作方法
       echo "index<br>";
    }
    public function _after_index(){ //前置操作
        echo "index.after<br>";
    }
}
1
2
3
4
// 浏览器访问./
index.before
index
index.after

改变操作方法的书写方式

通过配置 ACTION_SUFFIX 的值改变操作方法的书写形式。不影响网址的展现形式,只会对操作方法的定义产生影响。

// ./Application/Home/Controller/IndexController.class.php
//...
class IndexController extends Controller { // 控制器
    public function index(){ //操作方法
        echo "index<br>";
    }
    public function list(){ //保留字,打开./时会报错
        echo "list";
    }
}
1
2
3
4
5
6
//配置`ACTION_SUFFIX`的值改变操作方法的书写形式
// ./Application/Home/Conf/config.php
return array(
//...
'ACTION_SUFFIX' => 'Action'
);
// ./Application/Home/Controller/IndexController.class.php
//...
class IndexController extends Controller { // 控制器
    public function index(){ //由于没有后缀,打开./时会报错
        echo "index<br>";
    }
    public function listAction(){ //通过访问./index.php/Home/Index/List来执行
        echo "list";
    }
}

空控制器与空操作

空控制器是当系统找不到请求的控制器名称时,系统会尝试定位到空的控制器 EmptyController

空操作是当系统找不到请求的操作方法时,系统会尝试定位到空的操作方法 _empty

利用这个机制可以实现错误页面和 URL 优化。

// ./Application/Home/Controller/EmptyController.class.php
<?php
namespace Home\Controller;
use Think\Controller;
class EmptyController extends Controller {
    public function _empty(){
        echo "not found";
    }
}

//当访问不存在的页面(如 ./index.php/Home/User/index)时,会用 `EmptyController -> _empty()` 中的内容替换默认的错误页面

操作绑定到类

可以设置参数 ACTION_BIND_CLASS 来开启,可以让开发工作更加细化。此时,控制器和操作方法的定义成了目录的形式。

1
2
3
4
5
6
//配置`ACTION_SUFFIX`的值改变操作方法的书写形式
// ./Application/Home/Conf/config.php
return array(
//...
'ACTION_BIND_CLASS' => true
);
// 新建目录 ./Application/Home/Controller/Index
// ./Application/Home/Controller/Index/index.class.php
<?php
namespace Home\Controller\Index; //命名空间根据目录结构来
use Think\Controller;
class index extends Controller {
    public function run(){
        echo "bind action";
    }
}
// 浏览器访问 ./
bind action

调用的四种方式

  • 自动定位
  • new 实例化
  • A 函数
  • R 函数

URL模式

4种模式

通过 URL_MODEL 配置:

  • 0:普通模式(http://domain/index.php?m=model&c=controller&a=action
  • 1:PathInfo(http://domain/index.php/model/controller/action)(默认)
  • 2:ReWrite(http://domain/model/controller/action
  • 3:兼容模式

PathInfo、ReWrite 需要运行环境支持。

U函数

ThinkPHP 提供U函数动态生成模式匹配的 URL:

U('地址表达式', ['参数'], ['伪静态后缀'], ['显示域名'])
  • 地址表达式[模块/控制器/操作#锚点@域名]?参数1=值1&参数2=值2...
  • 第二个参数支持数组、字符串两种定义方式
  • 类 UNIX 系统对 URL 大小写敏感,通过配置 URL_CASE_INSENSITIVE 实现不区分大小写的 URL 访问

伪静态

通常为了满足更好的 SEO 效果:

  • URL_HTML_SUFFIX配置伪静态后缀
  • URL_DENY_SUFFIX配置禁止访问的URL后缀

共用示例

// ./Application/Home/Controller/IndexController.class.php
// 该部分为下面三个模式共用
//...
class IndexController extends Controller {
    public function index(){
        $this -> listActionsUrl();
    }
    private function listActionsUrl() {
        echo '当前 URL 模式为:' . C('URL_MODEL'); . '<br>';
        echo 'User 控制器 index 的操作方法的 URL 为:' . U('Home/User/index'); . '<br>';
        echo 'User 控制器 edit 的操作方法的 URL 为:' . U('Home/User/edit'); . '<br>';
        echo 'User 控制器 login 的操作方法的 URL 为:' . U('Home/User/login'); . '<br>';
    }
}

PathInfo模式

// ./Application/Home/Controller/UserController.class.php
//...
class UserController extends Controller {
    public function index(){
        echo 'user.index';
    }
    public function edit(){
        echo 'user.edit';
    }
    public function login(){
        echo 'user.login';
    }
}
1
2
3
4
5
//浏览器
当前 URL 模式为:1
User 控制器 index 的操作方法的 URL 为:/./index.php/Home/User/index.html
User 控制器 edit 的操作方法的 URL 为:/./index.php/Home/User/edit.html
User 控制器 login 的操作方法的 URL 为:/./index.php/Home/User/login.html

普通模式

1
2
3
4
5
// ./Application/Home/Conf/config.php
return array(
  //...
  'URL_MODEL' => 0
);
1
2
3
4
5
//浏览器
当前 URL 模式为:0
User 控制器 index 的操作方法的 URL 为:/./index.php?m=Home&c=User&a=index
User 控制器 edit 的操作方法的 URL 为:/./index.php?m=Home&c=User&a=edit
User 控制器 login 的操作方法的 URL 为:/./index.php?m=Home&c=User&a=login

Rewrite模式

1
2
3
4
5
// ./Application/Home/Conf/config.php
return array(
  //...
  'URL_MODEL' => 2
);
1
2
3
4
5
//浏览器
当前 URL 模式为:2
User 控制器 index 的操作方法的 URL 为:/./Home/User/index.html
User 控制器 edit 的操作方法的 URL 为:/./Home/User/edit.html
User 控制器 login 的操作方法的 URL 为:/./Home/User/login.html
1
2
3
4
5
6
7
//更改后缀
// ./Application/Home/Conf/config.php
return array(
  //...
  'URL_MODEL' => 2,
  'URL_SUFFIX' => 'shtml'
);
1
2
3
4
5
//浏览器
当前 URL 模式为:2
User 控制器 index 的操作方法的 URL 为:/./Home/User/index.shtml
User 控制器 edit 的操作方法的 URL 为:/./Home/User/edit.shtml
User 控制器 login 的操作方法的 URL 为:/./Home/User/login.shtml

本地 Apache 服务器实现 Rewrite 模式

Rewrite 是通过 URL 重写隐藏应用的入口文件index.php

  • Apache 开启 mod_rewrite.so 模块
  • AllowOverride All
  • 定义分布式配置文件 htaccess
  • 配置完后必须重启 Apache 服务器才能生效
1
2
3
4
5
6
7
8
9
# httpd.conf,开启下面的项
LoadModule rewrite_module modules/mod_rewrite.so
# 配置根目录(以 D:\path\to\ 为例)
DocumentRoot "D:/path/to/"
# 在 <Directory "D:/path/to/"> 中找到下面的项并设置
  AllowOverride All

# ./.htaccess(ThinkPHP 自带的分布式配置文件)已经定义好了
# 重启 Apache 服务器

配置 Apache 虚拟主机 Vhost

通过配置 Apache 虚拟主机 Vhost 实现更接近生产环境的 URL

  • Apache 开启 mod_vhost_alias.so 模块
  • 配置 httpd-vhosts.conf
  • 添加 hosts 主机头实现转发
  • 配置完后必须重启 Apache 服务器才能生效
# hosts,添加下面的项(以 a.bc 为例)
127.0.0.1  a.bc
# httpd.conf,开启下面的项
LoadModule vhost_alias_module modules/mod_vhost_alias.so
1
2
3
4
5
6
7
8
9
# Apache 下的 conf/extra/httpd-vhosts.conf,添加如下代码(除注释)
<VirtualHost *.80>
  # D:/path/to/ 为需要映射到的目录
  DocumentRoot "D:/path/to/"
  ServerName a.bc
  ErrorLog "logs/a.bc-error.log"
  CustomLog "logs/a.bc-access.log" comon
</VirtualHost>
# 重启 Apache 服务器

页面跳转和响应

方式

ThinkPHP 控制器提供了以下几种方式实现页面跳转和响应:

  • 重定向
  • 成功提示跳转
  • 错误提示跳转
  • 实现 Ajax 数据返回

重定向

redirect($addr, $comm, $time, $msg)
  • $addr:跳转地址表达式
  • $comm:附加参数
  • $time:跳转时间(秒)
  • $msg:提示信息

成功提示跳转

sucess($msg, $addr, $time)

支持 AJAX 响应。

  • $msg:提示信息
  • $addr:跳转地址
  • $time:跳转时间(秒)

错误提示跳转

error($msg, $addr, $time)

支持 AJAX 响应。

参数意思同“成功提示跳转”。

实现 Ajax 数据返回

ajaxReturn($data, $type)
  • $data:要返回的数据
  • $type:数据格式(如 jsonxml

判断请求的类型

控制器定义了 6 个常量,用来快速判断请求的类型:

  • IS_GET
  • IS_POST
  • IS_PUT
  • IS_DELETE
  • IS_AJAX
  • REQUEST_METHOD(枚举)

AJAX 请求的识别参数

如果不是用 jQuery 发起 AJAX 的话,需要在请求中添加一个参数才能让服务器知道是一个 AJAX 请求。

默认的参数名称是 ajax。通过 VAR_AJAX_SUBMIT 配置。

// ./Application/Home/Controller/UserController.class.php
// redirect
//...
class UserController extends Controller {
    //以下仅显示以下部分
    public function index(){
        $this -> redirect('edit', '', 2, '纯跳转'); // 显示“纯跳转”,2 秒后跳转到 ./index.php/Home/User/edit
    }
    //以下仅显示以上部分
    public function edit(){
        echo 'user.edit';
    }
    public function login(){
        echo 'user.login';
    }
}

// success
    public function index(){
        $this -> success('成功跳转', U('User/login'), 3);// 成功跳转页面,显示“成功跳转”,3 秒后跳转到 ./index.php/Home/User/login
    }

// error
    public function index(){
        $this -> success('出错了', U('User/login'), 5);// 错误跳转页面,显示“出错了”,5 秒后跳转到 ./index.php/Home/User/login
    }
// ./Application/Home/Common/function.php
<?php
function getTestData() {
  $data = array();
  for($i = 0; $i < 10; $i++) {
      $data[$i]['name'] = 'user-' . $i;
      $data[$i]['age'] = rand(18, 90);
  }
  return $data;
}

// ./Application/Home/Controller/UserController.class.php
//...
class UserController extends Controller {
    public function index(){
        $this -> ajaxReturn(getTestData(), 'json'); //返回 json 的 data 数据
    }
}

获取输入变量

获取输入变量的方式

  • $_GET$_POST$_SERVER不安全:没有统一的数据过滤,容易发生如SQL注入的攻击)
  • ThinkPHP 提供了 I 函数,方便实现输入变量读取,并自动进行数据安全过滤。

I函数

I('变量类型.变量名', ['默认值‘], ['过滤方法'], ['额外数据源'])
// server
// ./Application/Home/Controller/UserController.class.php
//...
class UserController extends Controller {
    public function index(){
        //下面一个案例只显示以下内容
        $server = I('server.'); // $_SERVER 数组的全部值
        //下面一个案例只显示以上内容
        dump($server);
    }
}

        $server = I('server.HTTP_HOST'); // 主机名

//get
    public function login(){
        $user = I('get.user', null);
        if($user === 'a') {
          //a  // 如果访问 ./Home/User/login/user/a 时会跳到这里
        } else {
          //not a
        }
    }

来源

【极客学院】PHP全套教学视频_哔哩哔哩 (゜-゜)つロ 干杯~-bilibili