一、框架概述
1、什么是框架
框架即英文名为Framework,它是许多代码文件的集合,这些代码文件是程序结构的代码,不是业务代码,里面包含了许多函数、类库(分页类、验证码类、文件上传类、DB类、Image类…)、设计模式(mvc、单例、AR..)等。
以后使用框架开发项目只需要写业务代码即可。
现在企业中开发模式基本有三种:
从快到慢排序:二次开发(需要修改源码)—>框架开发—->源码开发
源码开发建房子:从0开始,打地基.、浇筑水泥、、
框架开发建房子:相当于毛坯房,各种装修。
源码开发建房子:相当于精装修的房子,只需要拎包入住.
现在企业开发较多的模式属框架开发。
2、框架开发的好处
- 框架能节省开发时间
每个项目中常用的类库框架都已经封装好,如分页类、图像类,文件上传类等,直接调用即可,非常方便。(减少重复造轮子)
- 利于团队的合作开发
因为框架都是mvc设计模式,模块划分清晰,可以帮助我们快速、稳定、高效搭建web应用,从而提高开发效率。
- 使用框架的过程中可以使得我们的注意力全部集中在业务层面,而无需关心程序的底层架构。
3、框架的设计模式(MVC)
基本现在主流的框架(CI、TP、laravel、YII、zend framework、symfony、cakephp),都是采用单一入口(index.php),且都是采用mvc的设计模式,把一个web应用程序分为三块,控制器、模型、视图。
C-Controller 控制器
主要作用:就是接收用户的请求,在模型和视图之间起一个调度的作用
M-Model 模型
作用:对数据库做增删改查(curd)的
V-View视图
展示模板内容,给用户一个可操作的界面
mvc(框架)形象理解-酒店(难以理解的东西一定要把抽象的东西给生活化):
常见的php开发框架
ThinkPHP框架(TP框架)
TP框架的logo:
主要开发中小型项目
ThinkPHP框架是我们国人开发采用mvc模式设计的一款比较优秀的框架。在我们国内使用量较多,且开发文档也多,方便学习。
(2)CodeIgniter 框架
CodeIgniter框架:简称CI框架,
主要开发中小型项目
YII(易框架)
YII(简称易框架):主要开发大型的web应用程序:
Laravel框架
此框架使用量世界排名第一,有最”优雅”的框架称号。
注:Laravel底层代码很多都是借鉴了SymFony的优点。
(5)Zend官方框架
Zend Framework:php官方提供的框架,非常笨重,主要开发大型的web应用程序。
(6)Symfony国外框架
框架只有最合适的,没有最好的,需结合自己的系统业务去选择最合适的。
国内使用最多的框架是TP、laravel、CI。YII框架外企使用较多
ThinkPHP5框架
下载TP5框架
下载地址:http://www.thinkphp.cn/down.html
TP5框架的目录认识
手册位置:基础–>目录结构
- 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 命令行入口文件
每个application下面的模块目录都有mvc分层结构:
可参考手册:
三、使用TP5框架部署项目
我们是使用ThinkPHP5+ajax+jquery以及和第三方插件结合起来,做一个文章管理系统,掌握怎样使用ThinkPHP5快速开发一个项目。
配置项目虚拟主机
主要三个核心步骤:1、使用phpStudy建立虚拟主机 2、设置hosts文件映射 3、重启apache服务器
把框架的文件复制到我们的虚拟主机目录中去:
- 使用phpStudy建立虚拟主机 (www.article.com)
最终生成的虚拟主机文件(vhosts.conf)配置如下:
- 设置hosts文件映射
- 重启apache服务器
2、访问虚拟主机
输入配置的域名直接访问:
为什么会出现上面的一个笑脸?
答:那是因为受到框架的配置文件application/config.php的影响,默认访问index模块的index控制器的index方法,如下:
可以对index控制器的index方法的内容进行更改:
再次访问如下:
注:tp5默认值支持老本tp3的pathinfo模式进行访问。
如:http://域名/index.php/模块/控制器/方法名/参数1/值1/参数2/值2/
例:访问index模块的index 控制器的index方法
http://域名/index.php/index/index/index/参数1/值1/参数2/值2/
3、响应输出
控制器的所有操作方法都是return返回而不是直接输出,系统会调用Response::send方法将最终的应用返回的数据输出到页面或者客户端,并自动转换成default_return_type参数配置的格式。所以,应用执行的数据输出只需要返回一个正常的PHP数据即可。
tp5也是建议统一使用return返回数据,而不是echo输出,如非必要,请不要使用exit或者die中断执行。
四、控制器
控制器的作用
C:Controller
作用:主要是接受用户的请求,在模型和视图之间起调度的作用。
创建控制器
(1)修改控制器后缀
由于国人命名的习惯,我们可以通过以下配置文件给控制器文件名加个Controller后缀。
打开配置文件,[项目目录]/application/config.php,做如下修改:
创建控制器语法
语法规则:
控制器类名:控制器名+Controller
控制器文件名:控制器名+Controller.php
控制器文件所在路径:application/模块名/controller/
如在index模块下定义一个Test控制器:
控制器类名: TestController
控制器类文件名: TestController.php
文件定义位置:index/controller/TestController.php
注:类名首字母大写
代码如下:
访问:
访问控制器
1、可以通过tp3老版本的pathInfo模式进行访问。
http://网址/index.php/分组/控制器名称/操作方法名称
如访问Index模块的index控制器的test1方法
2、也可以把index.php入口文件给隐藏掉,变为下边的路由形式:
省去index.php入口访问,修改项目的重写文件.htaaccess。
第一步:文件位置:[项目根目录]/Public/.htaccess ,做如下修改:
(注:上图在index.php后边加”?”号)
重写文件.htaccsee解释:
<IfModule mod_rewrite.c>
Options +FollowSymlinks -Multiviews
RewriteEngine On #开启重写规则
RewriteCond %{REQUEST_FILENAME} !-d #如果请求的不是一个目录(-d 代表目录)
RewriteCond %{REQUEST_FILENAME} !-f #且如果请求的不是一个文件(-f 代表文件)
RewriteRule ^(.*)$ index.php?/$1 [QSA,PT,L] #上面两个条件都不满足,执行RewriteRule重写规则
</IfModule>
重写规则: RewriteRule 虚拟规则(正则写) 服务器真实文件路径
即用户输入的域名后面的规则若满足虚拟规则,就会访问对应的真实文件。
第二步:修改虚拟主机vhosts.conf的配置:加上AllowOverride All ,默认phpstudy创建的虚拟主机自带这一行。
第三步。再去httpd.conf开启重写文件:
重启apache服务器,省去入口文件index.php进行访问:
开启调试模式
为了在开发过程中,开发者能够及时看到详细的错误信息,我们在开发阶段可以把以下config配置文件中的app_debug配置设置为true,
访问一个不存在的方法,会报详细的错误。
若设置为false,则会出现友好的提示:
所以,项目上线后,我们要把此配置改为false。不要让用户看到我们网站报错。
五、项目分组(模块)
1、创建分组
一个项目中一般都有Home、Admin分组,即前台和后台,那对应框架中就是一个具体的文件夹,每个项目文件夹都有对应的控制器、模型、视图对应的文件夹,tp5框架中默认有一个分组index。
我们只需要把index分组复制一份改名(如admin)放在Application目录下即可,同时修改对应类所在分组的命名空间即可。
也需要改对应类的命名空间:
访问如下:
2、默认分组的设置
需修改框架的application/config.php的配置文件,如默认访问admin分组的index控制器的index方法,做如下修改:
直接输入域名访问的则是admin模块下的index控制器的index方法:
3、分组的访问权限控制
需修改框架的application/config.php的配置文件:
上图是设置禁止访问common和index分组。
再次访问index模块,会报错。
六、【了解】命令行操作
命令行创建分组
创建文件application/build.php并填充内容,可以参考根目录 build.php
[项目根目录] > php think build
创建application/build.php并填充如下内容:
执行命令
创建分组的效果
命令行创建控制器
[项目根目录] > php think make:controller 分组/名称
注:不写分组名会直接创建在common分组中
例:在Common中生成一个Demo的控制器
生成如下所示:
例如下述,要给index分组创建UserController.php控制器文件
[项目根目录] > php think make:controller index/User
命令如下;
生成的文件:
七、使用路由访问
老版本TP3.2多种访问模式(了解):
- pathinfo模式(默认形式,,重点掌握):http://域名/index.php/模块/控制器名/方法名/参数名/参数值/参数名/参数值…
- 普通模式(get形式):http://域名/index.php?m=模块&c=控制器名&a=方法名&参数名=参数值…
- rewrite模式(隐藏入口文件):http://域名/模块/控制器名/方法名/参数名/参数值/参数名/参数值…
- 兼容模式:http://域名/inde.php?s=/模块/控制器名/方法名/参数名/参数值…
上面的四种模式在tp5默认都是支持的。其在tp5框架中还可以单独定义路由规则来访问某个控制器中的某个方法。
只要配置文件config.php中开启路由功能,访问的时候就会经过路由规则,根据定义的路由规则从而访问到某个控制器中的方法。
路由图解:
- 开启路由,修改application/config.php配置文件
‘url_route_on’ => true, // 开启路由
‘url_route_must’ => true, // 必须使用路由(即不能使用之前的pathinfo模式访问)
注:若url_route_must设置为true,就不就可以通过上面四种模式来访问,只能通过定义的路由规则访问。
2、定义路由规则,定义在application/route.php文件中
Route::rule(‘路由表达式’,’路由地址’,’请求类型’,’路由参数(数组)’,’变量规则(数组)’);
说明:
路由表达式:静态地址、动态地址、可选动态地址
路由地址:表示路由表达式最终需要路由到的地址,有多种定义方式,常用的是”模块/控制器/操作?额外参数1=值1&额外参数2=值2”形式
请求类型:GET、POST 必须是大写的
路由参数:
method:请求类型
ext:允许的后缀
deny_ext:禁止的访问后缀
domain:允许什么样的域名访问有效
https:检测是否是https请求
before_behavior:行为发生前,进行路由检查
after_behavior:行为发生后,要执行的动作
…
详情参考:手册路由–>路由参数
变量规则:检查传递的变量是否符合某个(正则)规则,规则可以通过正则定义
例如规则:
Route::rule(‘login’,’home/User/login’,’GET’,[‘ext’=>’html’]);
访问:http://servername/index.php/login.html
路由到:http://servername/index.php/home/User/login
Route::rule(‘login/:id’,’home/User/login’,’GET’,[‘ext’=>’html’],[‘id’=>’\d+’]);
访问:http://servername/index.php/login/101.html
路由到:http://servername/index.php/home/User/login/id/101
Route::rule(‘login/:id/:name’,’home/User/login’,’GET’,[‘ext’=>’html’],[‘id’=>’\d+’,’name’=>’[a-zA-Z]+’]);
访问:http://servername/index.php/login/101/tom.html
路由到:
http://servername/index.php/home/User/login/id/101/name/tom
也可以像下边这样定义:
Route::get(‘路由表达式’,’路由地址’,’路由参数(数组)’,’变量规则(数组)’);
Route::post(‘路由表达式’,’路由地址’,’路由参数(数组)’,’变量规则(数组)’);
如一个控制器中的方法在路由规则中没有定义则是不允许被访问,报以下错误:
解决办法,把application/config.php文件中的以下配置改为false,就说明路由规则和pathinfo形式两者都可以进行访问。
‘url_route_must’ => false, // 是否强制使用路由
在application/route.php中定义路由规则:
访问如下:
展示视图
语法:控制器中调用fetch方法
return $this -> fetch(模块@控制器/操作);
注意:
控制器要想正常调用fetch方法,则必须继承Controller类:use think\Controller
fetch()具体有下述5种用法:
- 调用:view下当前控制器名/当前操作名.html模版文件
return $this -> fetch();
- 调用:view下当前控制器的/add.html模版文件
return $this -> fetch(‘add’);
- 找到view下边user目录的login.html模版文件[跨控制器]
return $this -> fetch(‘user/login’);
- 找到admin分组view目录的manager下边的login.html模版文件[跨分组]
return $this -> fetch(‘[email protected]/login’);
代码如下:
结果:
九、模板赋值
语法:在控制器调用assign方法
- public function index()
- {
- // 模板变量赋值
- $this->assign(‘name’,’ThinkPHP’);
- $this->assign(’email’,’[email protected]’);
- // 或者批量赋值
- $this->assign([
- ‘name’ => ‘ThinkPHP’,
- ’email’ => ‘[email protected]’
- ]);
- // 模板输出
- return $this->fetch(‘index’);
- }
或者把模板变量直接传递给fetch方法:
- public function index()
- {
- return $this->fetch(‘index’, [
- ‘name’ => ‘ThinkPHP’,
- ’email’ => ‘[email protected]’
- ]);
- }
代码如下:
模板中显示:
效果:
建议使用如下方式,分配模板变量:
模板中显示:
十、模板常用标签
volist标签
作用:主要用来遍历数组
语法:
Volist标签的name属性表示模板赋值的变量名称,因此不可随意在模板文件中改变。id表示当前的循环变量,可以随意指定,但确保不要和name属性值冲突。
代码如下:
控制器对模板赋值:
模板遍历:
效果:
循环数组序号(标号):
注:如果不知道key属性,默认{$key}从0开始,所以需要加1{$key+1}
比较标签
参考手册:
使用范例:
代码如下:
模板赋值遍历:
模板判断:
效果:
php标签
如果模板标签太多记不住,这里可以使用php标签统一进行一些代码的编写:
例1:代码如下:
例2:代码如下:
控制器赋值:
模板获取:
效果:
include包含标签
作用:
一般网站页面的头部或尾部的网页效果都是一样的,我们就可以把这些网页的代码抽离出来放在一个html文件中,需要使用这些文件的时候,在模板中用include标签引入即可,从而提高代码的复用性。
include语法:
注意:file的路径是从当前模块的view目录下开始找起。
如:有一个header.html模板,其所在路径为:Admin/view/public/header.html
在模板中引入此文件: <include file=”public/header” />
代码如下:
控制器输出模板:
在模板中引入公共的文件:
注:文件名后缀不要加html
效果:
十一、搭建后台首页
第一步:在后台Admin建立一个Index的控制器,输出模板内容
第二步:把我们的后台模板index.html复制到/admin/view/index/目录下面
第三步:把后台模板的left.html 、 top.html 、main.html复复制到/admin/view/index/目录下面.
第四步:在建立left、top、main三个方法
第五步:设置index.html模板的iframe的src路径:
注:助手函数:url(‘模块/控制器/方法’) 生成url地址,在模板中使用函数需要在一对花括号{}前面加个冒号:
第六步:把后台资源(img、css、js),复制到网站根目录public/admin/目录下面
同时config.php配置文件中,定义一个后台资源目录的路径,在模板中进行统一替换:
第七步:模板中替换使用config函数获取配置进行替换:
和上面操作一样分别替换top.html、left.html、main.html的静态资源目录。
最终效果:
注:助手函数config(‘配置名’),是获取配置文件中的值。模板中使用需要在{}前面加个冒号:。
助手函数手册位置:附录–》助手函数
十二、搭建登录页
第一步:在后台admin建立一个Public控制器,并建立一个login的方法,输出模板内容
第二步:把后台模板login.html赋值到/admin/view/public/目录下面,并替换静态资源文件路径
效果:
sublime快捷键:
替换:ctrl+h
找文件:ctrl+p
十三、控制器中的页面跳转和重定向
1、跳转
在应用开发中,经常会遇到一些带有提示信息的跳转页面,例如操作成功或者操作错误页面,并且自动跳转到另外一个目标页面。系统的\think\Controller类内置了两个跳转方法success和error,用于页面跳转提示
成功跳转:$this->success($msg,$url,$data,$time)
失败跳转:$this->error($msg,$url,$data,$time))
参数说明:
- msg:跳转的提示信息
- url:跳转的地址。 建议用助手函数url()生成地址。,失败默认跳回上一页。一般不需要指定
- data: 返回的数据,没有则留空
- time:默认成功和失败都是3秒,
代码如下:
success和error方法源码位置:
重定向
语法:
$this-> redirect(url,[$params])
参数说明:
第一个参数必填,后面两个个参数可缺省。
- $url:跳转的地址, 形式为 “模块/控制器/方法” 。
若直接写方法名如:$this-> redirect(‘index’),默认会重定向到当前模块的当前控制器的index方法。
若直接写控制器名和方法名如:$this-> redirect(‘index/index’),默认会重定向到当前模块的index控制器的index方法。
- $params:跳转携带的参数,数组形式如:传id等于3,array(“id”=>3)
$this -> redirect(分组/控制器/操作方法)
跳转到的地址:http://网址/分组/控制器/操作方法
$this -> redirect(分组/控制器/操作方法,[参数1=>值1,参数2=>值2])
跳转到的地址:http://网址/分组/控制器/操作方法/参数1/值1/参数2/值2
代码如下:
问:什么时候使用跳转和重定向?
答:
1、需要给用户操作的提示信息,则用跳转。
一般是删除或编辑失败的时候,这需要给用户提示错误信息,操作失败则用跳转error,成功用success。
2、不需要给任何提示信息,则用重定向。
如用户登录成功不需要给提示信息则直接redirect重定向到首页,登录失败就用error给用户提示错误信息。
请求Request
手册参考位置:请求–>请求信息
获取Request对象
图解Request对象、response对象:
图解说明:
- 服务端server把客户端请求过来的相关信息都封装在一个Request对象中。如请求地址、请求参数、请求类型、上传的文件信息等。
- 服务端server把响应给浏览器的相关信息都封装在一个Response对象。如响应http状态码200给客户端等。
获取Request对象的方式:
方式一:
引用\think\Request类 ,$request = Request::instance();
助手调试函数dump();内部封装pre格式化标签。
方式二(最简单的方式):
通过tp5框架提供的助手函数request()
$request = request();
方式三:
通过依赖注入(闭包)的方式,把Request对象注入到方法内部
public function 方法名(Request $request){}
相当于把Request类的对象$request作为p4的参数。
2、获取请求信息
手册参考位置:请求–>请求信息
$request->domain(); // 获取当前域名
$request->baseFile(); // 获取当前入口文件,不含域名
$request->url(); // 获取当前URL地址
$request->url(true); // 包含域名的完整URL地址
$request->baseUrl(); // 获取当前URL地址 不含QUERY_STRING
$request->pathinfo(); // 获取URL地址中的PATH_INFO信息
$request->path(); // 获取URL地址中的PATH_INFO信息 不含后缀
$request->ext(); // 获取URL地址中的后缀信息
$request->header(); // 获取当前请求的HTTP 请求头信息
$request->module(); // 获取当前模块名称
$request->controller(); // 获取当前控制器名称
$request->action(); // 获取当前操作名称
$request->method(); // 获取请求方法
$request->type(); // 获取资源类型
$request->ip(); // 获取访问ip地址
$request->isAjax(); // 判断 是否是ajax请求
$request->isPost(); // 判断 是否是post请求
$request->isGet(); // 判断 是否是get请求
代码如下:
3、获取请求参数
手册参考位置:请求–>输入变量
语法:变量类型方法(‘变量名/变量修饰符’,’默认值’,’过滤方法’)
方法 | 描述 |
---|---|
param | 获取当前请求的变量信息 |
get | 获取 $_GET 变量 |
post | 获取 $_POST 变量 |
session | 获取 $_SESSION 变量 |
cookie | 获取 $_COOKIE 变量 |
request | 获取 $_REQUEST 变量 |
server | 获取 $_SERVER 变量 |
env | 获取 $_ENV 变量 |
route | 获取 路由(包括PATHINFO) 变量 |
file | 获取 $_FILES 变量 |
(1)获取PARAM变量
PARAM变量是框架提供的用于自动识别GET、POST或者的一种变量获取方式,是系统推荐的获取请求参数的方法,用法如下:
// 获取当前请求的name变量
$request->param(‘name’);
// 获取当前请求的所有变量(经过过滤)
$request->param();
// 获取当前请求的所有变量(原始数据)
$request->param(false);
// 获取当前请求的所有变量(包含上传文件)
$request->param(true);
注:param方法会把当前请求类型的参数和PATH_INFO变量以及GET请求合并。
或使用助手函数实现:
input(‘param.name’);
input(‘param.’);
或者
input(‘name’);
input(”);
因为input函数默认底默认就采用PARAM方式进行读取变量。
(2)获取GET变量
使用内置的助手函数input获取get参数
input(‘id’);
input(‘name’);
input(‘get.’); //获取整个get数组参数
代码如下:
- 把表单设置get方式提交,不写action默认跳转到当前地址
假设输入的数据如下:
b、在当前方法p3中接收整个get参数和单个get参数,结果
(3)获取POST变量
使用助手函数实现:
input(‘name’);
input(‘post.’); //获取整个post数组参数
代码如下:
a、把表单设置post方式提交,不写action默认跳转到当前地址
假设输入的数据如下:
b、在当前方法p3中判断是否是post请求,获取整个post参数和单个post参数