前端控制器模式

| 选择喜欢的代码风格  

前端控制器模式就是给你的 web 应用程序设置单一的入口(比如 index.php),用来集中处理所有请求的机制,目前大多数的PHP框架是这种形式。

它的职责是载入所有依赖,处理请求,并发送响应给浏览器。前端控制器模式对整个架构是有益的,因为它鼓励模块化代码,并给了你一个单入口,可以写一些每个请求都需要跑的代码(比如输入数据的过滤)。

PHP 前端控制器模式扩展阅读:


前端控制器:单一入口,定义了一个中心入口文件,每个请求都需要从这个入口进入系统,当然也可以在这里对用户的输入请求进行过滤。前端控制器处理请求后选择适当的命令(处理业务的)。在PHP中,这种模式每次都需要初始化,所以会导致性能的下降,但好处还是显而易见的。

前端控制器处理的是请求,那么我们就需要把用户的请求进行处理。

下面是唯一入口的 index.php 的代码示例,包含一个简单的路由功能:


<?php
class Demo
{
	private static $_instance;
	public static $classMap;
	public static $dirMap = array();

	public function __construct()
	{
		self::$classMap = array(
			'Component'=>'/core/Component.php',
			'controllers\Controller'=>'/core/Controller.php',
			'models\Model'=>'/core/Model.php',
		);
	}

	public static function run()
	{
		self::$_instance = new self;
		self::import('controllers');
		self::import('models');
	}

	public static function route()
	{
		$request_uri = $_SERVER['REQUEST_URI'];
		$route = preg_replace("/.*c.php\/?/",'',$request_uri);
		$route = preg_replace("/\?.*/",'',$route);
		$route = trim($route,'/');

		empty($route) && $route = 'site/index';
		$routeArr = explode('/',$route);
		$controllerName = '';
		$dir = 'controllers';

		for($i=0,$c=count($routeArr);$i<$c;$i++)
		{
			if(in_array($dir.'.'.$routeArr[$i], self::$dirMap)){
				$dir .= '.'.$routeArr[$i];
				continue;
			}
			$controllerName .= $dir.'.'.ucfirst($routeArr[$i]).'Controller';
			break;
		}
		$controllerName = preg_replace('/\./','\\',$controllerName);
		if($i+1 == $c){
			$actionId = 'index';
		}else{
			$actionId = $routeArr[$i+1];
		}
		$actionName = ucfirst($actionId);
		
		if(!class_exists($controllerName)){
			self::err_404();
		}
		$obj = new $controllerName();
		if(!method_exists($obj, $actionName)){
			self::err_404();
		}
		$obj->$actionName();
	}

	public static function import($dir)
	{
		$files = scandir(dirname(__DIR__).DIRECTORY_SEPARATOR.$dir);
		foreach($files as $v)
		{
			if($v=='.' || $v=='..')
				continue;
			if(is_dir($dir.'/'.$v)){
				$dotDir = preg_replace('/\//','.',$dir.'/'.$v);
				in_array($dotDir,self::$dirMap) || self::$dirMap[] = $dotDir;
				self::import($dir.'/'.$v);
				continue;
			}
			$classname = substr($v,0,strpos($v,'.php'));
			$classname =preg_replace('/\//','\\',$dir).'\\'.$classname; 
			self::$classMap[$classname] = '/'.$dir.'/'.$v;
		}
	}

	public static function appendClassmap($arr=array())
	{
		self::$classMap = array_merge(self::$classMap,$arr);
	}

	public static function isAjax()
	{
		return isset($_POST['ajax']);
	}

    public static function autoload($className)
    {
    	if(isset(static::$classMap[$className])){
    		$classFile = static::$classMap[$className];
    	}else{
    		$classFile = DIRECTORY_SEPARATOR.$className.'.php';
    	}

    	$classFile = dirname(__DIR__).$classFile;
    	if(!is_file($classFile)){
    		return;
    	}

    	include($classFile);
    }

	public static function err_404()
	{
		echo '404 Not Found!';

		die;
	}
}
//SPL注册自动加载
spl_autoload_register(['Demo', 'autoload'], true, true);

现在,只要在一个php文件中包含这个类文件,运行就可以了。

<?php
require 'core/Demo.php';
Demo::run();
Demo::route();//路由


发表评论