模块

Route

路由用来根据请求的 URI 确定控制器与动作。 每个路由生成一个用于匹配 URI 和路由的正则表达式。 路由也可能包含用于设置控制器、动作和参数的键。

每个 <键> 将使用默认正则表达式模式转换成正则表达式。您可以为该键提供模式,以覆盖默认模式:

// 这个路由将只匹配 <id> 为数字
Route::set('user', 'user/<action>/<id>', array('id' => '\d+'));

// 这个路由将匹配 <path> 为任何东西
Route::set('file', '<path>', array('path' => '.*'));

另外,也可以在 URI 定义中使用括号,来创建可选的部分:

// 这是一个标准的默认路由,而且没有必需的键
Route::set('default', '(<controller>(/<action>(/<id>)))');

// 这个路由只需要 <file> 键
Route::set('file', '(<path>/)<file>(.<format>)', array('path' => '.*', 'format' => '\w+'));

路由还提供了一种方法来生成 URI(称为“反向路由”),这使得它们能够以非常强大且灵活的方式来生成内部链接。

package
BootPHP
category
Base
author
Tinsh
copyright
© 2005-2016 Kilofox Studio

该类在 SYSPATH/classes/route.php 第 33 行声明。

常量

REGEX_KEY

string(18) "<([a-zA-Z0-9_]++)>"

REGEX_SEGMENT

string(12) "[^/.,;?\n]++"

REGEX_ESCAPE

string(17) "[.\+*?[^\]${}=!|]"

属性

public static bool $cache

是否缓存路由

bool false

public static string $default_action

所有路由的默认动作

string(5) "index"

public static string $default_protocol

所有路由的默认协议

string(7) "http://"

public static array $localhosts

有效的本地主机条目列表

array(4) (
	0 => bool false
	1 => string(0) ""
	2 => string(5) "local"
	3 => string(9) "localhost"
)

protected callback $_callback

路由的回调方法

protected array $_defaults

protected array $_regex

protected string $_route_regex

protected static array $_routes

array(5) (
	"docs/media" => object Route(5) {
		protected _callback => NULL
		protected _uri => string(20) "guide/media(/<file>)"
		protected _regex => array(1) (
			"file" => string(2) ".+"
		)
		protected _defaults => array(3) (
			"controller" => string(9) "userguide"
			"action" => string(5) "media"
			"file" => NULL
		)
		protected _route_regex => string(35) "#^guide/media(?:/(?P<file>.+))?$#uD"
	}
	"docs/api" => object Route(5) {
		protected _callback => NULL
		protected _uri => string(19) "guide/api(/<class>)"
		protected _regex => array(1) (
			"class" => string(13) "[a-zA-Z0-9_]+"
		)
		protected _defaults => array(3) (
			"controller" => string(9) "userguide"
			"action" => string(3) "api"
			"class" => NULL
		)
		protected _route_regex => string(45) "#^guide/api(?:/(?P<class>[a-zA-Z0-9_]+))?$#uD"
	}
	"docs/guide" => object Route(5) {
		protected _callback => NULL
		protected _uri => string(25) "guide(/<module>(/<page>))"
		protected _regex => array(1) (
			"page" => string(2) ".+"
		)
		protected _defaults => array(3) (
			"controller" => string(9) "userguide"
			"action" => string(4) "docs"
			"module" => string(0) ""
		)
		protected _route_regex => string(59) "#^guide(?:/(?P<module>[^/.,;?\n]++)(?:/(?P<page>.+))?)?$#uD"
	}
	"default" => object Route(5) {
		protected _callback => NULL
		protected _uri => string(32) "(<controller>(/<action>(/<id>)))"
		protected _regex => array(1) (
			"controller" => string(83) "(manage|manage2|manage3|homepage|member|findpwd|product|cart|order|pay|forum|guide)"
		)
		protected _defaults => array(2) (
			"controller" => string(8) "homepage"
			"action" => string(5) "index"
		)
		protected _route_regex => string(166) "#^(?:(?P<controller>(manage|manage2|manage3|homepage|member|findpwd|product|cart|order|pay|forum|guide))(?:/(?P<action>[^/.,;?\n]++)(?:/(?P<id>[^/.,;?\n]++))?)?)?$#uD"
	}
	"page" => object Route(5) {
		protected _callback => NULL
		protected _uri => string(17) "(<id>(/<action>))"
		protected _regex => array(0) 
		protected _defaults => array(2) (
			"controller" => string(4) "page"
			"action" => string(5) "index"
		)
		protected _route_regex => string(61) "#^(?:(?P<id>[^/.,;?\n]++)(?:/(?P<action>[^/.,;?\n]++))?)?$#uD"
	}
)

