我们为什么要使用路由?

原因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框架」第一天:路由与控制器的更多相关文章

  1. 「七天自制PHP框架」第一天:路由与控制器

    我们为什么要使用路由? 原因1:一个更漂亮的URI 1.URI的改进 刚刚开始学PHP时,我们一定写过blog.php?id=1之类的URI,使用GET方式获取参数.这样的URI有两个缺点,一是容易被 ...

  2. 「七天自制PHP框架」第二天:模型与数据库

    往期回顾:「七天自制PHP框架」第一天:路由与控制器,点击此处 什么是模型? 我们的WEB系统一定会和各种数据打交道,实际开发过程中,往往一个类对应了关系数据库的一张或多张数据表,这里就会出现两个问题 ...

  3. 「七天自制PHP框架」第三天:PHP实现的设计模式

    往期回顾:「七天自制PHP框架」第二天:模型与数据库,点击此处 原文地址:http://www.cnblogs.com/sweng/p/6624845.html,欢迎关注:编程老头 为什么要使用设计模 ...

  4. 「七天自制PHP框架」第四天:模型关联

    往期回顾:「七天自制PHP框架」第三天:PHP实现的设计模式,点击此处 原文地址:http://www.cnblogs.com/sweng/p/6624845.html,欢迎关注:编程老头 前阵子在网 ...

  5. 「七天自制PHP框架」应用:JSON生成器

    刚刚开始学做一个WebAPP,数据查询的一般套路是通过一张PHP页面读取数据库,获得列表后“嵌写”在PHP页面中,虽然写法上丑陋至极,但也有“快糙猛”出效果的成就感,如图. 后来想想,不对啊,难道以后 ...

  6. 「七天自制PHP框架」应用:Model外键链接

    这里以行政区数据为例: 一级行政区数据范例: 二级行政区范例: 三级行政区范例: 在Model层建立三个Model class ProvinceModel extends Model{ public ...

  7. Web自动化必会知识:「Web基础、元素定位、元素操作、Selenium运行原理、项目实战+框架」

    1.web 基础-html.dom 对象.js 基本语法 Dom 对象里面涉及元素定位以及对元素的修改.因为对元素操作当中涉及的一些 js 操作,js 基本语法要会用.得要掌握前端的基本用法.为什么要 ...

  8. 「CSP」第一届提高组考后总结

    「CSP」第一届提高组考后总结 问题分析+反思 成绩 心态 考前心态 考时心态 考后心态 方法 心灵鸡汤... 在学习了三年之后,我们信竞迎来了初中最后一次大考,也是第一次 CSPCSPCSP 考试. ...

  9. 「从零单排canal 07」 parser模块源码解析

    基于1.1.5-alpha版本,具体源码笔记可以参考我的github:https://github.com/saigu/JavaKnowledgeGraph/tree/master/code_read ...

随机推荐

  1. js数据类型:引用和5种基本数据类型

    javascript有2种基本数据类型:引用和基本数据类型 基本数据类型又有5个分类:布尔型.字符串.数值.undefined.NULL.

  2. Linux supervisord配置使用

    supervisor官方网站 http://supervisord.org 1.安装supervisord Ubuntu: $sudo apt-get install python-setuptool ...

  3. U-Boot 内核 (一)

    1.首先安装Vmware,安装Ubuntu 15.04 (安装时记住用户名和密码) 2.终端命令Ctrl+Alt+T 3.进行准备工作 安装工具 sudo apt-get update sudo ap ...

  4. C++数据

    const :常量 ~x == -++x == -(x+1)   二进制数,1变为0,0变为1 ^                               相同为0,不同为1 &      ...

  5. windows phone 8.1常用启动器实例

    ---恢复内容开始--- 小梦今天给大家分享一下windows phone 8.1常用启动器实例,包括: 电话启动器 短信启动器 邮件启动器 添加约会|备忘到日历 地图启动器 地图路线启动器 wind ...

  6. 常见端口、端口查询及TCP状态

    查看电脑端口的开放情况命令:cmd——netstat -a -n -a:显示所有连接和监听端口:-n:以数字形式显示地址和端口号 “本地地址”指本地IP地址及其正在使用的端口号,“外部地址”指连接某端 ...

  7. 受限玻尔兹曼机(RBM)原理总结

    在前面我们讲到了深度学习的两类神经网络模型的原理,第一类是前向的神经网络,即DNN和CNN.第二类是有反馈的神经网络,即RNN和LSTM.今天我们就总结下深度学习里的第三类神经网络模型:玻尔兹曼机.主 ...

  8. zabbix 监控 tomcat jmx

    zabbix_server: zabbix_server.conf : # Add JavaGateway=127.0.0.1 JavaGatewayPort=10052 StartJavaPolle ...

  9. VB中的GDI编程-1 设备环境DC

    p{ font-size: 15px; } .alexrootdiv>div{ background: #eeeeee; border: 1px solid #aaa; width: 99%; ...

  10. 老李推荐:第1章2节《MonkeyRunner源码剖析》概述:边界

    老李推荐:第1章2节<MonkeyRunner源码剖析>概述:边界   边界 怎么样才算分析清楚一个事物的原理是什么呢?就以前面提到的<LINUX内核源代码情景分析>为例子,分 ...