设为首页 收藏本站
查看: 1239|回复: 0

[经验分享] 「七天自制PHP框架」第一天:路由与控制器

[复制链接]

尚未签到

发表于 2017-12-31 06:11:41 | 显示全部楼层 |阅读模式
我们为什么要使用路由?

原因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:使用控制器
DSC0000.png

  每一次都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代码,后端开发人员也有和前端人员沟通的成本,所以后面某一节,会再谈一种更好的分离方式。

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-430171-1-1.html 上篇帖子: visual studio code(vscode) 调试php(转) 下篇帖子: PHP的性能演进(从PHP5.0到PHP7.1的性能全评测)
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表