一个简单的PHP Route

一个简单的PHP Route · Nov 6, 2013 clicks

写了一个简单的PHP Route玩玩。

只有寥寥数行,实现最简单的功能

class Route{
	public static $rules = [];
	public static function addRule($uri,$rule,$defaults=[])
	{
		self::$rules[] = ['regex'=> self::compileRule($uri,$rule) , 'defaults'=>$defaults ];
	}
	public static function compileRule($uri,$rule)
	{
		$uri = str_replace(')', ')?', $uri);
		return  preg_replace_callback(
			"#<([^<>/\?]+)>#i", 
			function ($matches) use ($rule){
				$name = $matches[1];
				return "(?P<{$name}>" . ( !empty($rule[$name]) ? $rule[$name] : '[^<>/]+') . ')';
			},
			$uri
		);
		
	}
	public static function parseUri($uri){
		foreach (self::$rules as $rule_setting) {
			if ( preg_match("#{$rule_setting['regex']}#i", $uri, $matches) ){
				$ret = $rule_setting['defaults'];
				foreach ($matches as $name => $value) {
					$ret[$name] = $value;
				}
				return $ret;
			}
		}
		return NULL;
	}
}

一开始,第10行用的preg_match函数,而在后面的正则了用了/e修饰符, 在这种情况下,preg_match的第二个参数可以是一行php代码。

然而在PHP 5中,已经去掉了/e修饰符,所以只能用preg_match_callback函数了,再配合匿名函数,比以前用着更爽了。

 

下面是使用示例:

//example
Route::addRule(
	'<controller>/<action>(/<param>)',
	['controller'=>'[a-z]+','action'=>'[a-z]+'],
	['controller'=>'home','action'=>'index']
);
Route::addRule(
	'a_<param>.html',
	['param'=>'[0-9]+'],
	['controller'=>'article','action'=>'detail']
);
print_r(Route::parseUri('a_1234.html'));
print_r(Route::parseUri('find/me'));
print_r(Route::parseUri('find/somebody/tom'));

 

最后的输出结果:

Array
(
    [controller] => article
    [action] => detail
    [0] => a_1234.html
    [param] => 1234
    [1] => 1234
)
Array
(
    [controller] => find
    [action] => me
    [0] => find/me
    [1] => find
    [2] => me
)
Array
(
    [controller] => find
    [action] => somebody
    [0] => find/somebody/tom
    [1] => find
    [2] => somebody
    [3] => /tom
    [param] => tom
    [4] => tom
)
PHP