「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 ...
随机推荐
- 原生ajax详解
Ajxa局部刷新用于提高用户体验.Ajax技术的核心是XMLHttpRequest对象(简称XHR) XMLHttpRequest对象 XMLHttpRequest对象在ie7及更高版本可以这样申明. ...
- web CSS的知识- 关于后代选择器,子选择器,兄弟选择器的使用
1. 后代选择器官方解释:后代选择器可以选择作为某元素后代的元素.理解:选择某一标签的后代中,所有的此标签标记例:ul em {color:red;}就是选择,h1标签后代中中,所有的em.代码如下: ...
- apply()
apply() 1.apply和call的区别在哪里 2.什么情况下用apply,什么情况下用call 3.apply的其他巧妙用法(一般在什么情况下可以使用apply) apply:方法能劫持另外一 ...
- JavaWeb之JDBC
一.介绍 C#定义了ADO.Net接口来实现对SQLServer.Oracel等数据库的访问,那Java定义了JDBC接口实现对数据库的访问,数据库提供商只要实现这些接口,Java语言就能访问数据库. ...
- ubuntu如何进入local、bin目录
回到home目录,输入命令:cd /usr/local 若要进入bin目录,输入命令:cd /usr/local/bin
- 关于OOCSS的一点思考
关于面向对象,自己是很熟悉了,不能说代码实际开发效果有多好,但是这个概念确实经常见,那么到底什么是面向对象? 面向对象是一种对现实世界理解和抽象的方法,是计算机编程技术发展到一定阶段后的产物---百度 ...
- JavaScript 方法调用模式和函数调用模式
这两天在读<JavaScript语言精粹>关于第4章函数调用的几种模式琢磨了半天. 这里就说一下方法调用模式跟函数调用模式. 方法调用模式: 当一个函数被保存为对象的一个属性时,我们称它为 ...
- 大数据量场景下storm自定义分组与Hbase预分区完美结合大幅度节省内存空间
前言:在系统中向hbase中插入数据时,常常通过设置region的预分区来防止大数据量插入的热点问题,提高数据插入的效率,同时可以减少当数据猛增时由于Region split带来的资源消耗.大量的预分 ...
- 模拟jquery链式访问
一直写代码写代码,博客都快荒废了,眼看一月要过完,不能不留下点记忆,嘿嘿,刚研究了下jquery的链式访问,这么好用的技能我赶紧get了下,研究后略微修改,模拟一个简单的链式访问,下面这段代码支持修改 ...
- IOS开发创建开发证书及发布App应用(二)——创建证书
2. 创建证书 证书分为两种,一种是开发者证书,主要是用来真机调试的 另一种就是发布证书,就是用来发布应用的, 最好是两种都要下载,不然编译时候可能报错,我猜想可能苹果怕你没用真机调试 创建证书分为两 ...