前言:
1、为了书写方便,thinkPHP在下面会用"tp"或"TP"代替
2、在阅读该文章前是默认读者对PHP的基本语法和数据库操作是较为熟悉。
3、用 · 符号开头的是一个独立的知识点。
4、横线代码每个知识点的分割线
· 如何使用TP呢?其实就3步,下面会逐一介绍
1、找到ThinkPHP的完整版
2、通过ThinkPHP自动生成项目目录
3、在生成的项目上编写代码
· ThinkPHP核心文件介绍
├─ThinkPHP.php 框架入口文件
├─Common 框架公共文件
├─Conf 框架配置文件
├─Extend 框架扩展目录
├─Lang 核心语言包目录
├─Lib 核心类库目录
│ ├─Behavior 核心行为类库
│ ├─Core 核心基类库
│ ├─Driver 内置驱动
│ │ ├─Cache 内置缓存驱动
│ │ ├─Db 内置数据库驱动
│ │ ├─TagLib 内置标签驱动
│ │ └─Template 内置模板引擎驱动
│ └─Template 内置模板引擎
└─Tpl 系统模板目录
· 使用thinkPHP生成项目目录
描述:只需自己新建一个index.php文件作为入口文件,再引用tp的启动文件即可。代码如下:
//定义一个应用名称 define('APP_NAME','demo'); //定义要生成项目的路径 define('APP_PATH','./demo/'); //引入to的启动文件 require 'ThinkPHP/ThinkPHP.php';
项目目录结构及说明:
demo 项目文件夹
├─Common 项目公共文件目录
├─Conf 项目配置目录
├─Lang 项目语言目录
├─Lib 项目类库目录
│ ├─Action Action类库目录
│ ├─Behavior 行为类库目录
│ ├─Model 模型类库目录
│ └─Widget Widget类库目录
· tp的路由模式,有4种
1.PATHINFO => http://域名/项目名/入口文件/模块名/方法名/键1/值1/键2/值2
2.普通模式 => http://域名/项目名/入口文件?m=模块名&a=方法名&键1=值1&键2=值2
3.重写模式(REWRITE) => http://域名/项目名/模块名/方法名/键1/值1/键2/值2
4.兼容模式 => http://域名/项目名/入口文件?s=模块名/方法名/键1/值1/键2/值2
叙述:什么是路由?在前端表现就是URL,在后端表现就是文件管理器的"文件路径"。为什么叫路由?是平时上网用的路由器吗?当然不是,至于为什么叫路由,不知道,大家都这样叫。就这样叫呗。关键是它为什么叫路由不是重点,不必深究。在初学阶段,只需搞清楚PATHINFO和普通模式就可以,另外两个不必深究,也不在本教程范围内,因为前面两种模式已经够用了。很多初学者认为路由的模式很难,其实只是被它的符号吓到,就像初学正则那样。但其实是很简单,只要搞清楚一个问题就可以了,就是"路由是怎样和这个框架产生的项目文件结构对应起来?"
-------路由是怎样和这个框架的文件结构对应起来?--------
要理解这个问题,只需清楚两个点,即"模块"和"方法"。这两个词也是贯穿TP框架的文件映射,例如:
http://127.0.0.1/thinkPHP_test/index.php/Index/show/name/我是小明
关系是: index.php作为入口文件,Index是该入口文件下的模块,show是该模块下的方法,name是show方法的参数,我是小明是name参数的值。这样一层一层下去。
综上所述:TP的路由就两个字总结:"映射"
补充:在这里说下,普通模式的规则,m代表是模块名,a代表方法名,至于为什么要用m和a开头,框架规定这样写的,不必深究。
· 在生成的项目上编写代码:
先看tp自动生成的列子,打开目录demo -> Lib -> Action -> IndexAction.class.php ,代码如下:
<?php // 本类由系统自动生成,仅供测试用途 class IndexAction extends Action {
//这个公共方法是tp自动生成的方法 public function index(){ $this->show('<style type="text/css">*{ padding: 0; margin: 0; } div{ padding: 4px 48px;} body{ background: #fff; font-family: "微软雅黑"; color: #333;} h1{ font-size: 100px; font-weight: normal; margin-bottom: 12px; } p{ line-height: 1.8em; font-size: 36px }</style><div style="padding: 24px 48px;"> <h1>:)</h1><p>欢迎使用 <b>ThinkPHP</b>!</p></div><script type="text/javascript" src="http://tajs.qq.com/stats?sId=9347272" charset="UTF-8"></script>','utf-8'); } //这是自定义的方法 public function show(){ echo "你好,".$_GET['name']; } }
调用: http://127.0.0.1/thinkPHP_test/index.php/Index/show/name/我是小明
详解:
1、大家有没有想过为什么IndexAction.class.php这个文件要这样命名?因为????Action.class.php这样的格式是tp对类文件的命名规则。前面的Index是对应哪个入口文件。
2、上面调用的URL,各个节点表示如下:
index.php是项目的入口文件,
/Index 表示是Index模块
/show 表示Index模块下的show方法
?name=我是小明 表示show方法下的参数,就是我们上面的自定义方法的中,通过$_GET获取回来的参数。
· 初次更改配置文件
我们尝试更改下路由的分隔符,比如把 http://域名/项目名/入口文件/模块名/方法名&参数=xxx 改成 http://域名/项目名/入口文件~模块名~方法名&参数=xxx,就是把" / " 改成 " ~ "
打开demo -> config -> config.php,写入如下代码
return array( 'URL_PATHINFO_DEPR' => '~' //把路由的分隔符改成 "~" ); ?>
调用:http://www.127.0.0.1/thinkPHP_test/index.php/index~show~name~我是小明
很明显,这种更改只能是对模块名往后的路由才有效,现在你肯定很奇怪,你的路由不生效。为什么呢?因为tp是有缓冲机制的,在自创建的项目目录会有一个叫Runtime的文件夹,它是每次运行tp都会创建的(已存在就不会创建),它是记录框架产生的缓冲、数据、日志和一些临时文件。这个时候,我们需要手动删除Runtime文件夹,在调用http://www.127.0.0.1/thinkPHP_test/index.php/index让它运行一次tp,这是tp会检查到Runtime文件夹不存在,就会创建,并且会去读最新的config文件。这是再调用上面的URL就OK了。
背景:从上可知,Runtime文件是做缓存的,那么我们就会想,难道每次修改东西都要手动去删除那个文件?如果是这样,真的要疯了。但tp有方法解决的,就是开启调试模式,就不会走缓存。那怎么开启?只需在index.php添加以下代码:
define('APP_DEBUG',true);
现在刷新页面就马上可以查看。
· 开启页面PAGE_TRACE:2步
1、在入口文件开启debug模式 (不清楚点这里)
2、在config/config.php,输入以下代码:
'SHOW_PAGE_TRACE' => true
效果如下:
· TP的模板输出:
叙述:模板输出只需搞清楚几个问题就可以了,下面逐一回答。
1、在哪里控制模板输出?
2、模板应该放在哪里?
3、控制的地方是怎样把数据传入模板?
4、模板又是怎样拿到传过来的数据?
---<1、在哪里控制模板输出?>---
这里又要回到MVC上,是C控制V(模板)的输出,M又是给C供货的(数据)。所以MVC就是仓库(M)、货车(C)、店铺(V)的关系。言归正传,现在知道哪里控制模板输出,但怎么输出呢?先打开 action文件夹下的
IndexAction.class.php,输入以下代码:
<?php // 本类由系统自动生成,仅供测试用途 class IndexAction extends Action { public function show(){ $this -> display(); } }
调用display就可以输出模板,但又来问题了?display参数都没有,输出什么东西?这就要回答第二个问题。
---<2、模板应该放在哪里?>---
模板是放在V层,也就tpl文件夹。在tpl文件夹下新建一个index文件夹,再在index文件夹新建一个show.html。TP的规则是action类对应tpl类,简单来说就是文件夹和文件的名字要和控制层的模块名和方法名对应上。看下图:
![](https://i-blog.csdnimg.cn/blog_migrate/b0d9f8ae0becf785f9cc3f78a7608aa3.png)
---<3、控制的地方是怎样把数据传入模板?>---
直接看代码:用过assign方法传入。
<?php class IndexAction extends Action { public function show(){ $name = "小明"; $this->assign('name',$name); $this -> display(); } } ?>
---<4、模板又是怎样拿到传过来的数据?>---
直接看代码:用TP的定界符{}取值。
<!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8"> <title></title> </head> <body> 我是SHOW模板,接到的变量是:{$name} </body> </html>
补充: 更改定界符可以在config文件更改:
左定界符:'TMPL_L_DELIM' => '<'
右定界符:'TMPL_R_DELIM' => '>'
a.循环变量输出模板:
<volist name="data" id="v"> id={$v.id} _____ username={$v.username} _____ sex={$v.sex}<br> </volist>
b.模板输出js代码
<script> alert("{$data[0].username}") </script>
c.display() 参数指定模板
$this -> display('show')
上面就是强指定show模板输出
· 链接数据库:总体是3步:
1、建立数据库
2、在config/config.php配置数据库信息,列子如下:
--------普通方式配置------------ 'DB_TYPE' => 'MYSQL', //数据库类型 'DB_HOST' => 'localhost', //数据库地址 'DB_NAME' => 'thinkphp_test', //数据库名称 'DB_USER' => 'root', //数据库用户名 'DB_PWD' => '', //数据库密码 'DB_PORT' => '3306', //数据库端口 'DB_PREFIX' => 'tp_', //数据表前缀
注意:thinkphp是有默认前缀,默认为'think_' --------或者使用DSN方式配置------------ 'DB_DSN'=>'mysql://root:@localhost:3306/thinkphp_test' 注意:用DSN方式,前缀是没法配置的,DSN的优先级比普通高
3、使用TP链接数据库,用new model 或 M 都可以创建模型类,模型类就是用来操作数据库的,所谓的操作就是增删改查(CDUR)
$m = new Model('User'); //用Mode类生成一个子类,参数为数据表名称 $arr = $m->select(); //获取该数据库的全部数据 var_dump($arr); //打印
补充:关于CDUR的操作,TP对应的方法如下:
增 -C Create $m->add()
删 -D Delete $m->delete()
改 -U Update $m->save()
查 -R Read $m->select()
· 输出格式化 :dump
$m = M('User'); dump($m.select());
· 对数据库CDUR操作,这些数据库操作的方法大部分第一个参数都是以主键为准的
1、创建(C):add
格式: $m -> 字段名 = 值; $m.add(); --------例子---------- $m -> username = '奇迹'; $return = $m -> add(); echo $return; 返回值:新增的id号
2、删除(D):delete
$del = $m -> delete(9); echo $del;
返回值:受影响行数
3、更新(U):save
$data['id'] = 2; $data['username'] = '传奇'; $count = $m -> save($data); echo $count;
返回值:受影响行数,但要注意返回值要用 $count !== false 进行比较,因为它有可能返回0
4、读取(C):select、find、getField
------select方法 :查找全部------------ $m = M('User'); $arr = $m->select(); //获取user表中全部的数据 var_dump($arr); ------find方法 :查找单个------------ $m = M('User'); $arr = $m->find(2); //比如,传一个参数为2,则找出主键为2的数据 var_dump($arr); ------getField方法 : 查找单个------------ $m = M('User'); //参数为某个字段,前面加个where则是刷选id为2的username $arr = $m->where('id=2')->getField('username'); var_dump($arr);
· 数据库之条件查询 :(查询方式有5种)
1、普通查询方式
2、表达式查询方式
3、区间查询
4、统计查询
5、统计查询
a.普通查询方式 : where
//--- 字符串查询 --- $arr=$m->where("sex=0 and username='机器'")->find(); //--- 数组查询 --- $data['sex']=0; $data['username']='奇迹'; $arr=$m->where($data)->find(); //注意:这种方式默认是and的关系,如果使用or关系,需要添加数组值 //--- 或OR 查询 --- $data['sex']=0; $data['username']='奇迹'; $data['_logic']='or'; $arr=$m->where($data)->find();
b.表达式查询:
$data['id']= ['lt',6]; $arr=$m->where($data)->select(); EQ 等于 NEQ不等于 GT 大于 EGT大于等于 LT 小于 ELT小于等于
LIKE 模糊查询 $data['username']=['like','%ge']; $arr=$m->where($data)->select();
NOTLIKE $data['username']=['notlike','%ge%']; //notlike中间没有空格 $arr=$m->where($data)->select(); 多个通配符查询,默认是or逻辑 $data['username']=array['like',['%ge%','%2%','%五%'],'and'];//如果没有第三个值,默认关系是or关系 $arr=$m->where($data)->select();
in : 包含
$data['id']=['in',[4,6,7]]; $arr=$m->where($data)->select(); //SELECT * FROM `tp_user` WHERE ( `id` IN (4,6,7) )
not in : 不包含 $data['id']=['not in',[4,6,7]]; $arr=$m->where($data)->select(); //SELECT * FROM `tp_user` WHERE ( `id` NOT IN (4,6,7) )
c.区间查询:
between : 在区间,包含开始位置 $data['id']=['between',[5,7]]; $arr=$m->where($data)->select(); //SELECT * FROM `tp_user` WHERE ( (`id` BETWEEN 5 AND 7 ) ) not between : 不在区间内,不包含开始位置 $data['id']=['not between',array[5,7]];//注意,not 和 between中间一定要有空格 $arr=$m->where($data)->select(); 逻辑区间:and $data['id']=[['gt',4],['lt',10]];//默认关系是 and 的关系 //SELECT * FROM `tp_user` WHERE ( (`id` > 4) AND (`id` < 10) ) 逻辑区间:or $data['id']=[['gt',4],['lt',10],'or'] //关系就是or的关系 复合查询区间 $data['name']=[['like','%2%'],['like','%五%'],'gege','or'];
d.统计查询
count //获取个数 max //获取最大数 min //获取最小数 avg //获取平均数 sum //获取总和
--- 例子 --- $arr = $m -> sum('id'); dump($arr);
e.SQL直接查询 :query 、execute
-- 生成一个空的M对象,使用query方法
$m=M(); $result=$m->query("select * from t_user where id >50"); dump($result);
-- execute 返回受影响的行数
· tp常量
__URL__ : 表示当前URL,在tp是到模块名,一般给后端接口使用 /thinkPHP_test/index.php/Index
__APP__ : 表示当前项目路径,一般给前端静态文件用 /thinkPHP_test/index.php
__PUBLIC__ : 当前项目路径的public文件夹 /thinkPHP_test/Public
· 常用的连贯操作
1.where 帮助我们设置查询条件 2.order 对结果进行排序 $arr=$m->order('id desc')->select(); $arr=$m->order[array['id'=>'desc','sex'=>'asc']]->select(); 3.limit 范围选取 limit(2,5) limit('2,5') limit(10)//limit(0,10) 4.field 设置查询字段 field('username as name,id') //返回时改名,该例子是把username改成name,但不是改数据库 field(['username'=>'name'],'id') //也是改名 field('id',true) //获取除了id以外的所有字段 5.table 6.group 7.having
· 模块之间的调用:
//在user模块调用index模块的方法 --- UserAction.class.php --- class UserAction extends Action { $index = new IndexAction(); //new 一个对象出来使用 $index.index(); } --- IndexAction.class.php --- class IndexAction extends Action { public function index(){ $m = M('User'); $this -> display(); } }
· tp的前置操作和后置操作:_before_方法名、_after_方法名
叙述:什么叫前置操作?就是当一个方法执行时会先执行前置操作,后置操作也是同理。前置操作举例个应用场景,比如,有些应用的操作需要在用户登陆后才能使用的。那就要在前置操作进行是否登陆的判断。看代码:
<?php class UserAction extends Action { public function _before_index(){ echo '我先执行<br>'; } public function index(){ echo "我是你要执行的方法<br>"; } public function _after_index(){ echo '我后执行<br>'; } } ?>
· URL 知识点
a.URL大小写:默认是区分大小写的,如想不区分大小写,在配置文件输入以下代码即可
URL_CASE_INSENSITIVE'=>true
b.伪静态:
http://serverName/User/3.html http://serverName/User/3.xhtml http://serverName/User/3.xml http://serverName/User/3.pdf 如果想限制伪静态的后缀名可以在config配置,如下 'URL_HTML_SUFFIX'=>'.shtml | .html | .pdf' 这只有以上定义的后缀才有效
c.路由规则
1、启动路由 要在配置文件中开启路由支持 2、使用路由 1.规则表达式配置路由 'my'=>'Index/index',//静态地址路由 ':id/:num'=>'Index/index',//动态地址路由 'year/:year/:month/:date'=>'Index/index',//动态和静态混合地址路由 'year/:year\d/:month\d/:date\d'=>'Index/index',//动态和静态混合地址路由 加上 \d代表类型只能是数字 'my/:id$'=>'Index/index',// 加上$说明地址中只能是 my/1000 后面不能有其他内容了 2.正则表达式配置路由 '/^year\/(\d{4})\/(\d{2})\/(\d{2})/'=>'Index/index?year=:1&month=:2&date=:3' 3、注意事项: 1.越复杂的路由越往前面放 'URL_ROUTE_RULES'=>array( 'my/:year/:month:/:day'=>'Index/day', 'my/:id\d'=>'Index/index', 'my/:name'=>'Index/index', ) 2.可以使用$作为完全匹配的路由规则 'URL_ROUTE_RULES'=>array( 'my/:id\d$'=>'Index/index', 'my/:name$'=>'Index/index', 'my/:year/:month:/:day$'=>'Index/day', ), 3.用正则匹配的方式 'URL_ROUTE_RULES'=>array( '/^my\/(\d+)$/'=>'Index/index?id=:1', '/^my\/(\w+)$/'=>'Index/index?name=:1', '/^my\/(\d{4})\/(\d{2})\/(\d{2})$/'=>'Index/day?year=:1&month=:2&day=:3', )
· 项目分组 :就是在同一个index入口下做分组,比如前台和后台