「7天自制PHP框架」第一天:路由与控制器
我们为什么要使用路由?
原因1:一个更漂亮的URI
1.URI的改进
刚刚开始学PHP时,我们一定写过blog.php?id=1之类的URI,使用GET方式获取参数。这样的URI有两个缺点,一是容易被SQL注射攻击,二是维护性可读性差,大家可以比较下面两种URI哪一种更具备可读性。
www.mysite.com/blog.php?id=1
上面URI是我们初学PHP最常用的。
www.mysite.com/blog/1
这种URI是目前最流行的URI,举个例子,比如很多读书类,电影类网站,都使用了这样的URI,这样的URI要比index.php?a=1&b=2&c=3&d=4....要简洁很多。
2.实现方法
在WEB项目的根目录下写一个.htaccess文件
RewriteEngine On
RewriteRule ^([a-zA-Z0-9/]*)$ index.php/$1
重写规则,让域名后面的字符串直接做为一个参数传入index.php,这样index.php就成为了你整个WEB应用的中心,定义了“请求和响应的映射”。
原因2:单一入口机制的易维护性
1.路由数组
一个PHP初学者,刚开始做项目,项目做着做着规模做大了,常常这个PHP页面给另一个PHP页面用GET方法传值,有时传的值还不止一个,时间一久,你的WEB项目,N个PHP页面宛如一个复杂的蜘蛛网,让你难以维护。一旦有修改,会涉及很多PHP文件,工作量很大。
MVC的单一入口机制可以解决维护难的问题,路由就是一套映射,可以让你一个URI对应一个方法。
$route=[
''=>'IndexController@Index',
'blog'=>'BlogController@Show',
'blog/{id}/{name}'=>'BlogController@Show',
];
2.获取参数
$path=$_SERVER['PATH_INFO'];
$path=ltrim($path,'/');
echo $path.PHP_EOL;
我们在浏览器里输入:www.mysite.com/blog/1后,path变量为/blog/1。使用ltrim函数删除左边的斜杠,然后使用explode把字符串拆解成数组。
$path_arr=explode('/', $path);
核心代码如下:
if(isset($_SERVER['PATH_INFO'])){
$path=$_SERVER['PATH_INFO'];
$path=ltrim($path,'/');
$path_arr=explode('/', $path);
} if(isset($path_arr[0])){
$key=$path_arr[0];
unset($path_arr[0]);
}
else{
$key='';
} if(isset($path_arr[1])){
$parameters=array_values($path_arr);
} if(isset($route[$key])){
$arr=explode('@', $route[$key]); $controller=new $arr[0];
$action=$arr[1]; if(isset($parameters)){
$controller->$action($parameters);
}
else{
$controller->$action();
}
}
else{
require 'error.html.php';
}
unset函数可以销毁数组中key和value,但是并不会重建索引,所以path_arr[0]是要调用的控制器类和方法名,path_arr[1]或者path_arr[1..N]就作为传入方法的参数。
重定向和错误页面是WEB系统中最常见的,如果不用路由机制,你可能要没完没了的重复写重定向或者错误页面的显示或者跳转代码,有了路由,只需要一句话就可以完成。
原因3:减少资源的消耗
MVC采用了控制器(controller)来响应请求(request),每次请求来时,应该在指定的一个PHP文件中初始化这个控制器,而不是分别在不同的PHP文件中做初始化工作,这样可以减少资源的消耗。
是不是一定要用控制器?
方案1:不用控制器
我们现在路由数组里添加一项,value不是一个字符串,而是一个匿名函数(Closure)
$route=[
''=>'Index',
'blog'=>'BlogController@Show',
'blog/{id}/{name}'=>'BlogController@Show',
'f'=>function(){echo 'hello';}
];
这里的route[f]是一个匿名函数,并不是一个控制器类的方法,所以,我们要把上一节路由代码做一下修改:
if(isset($route[$key])){
if($route[$key] instanceof Closure){
$route[$key]();
}
else{
$arr=explode('@', $route[$key]);
$controller=new $arr[0];
$action=$arr[1];
if(isset($parameters)){
$controller->$action($parameters);
}
else{
$controller->$action();
}
}
}
else{
require 'error.html.php';
}
方案2:使用控制器
每一次都require一个html页面是一件很不优雅的事情,所以我们写一个render函数
function render($path,array $args){
extract($args);
require($path);
}
接上一篇博客,我们知道每个URI对应了一个方法,但是我们常常遇到这样的问题:
<?php class Controller{
public function __call($method,$args){
echo 'has not this function'.$method;
}
} class IndexController extends Controller{
public function Index(){
echo __CLASS__;
for($i=1;$i<=20;++$i){
$data[$i]='content';
} render('template.html.php',['data'=>$data]);
}
} class BlogController extends Controller{
public function Show(){
echo __CLASS__;
for($i=1;$i<=10;++$i){
$data[$i]='blog';
}
render('template.html.php',['data'=>$data]);
}
} ?>
用不用控制器,取决于你的业务复杂度。个人建议使用控制器,但是对于业务很简单的页面跳转或检查,可以直接写在一个匿名函数里。
控制器里写些什么?
我们也许写过这样的代码:
class IndexController extends Controller{
public function Index($content){
return '<html><head></head><body>'.$content.'</body></html>';
}
}
这样把界面的代码嵌入的写法是非常难以维护的,也是很多开发人员(包括我)最厌恶的写法,因为这种写法并没有做好界面与业务逻辑的分离,所以我们需要使用视图。
<html>
<head> </head> <body>
<?php foreach($data as $key=>$value){ ?>
<div>
<?php echo $key.':'.$value; ?>
</div>
<?php } ?>
</body>
</html>
每一次调用控制器的某个方法时,render函数都会把参数以关联数组的形式传入,做到“业务逻辑”和“表现”的浅层次分离,但是这种分离还不是最好的,因为前端开发人员仍然需要面对甚至处理PHP代码,后端开发人员也有和前端人员沟通的成本,所以后面某一节,会再谈一种更好的分离方式。
「7天自制PHP框架」第一天:路由与控制器的更多相关文章
- 「七天自制PHP框架」第一天:路由与控制器
我们为什么要使用路由? 原因1:一个更漂亮的URI 1.URI的改进 刚刚开始学PHP时,我们一定写过blog.php?id=1之类的URI,使用GET方式获取参数.这样的URI有两个缺点,一是容易被 ...
- 「七天自制PHP框架」第二天:模型与数据库
往期回顾:「七天自制PHP框架」第一天:路由与控制器,点击此处 什么是模型? 我们的WEB系统一定会和各种数据打交道,实际开发过程中,往往一个类对应了关系数据库的一张或多张数据表,这里就会出现两个问题 ...
- 「七天自制PHP框架」第三天:PHP实现的设计模式
往期回顾:「七天自制PHP框架」第二天:模型与数据库,点击此处 原文地址:http://www.cnblogs.com/sweng/p/6624845.html,欢迎关注:编程老头 为什么要使用设计模 ...
- 「七天自制PHP框架」第四天:模型关联
往期回顾:「七天自制PHP框架」第三天:PHP实现的设计模式,点击此处 原文地址:http://www.cnblogs.com/sweng/p/6624845.html,欢迎关注:编程老头 前阵子在网 ...
- 「七天自制PHP框架」应用:JSON生成器
刚刚开始学做一个WebAPP,数据查询的一般套路是通过一张PHP页面读取数据库,获得列表后“嵌写”在PHP页面中,虽然写法上丑陋至极,但也有“快糙猛”出效果的成就感,如图. 后来想想,不对啊,难道以后 ...
- 「七天自制PHP框架」应用:Model外键链接
这里以行政区数据为例: 一级行政区数据范例: 二级行政区范例: 三级行政区范例: 在Model层建立三个Model class ProvinceModel extends Model{ public ...
- Web自动化必会知识:「Web基础、元素定位、元素操作、Selenium运行原理、项目实战+框架」
1.web 基础-html.dom 对象.js 基本语法 Dom 对象里面涉及元素定位以及对元素的修改.因为对元素操作当中涉及的一些 js 操作,js 基本语法要会用.得要掌握前端的基本用法.为什么要 ...
- 「CSP」第一届提高组考后总结
「CSP」第一届提高组考后总结 问题分析+反思 成绩 心态 考前心态 考时心态 考后心态 方法 心灵鸡汤... 在学习了三年之后,我们信竞迎来了初中最后一次大考,也是第一次 CSPCSPCSP 考试. ...
- 「从零单排canal 07」 parser模块源码解析
基于1.1.5-alpha版本,具体源码笔记可以参考我的github:https://github.com/saigu/JavaKnowledgeGraph/tree/master/code_read ...
随机推荐
- JavaWeb之Servlet总结
今天上班居然迟到了,昨天失眠了,看完吐槽大会实在不知道做些什么,刚好朋友给我发了两个JavaWeb的练习项目,自己就又研究了下,三四点才睡,可能周日白天睡的太多了,早上醒来已经九点多了,立马刷牙洗脸头 ...
- 会话控制之session和cookie(20161107)
注:除了登录页面,每个页面,包括处理页面也要加,为了提高安全性 session尽量不用,因为很占内存 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML ...
- 队列工厂之RedisMQ
本次和大家分享的是RedisMQ队列的用法,前两篇文章队列工厂之(MSMQ)和队列工厂之RabbitMQ分别简单介绍对应队列环境的搭建和常用方法的使用,加上本篇分享的RedisMQ那么就完成了咋们队列 ...
- DapperPoco -- 基于Dapper的、轻量级的、高性能的、简单的、灵活的ORM框架
为什么要重复造轮子 因为现有的轮子都在某些方面不太令我满意,下面我来一一点评一下,欢迎拍砖. Entity Framework 我喜欢傻瓜化使用方式的框架,同时又不失灵活性. EF虽然使用起来足够简单 ...
- 关于Tarjan(2)
Tarjan有第二个神奇的用法,求强连通分量!!!!!!!!!!!!!!!!!!! 同样利用了dfn:dfs序,low:能回到的最早祖先的dfn: 废话少说 上板子 #include<iostr ...
- 解决Chrome动画”卡顿”的办法
为动画DOM元素添加CSS3样式-webkit-transform:transition3d(0,0,0)或-webkit-transform:translateZ(0);,这两个属性都会开启GPU硬 ...
- python全栈开发第10天-正则表达式
正则表达式 正则表达式,又称规则表达式.(英语:Regular Expression,在代码中常简写为regex.regexp或RE),计算机科学的一个概念.正则表通常被用来检索.替换那些符合某个模式 ...
- 给angularJs grid列上添加自定义按钮
由于项目需要在angular 显示的表格中添加按钮,多次查询资料终于找到解决方法.就是给columnDefs 上的列增加 cellTemplate,同时绑定对应的触发事件,代码如下 columnDef ...
- winow7安装django 1.9.1
1.下载django https://www.djangoproject.com/download/ 2.解压,并到该目录下 执行 python setup.py install 3.验证是否安装成功 ...
- 为什么你应该抛弃Express的视图渲染引擎
Nodejs Express框架的一个被人们广为使用的特性是它的渲染引擎.Express视图渲染引擎允许Controller提供一个视图名称和视图模型对象给Express,然后返回由HTTP响应流输出 ...