以前讲了这么多,实际上都只是为框架搭建了一个架子而已,框架里面尚未什么东西, 从今天开始,我就开始从Controller,Model,View这几块儿来分别介绍一下。 php
PS:以前的不少内容我都没有细讲,就好比路由,真正的框架路由确定不是经过GET方式指定的,而是正则,而且它须要兼容多个Server,多种方式。 数组
咱们知道全部的请求都须要通过控制器,因此首先仍是说一下控制器。 服务器
咱们以前已经 说过控制器的概念了,可是这个控制器仍是功能太弱了,由于它只是从功能上是控制器,框架并无为它作任何事情,框架实际上能够实现一些经常使用的功能,而后用户定义的控制器继承它,这样用户能够少写不少代码的。 框架
以前的控制器是: 函数
<?php class IndexController { public function index() { echo 'Hello world'; } }如今假设框架已经实现了控制器的一些基本功能,这个类咱们称为Controller.php,那么如今代码就变成了:
<?php class IndexController extends Controller { public function index() { echo 'Hello world'; } }这样作有什么好处呢,因为Controller继承了Base,因此IndexController也拥有了Base的功能,这样就不须要用户再编写不少捕获的代码等。
固然,这样作也有缺点,测试IndexController的时候比较麻烦。 测试
今天我先说一下控制器比较基础的两个功能,跳转和转发。 ui
首先是跳转,这个用的太广泛了,好比用户登陆的时候,点击登陆按钮,进入后台处理的页面,处理完毕以后就须要跳转,那么怎么实现跳转呢? this
有几种方式: url
第一种:<script>location.href = "XXXX";</script>在JS中实现跳转; code
第二种:header("Location:url");具体使用可查看PHP手册;
第三种:在HTML的meta中设置refresh;
因为header调用的时候若是以前页面已经有输出,跳转会失效,因此须要结合meta的refresh一块儿使用,固然,你也能够直接使用JS的这种方式来实现,只是我不太喜欢这种方式,由于我以前使用这种方式实现跳转的时候出过问题。
如今咱们定义跳转这个函数的名字为_redirect,为何前面加上_呢,这也是个人一个习惯,对于函数,只要不是public,我都使用_做为前缀。可能你们会问了,为何不设置这个函数为public呢,由于用户编写的控制器也只会继承它而不会直接调用,因此我设置成为了protected。
protected function _redirect(Array $arr) { }
暂时能够将功能弄得弱一点,假设跳转的参数经过数组传递过来,那么咱们可使用类型提示(Array $arr)这种方式来搞定,若是传递的参数不是数组,那么直接会报错。
咱们使用的方式能够是这样:
$this->_redirect(array( 'action' => 'test', 'controller' => 'Test', 'param1' => '1' ));它表明的意思是跳转到Test这个控制器的test这个Action,而且还传递了一个参数,这个参数名为param1,值为1。
protected function _redirect(Array $arr) { $controller = empty($_GET['c']) ? C('defaultController') : trim($_GET['c']); //设置了默认的控制器 $action = empty($_GET['a']) ? C('defaultAction') : trim($_GET['a']); //设置了默认的Action array_key_exists('controller',$arr) || $arr['controller'] = $controller; array_key_exists('action',$arr) || $arr['action'] = $action; $str = '/?'; foreach($arr as $key => $val) { if(!is_int($key)) { $str .= ($key . '=' . $val . '&'); } } $str = substr($str,0,strlen($str) - 1); Response::redirect($str); }
这个就是我刚刚手写的跳转代码,实际上就是把传递的数组拼接一下而后组成一个字符串,这个字符串就能够当作是一个URL,因为如今没有对Route.php进行更多的处理,对于localhost/demo2/index.php?controller=a这种URL它跳转就会出错,暂时只支持localhost/index.php?controller=a这种URL,还有$controller和$action的获取和Route.php中的代码重复了,这些都须要在后面真正实现路由的时候再讲解,暂时就这么看看吧,虽然我本身都感受这样的代码很恶心。
可能你们都注意到了,当这个函数拼接到URL以后,是直接调用了Response的redirect方法,这是为何呢?
第一:有可能在真正应用中,咱们直接在控制器中调用$this->_redirect知足不了咱们的需求,这个时候咱们就须要直接调用Response::redirect,好比跳转到百度首页就只能调用Response::redirect("http://www.baidu.com");
第二:从逻辑上,跳转是一个服务器对客户端的响应,因此须要写在Response中,具体的可参照Java。
那么咱们又必须新建一个Response.php这样一个文件:
<?php class Response extends Base { public static function redirect($url) { if(is_string($url)) { if(!headers_sent()) { header("Location:" . $url); exit(); } else { $str = '<meta http-equiv="Refresh" contect="0;url='.$url.'">'; exit($str); } } else { //错误处理 } } }这里的逻辑比较简单,实际上就是断定是否有输出,没有输出那么就直接使用header("Location")进行跳转,若是有输出,那么使用meta的refresh跳转。
注意:实际上还能够在这个跳转上开发更多的功能,可是因为我只是大概讲一下,因此更多的内容就不写了,有兴趣的人能够去Toper上面看看。
这样,一个比较简单的跳转就完成了,那么怎么实现转发呢?
能够简单这样理解,转发实际上就是再调用了一下某一个Controller的某一个Action。
因此这样咱们就能够比较简单的实现转发了:
protected function _forward(Array $arr) { $controller = empty($_GET['c']) ? C('defaultController') : trim($_GET['c']); //设置了默认的控制器 $action = empty($_GET['a']) ? C('defaultAction') : trim($_GET['a']); //设置了默认的Action if(array_key_exists('controller',$arr)) { $controller = $arr['controller']; } if(array_key_exists('action',$arr)) { $action = $arr['action']; } $controller .= 'Controller'; if($controller === get_class()) { if(method_exists($this,$action)) { $this->$action(); } else { //时间有限,不写逻辑了 } } else { if(class_exists($controller)) { $class = new $controller(); if(method_exists($class,$action)) { $class->$action(); } else { //时间有限,不写了 } } else { //时间有限,不写了 } } }实际上逻辑上就是断定一下要调用的Action是否属于本控制器,若是是本控制器,直接调用$this->$action()便可,不然,须要实例化这个控制器,即$class = new $controller(),而后再调用这个Action。
原本觉得半个小时就能够写完,结果写了一个小时了,因为时间超出个人预算,因此代码都是手写的,不知道有不有什么语法错误什么的,反正看看思路就OK了。
代码点此下载