protected string $_uri

路由 URI

方法

public __construct( [ mixed $uri = NULL , array $regex = NULL ] ) (在 Route 中定义)

创建一个新的路由。为键设置 URI 和正则表达式。 路由应该始终由 Route::set 来创建,否则它们将无法正确保存。

$route = new Route($uri, $regex);

参数 $uri 可以是基本的正则匹配的字符串,也可以是一个有效的回调或匿名函数(php 5.3+)。 如果使用回调或匿名函数,您的方法应该返回一个包含正确的路由键的数组。 如果希望路由“可逆”,您需要传递路由字符串作为第三个参数。

$route = new Route(function($uri)
{
    if ( list($controller, $action, $param) = explode('/', $uri) && $controller == 'foo' && $action == 'bar' )
    {
        return array(
            'controller' => 'foobar',
            'action' => $action,
            'id' => $param,
        );
    },
    'foo/bar/<id>'
});

参数

  • mixed $uri = NULL - 路由 URI 模式或 lamba/回调函数
  • array $regex = NULL - 键模式

Tags

返回值

  • void

源代码

public function __construct($uri = NULL, $regex = NULL)
{
	if ($uri === NULL)
	{
		// 假设路由来自缓存
		return;
	}
	if (!is_string($uri) && is_callable($uri))
	{
		$this->_callback = $uri;
		$this->_uri = $regex;
		$regex = NULL;
	}
	else if (!empty($uri))
	{
		$this->_uri = $uri;
	}
	if (!empty($regex))
	{
		$this->_regex = $regex;
	}
	// 保存编译了的正则
	$this->_route_regex = Route::compile($uri, $regex);
}

public static all( ) (在 Route 中定义)

检索所有命名的路由。

$routes = Route::all();

返回值

  • array - 路由名称

源代码

public static function all()
{
	return Route::$_routes;
}

public static cache( [ boolean $save = bool false ] ) (在 Route 中定义)

保存或者加载路由缓存。如果您的路由长时间保持不变,用它来重新加载缓存中的路由,而不是在加载每个页面时重新定义它们。

if ( !Route::cache() ) Route::cache(true);

参数

  • boolean $save = bool false - 缓存当前路由

Tags

返回值

  • void - 保存路由时
  • boolean - 加载路由时

源代码

public static function cache($save = false)
{
	if ($save === true)
	{
		// 缓存所有定义的路由
		BootPHP::cache('Route::cache()', Route::$_routes);
	}
	else
	{
		if ($routes = BootPHP::cache('Route::cache()'))
		{
			Route::$_routes = $routes;
			// 路由已缓存
			return Route::$cache = true;
		}
		else
		{
			// 路由未缓存
			return Route::$cache = false;
		}
	}
}

public static compile( ) (在 Route 中定义)

返回编译的路由正则表达式。将键和可选的组翻译成正确的 PCRE 正则表达式。

$compiled = Route::compile(
    '<controller>(/<action>(/<id>))',
    array(
        'controller' => '[a-z]+',
        'id' => '\d+',
    )
);

Tags

返回值

  • string

源代码

