这两天看了看慕课网的 《从零打造自己的MVC矿建》 感觉很有收获
做点总结
首先是框架运行原理:
一个框架 进入入口文件后 首先它会定义一些常量 ,然后加载核心类库,启动框架
接下来路由类会根据一定的规则去解析用户输入的路由 找到对应的控制器 把控制器加载进来 去调用模型 把结果响应到视图
那么入口文件是干什么的呢
<?php
/**
* 1.入口文件
* 2.定义常量
* 3.加载函数库
* 4.启动框架
*/
header("content-type:text/html;charset=utf-8");
define('IMOOC', realpath(''));
define('CORE', IMOOC.'/core');
define('APP', IMOOC.'/application');
define('MODULE', 'application');
define('DEBUG', true);
if (DEBUG) {
ini_set('display_error', 'On');
}else{
ini_set('display_error', 'Off');
}
include CORE.'/common/function.php';
include CORE.'/imooc.php';
spl_autoload_register('\core\imooc::load');
\core\imooc::run();
通过上面代码我们看到: 入口文件 一般来说
首先会定义一些框架中需要用到的常量 :例如文件夹路径 、系统设计模式等等
接下来 会加载核心类库
最后去运行核心类库中运行框架的方法
说到加载类库 就不得不提到自动加载了 这是一个框架的灵魂
他需要用到一个函数
spl_autoload_register('\core\imooc::load');
在了解这个函数之前先来看另一个函数:__autoload。
一、__autoload
这是一个自动加载函数,在PHP5中,当我们实例化一个未定义的类时,就会触发此函数。看下面例子:
printit.class.php
<?php
class PRINTIT {
function doPrint() {
echo 'hello world';
}
}
?>
index.php
<?
function __autoload( $class ) {
$file = $class . '.class.php';
if ( is_file($file) ) {
require_once($file);
}
}
$obj = new PRINTIT();
$obj->doPrint();
?>
运行index.PHP后正常输出hello world。在index.php中,由于没有包含printit.class.php,在实例化printit时,自动调用__autoload函数,参数$class的值即为类名printit,此时printit.class.php就被引进来了。
在面向对象中这种方法经常使用,可以避免书写过多的引用文件,同时也使整个系统更加灵活。
二、spl_autoload_register()
再看spl_autoload_register(),这个函数与__autoload有与曲同工之妙,看个简单的例子:
<?
function loadprint( $class ) {
$file = $class . '.class.php';
if (is_file($file)) {
require_once($file);
}
}
spl_autoload_register( 'loadprint' );
$obj = new PRINTIT();
$obj->doPrint();
?>
将__autoload换成loadprint函数。但是loadprint不会像__autoload自动触发,这时spl_autoload_register()就起作用了,它告诉PHP碰到没有定义的类就执行loadprint()。
spl_autoload_register() 调用静态方法
<?
class test {
public static function loadprint( $class ) {
$file = $class . '.class.php';
if (is_file($file)) {
require_once($file);
}
}
}
spl_autoload_register( array('test','loadprint') );
//另一种写法:spl_autoload_register( "test::loadprint" );
$obj = new PRINTIT();
$obj->doPrint();
?>
是不是很神奇
那么看看我的 \core\imooc::load 到底干了些什么
public static $classMap = array();
public static function load($class)
{
//自动加载类库
//检测类是否已经被加载
if(isset($classMap[$class])) {
return true;
} else {
$class = str_replace('\\', '/', $class);
$file = IMOOC.'/'.$class.'.php';
if(is_file($file)) {
include $file;
self::$classMap[$class] = $class;
} else {
return false;
}
}
}
为了考虑性能 首先检测了类库是不是已经加载过了
如果没有加载过
那么 include 类库
是不是也很简单
接下来我们该分配路由了
我的是LAMP环境
apache路由规则重写模块已经加载过了
直接在项目根目录 新建一个 .htaccess文件
<IfModule mod_rewrite.c>
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ index.php/$1 [QSA,PT,L]
</IfModule>
这样我们用户的所有请求都会重定向加上index.php
用户输入的url是这样的:
www.imooc.com/index/index
实际访问的页面是这样的
www.imooc.com/index.php/index/index
然后我们的路由要干几件事
1.隐藏index.php
2.获取url 参数部分
3.返回对应的控制器和方法
4.将多余的参数转化为$_GET 参数
第一步我们在上面已经做完了
接下类我们完成下面的几步
<?php
namespace core\lib;
class route
{
public $controller;
public $action;
public function __construct()
{
// xxx.com/index/index
/**
* 1.隐藏index.php
* 2.获取url 参数部分
* 3.返回对应的控制器和方法
*/
if(isset($_SERVER['REQUEST_URI']) && $_SERVER['REQUEST_URI'] != '/')
{
$path = $_SERVER['REQUEST_URI'];
$patharr = explode('/', trim($path, '/'));
if(isset($patharr[0])){
$this->controller = $patharr[0];
unset($patharr[0]);
}
if(isset($patharr[1])){
$this->action = $patharr[1];
unset($patharr[1]);
}else{
$this->action = 'index';
}
//url多余部分转化为GET参数
//a/1/b/2/c/3
$count = count($patharr) + 2;
$i = 2;
while ($i < $count) {
if(isset($patharr[$i + 1]))
{
$_GET[$patharr[$i]] = $patharr[$i + 1];
}
$i += 2 ;
}
}
else
{
$this->controller = 'index';
$this->action = 'index';
}
}
}
这样我们就在用户输入url的时候将用户第一个斜杠之后的参数存到 controller中第二个参数存到 action 中
我们的路由就弄好了!