继续框架之旅(ps:已经忘了上次写的时候的思路了...)。目前我们已经有了大概的物理目录了,先来写一个控制器吧,这个是用来控制网站运行方式的。这样说貌似不清楚...控制器主要就是分析uri路径,然后按照这个路来调用执行类,来达到控制网站运行的目的。
<?php
/**
*framework\models\controller.class.php
*/
class Controller {
public function __Construct() {
$request = $_SERVER['REQUEST_URI'];
$url = 'http://' . $_SERVER ['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
//判断url是否合法
if (! filter_var($url, FILTER_VALIDATE_URL,FILTER_FLAG_SCHEME_REQUIRED)){
//这里面是要做错误日志log记录的 本着简单原则 略…… 以后类似得同样略
$request = '/'; //不合法则使用根目录
}
$splits = explode('/', trim($request, '/')); // 用/分解uri
$tmp = explode('.', trim($splits[0], '.'));
$splits[0] = $tmp[0];
if(!empty($splits[1])){
$tmp = explode('.', trim($splits[1], '.'));
$splits[1] = $tmp[0];
}
$this->_Controller = !empty($splits[0]) ? $splits[0] : 'index'; //不存在的话默认index
$this->_Act
if(!empty($splits[2])) { //如果目录中存在更长的参数路径
$keys = $values = array();
for($idx=2, $cnt = count($splits); $idx<$cnt; $idx++) {
if($idx%2 == 0){
//Is even, is key
$keys[] = $splits[$idx];
} else {
//Is odd, is value
$values[] = $splits[$idx];
}
}
$this->_Params = array_combine($keys, $values);
//var_dump($this->_Params);
}
}
public function Route() {
$this->loadControllerClass();
if(!class_exists($this->GetController())) {
if ($this->GetController() == 'error') {
throw new Exception('Not Find error Class', E_USER_ERROR);
} else {
#类不存在 页面不存在 log 略……
$url = 'http://' . $_SERVER ['HTTP_HOST'] . '/error'; //假定网站已经完成了error的页面
header('Location:'.$url);
}
}
if ($rc = new ReflectionClass($this->GetController())) {
if($rc->implementsInterface('IController')) {
if(!$rc->HasMethod($this->GetAction())){
//重定向浏览器 到上一层 基类地址
$url = 'http://' . $_SERVER ['HTTP_HOST'] . '/' . $this->_Controller;
header('Location:' . $url);
//确保重定向后,后续代码不会被执行
/**
*@todo 如果这里使用了session则应该先关闭
*/
exit;
}
if($rc->HasMethod($this->GetAction())) {
$controller = $rc->NewInstance();
$method = $rc->GetMethod($this->GetAction());
$this->SetBody($method->Invoke($controller));
} else {
throw new Exception("Action");
}
} else {
throw new Exception("Interface");
}
} else {
throw new Exception("controller");
}
}
/**
*负责读取class文件,生成类定义
*@todo 这里是否存在随意调用用户提供名字的文件的漏洞
*/
public function LoadControllerClass() {
$classFile = './application/controllers/' . $this->_Controller .'.php';
//var_dump($classFile);
if (file_exists($classFile)){
include($classFile);
}else {
//error log 略…
if ($this->_Controller != 'error'){
$this->_Controller = 'error'; //重新定向到error类
$this->LoadControllerClass();
}
}
}
/**
* 获得执行类名
*@return string Class Name
*/
public function GetController() {
return $this->_Controller;
}
/**
*获得参数值
*@return string
*/
public function GetParams() {
return $this->_Params;
}
/**
*获得执行函数
*@return string Class Method
*/
public function GetAction() {
return $this->_Action;
}
/**
*获得网页内容
*@return string html body
*/
public function getBody() {
return $this->_Body;
}
public function setBody($body) {
$this->_Body = $body;
}
protected $_Controller; //控制类
protected $_Action; //执行方法
protected $_Params; //获得的url参数
protected $_Body; //输出体
}
控制器主要任务就是分析uri的路径名 并且拆分开了 然后分解成类名与执行函数名,这里做了一个小小的url验证,用到了php标准库的filter_var函数。
http://127.0.0.1/index/
将被分解为 $this->_Controller ='index'; $this->_Action = 'loadindex';
因为action不存在 则自动赋值loadindex这个初始值。
然后下面开始调用这个类,通过loadControllerClass 来include 目录为 application/controllers/下的同类名php文件( application/controllers/index.php)。然后开始调用这个类并执行。这里用到了php的反射机制 ,如果没研究过可以看看手册 。调用过程中程序还检查了这个类是否是 IController接口类。
IController接口很简单
interface IController{
public function loadindex();
}
保证类拥有loadindex 的接口函数。 保存controller.php
framework\models\controller.class.php
不知道个脚本能否正常运行,肯定要改改才行估计。我原来这个类写的是singleton模式,构造函数用的是private。不过想想没什么必要,反正自己用,这里顺手就改回来了..还有日志记录等等这些让我删掉不少,。主要是避免分散注意力。不过大致思路已经有了。另外关于这个反射,为什么非要用反射呢? 明天有空改成直接调用看看效果-_-;