public static function compile($uri, array $regex = NULL)
{
	if (!is_string($uri))
		return;
	// 转义除 ( ) < > 以外的所有 preg_quote 将要转义的东西
	$expression = preg_replace('#' . Route::REGEX_ESCAPE . '#', '\\\\$0', $uri);
	if (strpos($expression, '(') !== false)
	{
		// 使 URI 中的可选部分不被捕捉并且是可选的。
		$expression = str_replace(array('(', ')'), array('(?:', ')?'), $expression);
	}
	// 为键插入默认正则
	$expression = str_replace(array('<', '>'), array('(?P<', '>' . Route::REGEX_SEGMENT . ')'), $expression);
	if ($regex)
	{
		$search = $replace = array();
		foreach ($regex as $key => $value)
		{
			$search[] = "<$key>" . Route::REGEX_SEGMENT;
			$replace[] = "<$key>$value";
		}
		// 用用户规定的正则替换默认正则
		$expression = str_replace($search, $replace, $expression);
	}
	return '#^' . $expression . '$#uD';
}

public defaults( [ array $defaults = NULL ] ) (在 Route 中定义)

当键不存在时,为它们提供默认值。默认动作将总是“index”,除非它在这里重载。

$route->defaults(array(
    'controller'    => 'welcome',
    'action'        => 'index'
));

如果没有传递参数,该方法将充当 getter。

参数

  • array $defaults = NULL - 键值

返回值

  • $this - 或数组

源代码

public function defaults(array $defaults = NULL)
{
	if ($defaults === NULL)
	{
		return $this->_defaults;
	}
	$this->_defaults = $defaults;
	return $this;
}

public static get( string $name ) (在 Route 中定义)

检索一个命名的路由。

$route = Route::get('default');

参数

  • string $name required - 路由名

Tags

返回值

  • Route

源代码

public static function get($name)
{
	if (!isset(Route::$_routes[$name]))
	{
		throw new BootPHP_Exception('The requested route does not exist: :route', array(':route' => $name));
	}
	return Route::$_routes[$name];
}

public is_external( ) (在 Route 中定义)

该路由是否为远程控制器的外部路由。

返回值

  • boolean

源代码

public function is_external()
{
	return !in_array(Arr::get($this->_defaults, 'host', false), Route::$localhosts);
}

public matches( string $uri ) (在 Route 中定义)

测试路由是否匹配所给 URI。匹配成功则返回所有路由参数的数组。匹配失败则返回布尔值 false。

// 参数: controller = users, action = edit, id = 10
$params = $route->matches('users/edit/10');

这个方法应该总是在一个 if/else 块中使用:

if ( $params = $route->matches($uri) )
{
    // 解析参数
}

参数

  • string $uri required - 要匹配的 URI

返回值

  • array - 如果成功
  • false - 如果失败

源代码

public function matches($uri)
{
	if ($this->_callback)
	{
		$closure = $this->_callback;
		$params = call_user_func($closure, $uri);
		if (!is_array($params))
			return false;
	}
	else
	{
		if (!preg_match($this->_route_regex, $uri, $matches))
			return false;
		$params = array();
		foreach ($matches as $key => $value)
		{
			if (is_int($key))
			{
				// 路过所有未命名的键
				continue;
			}
			// 为所有匹配的键赋值
			$params[$key] = $value;
		}
	}
	foreach ($this->_defaults as $key => $value)
	{
		if (!isset($params[$key]) || $params[$key] === '')
		{
			// 为不匹配的键赋默认值
			$params[$key] = $value;
		}
	}
	return $params;
}

public static name( object $route ) (在 Route 中定义)

获得路由名称。

$name = Route::name($route)

参数

  • object $route required - Route 实例

返回值

  • string

源代码

public static function name(Route $route)
{
	return array_search($route, Route::$_routes);
}

public static set( string $name [, string $uri_callback = NULL , array $regex = NULL ] ) (在 Route 中定义)

存储一个命名的路由,并返回它。如果“action”未定义,那么将始终设置为“index”。

Route::set('default', '(<controller>(/<action>(/<id>)))')
    ->defaults(array(
        'controller' => 'welcome',
    ));

