现在PHP有很多的框架,基本都是以MVC为基础进行设计的。其实很多框架(像thinkphp,zf,symfont等)都有两个特性,自动加载类文件和统一入口。这里就简单实现以上两个特性。
假设PHP使用的版本在5.3以上,5.3以上支持命名空间
自动加载类文件:
我们做__autoload来实现,现在PHP官方是建议使用spl_autoload去实现,具体好处自己去google吧。这里还是简单的用__autoload去实现,来学习自动加载的原理。
目录结构:
inc.php:
<?php function __autoload($clsName){ $clsInfo = explode("\", $clsName); $len = count($clsInfo); $clsName = $clsInfo[$len - 1]; if($len == 1){ $clsInfo[$len - 1] = '/home/wwwroot/domain.com/library'; }else{ $pref = substr($clsName, 0, 3); $clsInfo[0] = '/home/wwwroot/domain.com/module/' . $clsInfo[0]; if($pref == 'ctl'){ $clsInfo[$len - 1] = 'control'; }elseif($pref = 'mdl'){ $clsInfo[$len - 1] = 'module'; }else{ $clsInfo[$len - 1] = 'library'; } } $clsFile = implode("/", $clsInfo) . "/" . $clsName . ".php"; $clsFile = realpath($clsFile); if($clsFile){ require_once($clsFile); }else{ exit("{$clsFile} is not exists!!"); } }
上面这个加载函数的应用实例:
require_once(inc.php); new libEntry();//加载/home/wwwroot/domain.com/libEntry.php new /libEntry(); //加载/home/wwwroot/domain.com/library/libEntry.php new /index/clsIndex(); //加载/home/wwwroot/domain.com/module/index/control/clsIndex.php new /index/mdlDb(); //加载/home/wwwroot/domain.com/module/index/module/mdlDb.php new /index/libUser(); //加载/home/wwwroot/domain.com/module/index/library/libUser.php
统一入口:
libRouter.php:
<?php class libRouter{ private $entry; private $control; private $method; function __construct(){ $url = $_GET['_URL_']; $urlInfo = explode('/', trim($url, '/')); $this->entry = $urlInfo[0]; $module = $urlInfo[1]; $params = explode('-', $module); $len = count($params); $this->control = $params[0]; if($len % 2 == 0){ $this->method = $params[1]; unset($params[1]); }else{ $this->method = ''; } unset($params[0]); $data = array_values($params); $len = count($data); for($i = 0; $i < $len; $i += 2){ $GLOBAL['_params'][$data[$i]] = $data[$i + 1]; } } public function route(){ $base = '/home/wwwroot/domain.com/module/'; $base .= $this->entry . '/'; if(!$this->entry || !is_dir($base)){ exit('Error entry!'); } !$this->control && $this->control = 'index'; !$this->method && $this->method = 'index'; $controlName = 'ctl' . ucfirst($this->control); $controlFile = "{$base}control/{$controlName}.php"; if(!is_file($controlFile)){ exit('Error control!!'); } require_once "{$controlFile}"; $control = new $controlName(); $methods = array($this->method, 'index'); $method = null; foreach($methods as $tmp){ $tmp = 'func' .ucfirst($tmp); if(method_exists($control, $tmp)){ $method = $tmp; break; } } if(empty($method)){ exit("Error method!!"); } $control->$method(); } }
实例应用:
index.php:
<?php require_once('inc.php'); $router = new libRouter(); $router->route();
module/index/control/ctlIndex.php:
<?php class ctlIndex{ function __construct() { //; } public function funcIndex(){ echo 'Hello World!'; } }
module/index/control/ctlUser.php
<?php class ctlUser{ function __construct() { //; } public function funcGetName(){ echo "My Name is Happy."; } }
配置nginx:
在nginx配置文件中,对应的域名配置下,加入下面的语句。
#访问的文件不存在是,统一由index.php处理。
if(!-f $request_filename){ rewrite ^(.*)$ /index.php?_URL_=$1 last; }
实例:
配置完上面的所有内容,我们接下来,访问看看:
其实上面两个链接分别被nginx处理为:
www.domain.com/index.php?_URL_=/index/user-getName
www.domain.com/index.php?_URL_=/index/index-index
总结:
以上就简单的完成了,统一入口和自动加载类的实现了。当然, 要应用到生产环境中,这样是远远不够的,至少还要加上对于类名的过滤,及没有提交类名和方法时的默认调用:
比如直接访问www.domain.com时,默认调用module/index/ctlIndex.php里的funcIndex方法。