参数

  • string $name required - 路由名
  • string $uri_callback = NULL - URI 模式
  • array $regex = NULL - 路由的键的正则表达式

返回值

  • Route

源代码

public static function set($name, $uri_callback = NULL, $regex = NULL)
{
	return Route::$_routes[$name] = new Route($uri_callback, $regex);
}

public uri( [ array $params = NULL ] ) (在 Route 中定义)

基于给定的参数,为当前路由生成 URI。

// 使用“default”路由: “users/profile/10”
$route->uri(array(
    'controller' => 'users',
    'action'     => 'profile',
    'id'         => '10'
));

参数

  • array $params = NULL - URI 参数

Tags

返回值

  • string

源代码

public function uri(array $params = NULL)
{
	// 从路由的 URI 开始
	$uri = $this->_uri;
	if (strpos($uri, '<') === false && strpos($uri, '(') === false)
	{
		// 这是一个静态路由,无需替换任何东西
		if (!$this->is_external())
			return $uri;
		// 如果本地主机设置中没有协议
		if (strpos($this->_defaults['host'], '://') === false)
		{
			// 使用定义的默认协议
			$params['host'] = Route::$default_protocol . $this->_defaults['host'];
		}
		else
		{
			// 使用提供的带协议的主机
			$params['host'] = $this->_defaults['host'];
		}
		// 编译最终的URI并返回它
		return rtrim($params['host'], '/') . '/' . $uri;
	}
	while (preg_match('#\([^()]++\)#', $uri, $match))
	{
		// 搜索匹配的值
		$search = $match[0];
		// 从匹配中去除括号,作为替换内容
		$replace = substr($match[0], 1, -1);
		while (preg_match('#' . Route::REGEX_KEY . '#', $replace, $match))
		{
			list($key, $param) = $match;
			if (isset($params[$param]))
			{
				// 用参数值替换键
				$replace = str_replace($key, $params[$param], $replace);
			}
			else
			{
				// 该组丢失了参数
				$replace = '';
				break;
			}
		}
		// 在 URI 中替换该组
		$uri = str_replace($search, $replace, $uri);
	}
	while (preg_match('#' . Route::REGEX_KEY . '#', $uri, $match))
	{
		list($key, $param) = $match;
		if (!isset($params[$param]))
		{
			// 查找默认
			if (isset($this->_defaults[$param]))
			{
				$params[$param] = $this->_defaults[$param];
			}
			else
			{
				// 需要未分组的参数
				throw new BootPHP_Exception('Required route parameter not passed: :param', array(
				':param' => $param,
				));
			}
		}
		$uri = str_replace($key, $params[$param], $uri);
	}
	// 修剪 URI 中多余的斜杠
	$uri = preg_replace('#//+#', '/', rtrim($uri, '/'));
	if ($this->is_external())
	{
		// 需要将主机添加到 URI 中
		$host = $this->_defaults['host'];
		if (strpos($host, '://') === false)
		{
			// 使用定义的默认协议
			$host = Route::$default_protocol . $host;
		}
		// 清理主机并将其放到 URI 中
		$uri = rtrim($host, '/') . '/' . $uri;
	}
	return $uri;
}

public static url( string $name [, array $params = NULL , mixed $protocol = NULL ] ) (在 Route 中定义)

根据路由名称创建一个 URL。这是一个快捷写法:

echo URL::site(Route::get($name)->uri($params), $protocol);

参数

  • string $name required - 路由名称
  • array $params = NULL - URI 参数
  • mixed $protocol = NULL - 协议字符串或布尔值,添加协议与域

Tags

返回值

  • string

源代码

public static function url($name, array $params = NULL, $protocol = NULL)
{
	$route = Route::get($name);
	// 创建一个带路由的 URI,并将其转换为 URL
	if ($route->is_external())
		return Route::get($name)->uri($params);
	else
		return URL::site(Route::get($name)->uri($params), $protocol);
}