1、爲什麼可以直接使用 Route::get 調用呢? 因爲這個是執行的 facade門面模式,就不具體說了,接下來看具體代碼的流程
Route::get('hello/:name', 'index/hello');
2、定位到 get 方法,第一個參數是路由規則,第二個是路由地址等等,發現最後都是定位到了 rule 方法,
/**
* 註冊GET路由
* @access public
* @param string $rule 路由規則
* @param mixed $route 路由地址
* @param array $option 路由參數
* @param array $pattern 變量規則
* @return RuleItem
*/
public function get($rule, $route = '', array $option = [], array $pattern = [])
{
return $this->rule($rule, $route, 'GET', $option, $pattern);
}
3、rule 方法中的 $this->group 是如何獲取的?
/**
* 註冊路由規則
* @access public
* @param string $rule 路由規則
* @param mixed $route 路由地址
* @param string $method 請求類型
* @param array $option 路由參數
* @param array $pattern 變量規則
* @return RuleItem
*/
public function rule($rule, $route, $method = '*', array $option = [], array $pattern = [])
{
return $this->group->addRule($rule, $route, $method, $option, $pattern);
}
我們會發現在 __construct 中有 setDefaultDomain() 方法,裏面有一段 new domain 類,而 Domain 繼承了 RuleGroup 類,這樣就實例化了 RuleGroup 類,那麼定位到 RuleGroup 中的 addRule 方法,如下圖
/**
* 初始化默認域名
* @access protected
* @return void
*/
protected function setDefaultDomain()
{
// 默認域名
$this->domain = $this->host;
// 註冊默認域名
$domain = new Domain($this, $this->host);
$this->domains[$this->host] = $domain;
// 默認分組
$this->group = $domain;
}
4、分析 addRule 方法
1、 首頁自動完整匹配,當 $rule == / 或者爲空時 $rule = $
2、創建路由規則實例,最後進行成員屬性定義,走到 setRule 方法中。
3、 看到最後 rule 是否爲 $,如果是的話,那麼 去除 $, 並對 option['complete_match'] 賦值爲 true
if ('$' == substr($rule, -1, 1)) {
// 是否完整匹配
$rule = substr($rule, 0, -1);
$this->option['complete_match'] = true;
}
4、去除左邊的 / 符號
$rule = '/' != $rule ? ltrim($rule, '/') : '';
5、對 rule 中 有 : 號的 進行 轉化。
if (false !== strpos($rule, ':')) {
$this->rule = preg_replace(['/\[\:(\w+)\]/', '/\:(\w+)/'], ['<\1?>', '<\1>'], $rule);
s} else {
$this->rule = $rule;
}
比如:rule 爲 hello/:name 那麼會轉化爲 hello/<name>
比如: rule 爲 hello/[:name] 那麼會轉化爲 hello/<?name>
6、生成路由標識的快捷訪問
1、分析路由規則中的變量,執行 parseVar 方法,當 rule 中存在 ?號,會 name => 2,否則爲 1,
/**
* 分析路由規則中的變量
* @access protected
* @param string $rule 路由規則
* @return array
*/
protected function parseVar($rule)
{
// 提取路由規則中的變量
$var = [];
if (preg_match_all('/<\w+\??>/', $rule, $matches)) {
foreach ($matches[0] as $name) {
$optional = false;
if (strpos($name, '?')) {
$name = substr($name, 1, -2);
$optional = true;
} else {
$name = substr($name, 1, -1);
}
$var[$name] = $optional ? 2 : 1;
}
}
return $var;
}
array(1) {
["name"] => int(2)
}
array(1) {
["name"] => int(1)
}
2、生成 變量 $value
$value = [$this->rule, $vars, $this->parent->getDomain(), $suffix, $this->method];
array(5) {
[0] => string(13) "hello/<name?>"
[1] => array(1) {
["name"] => int(2)
}
[2] => string(9) "localhost"
[3] => NULL
[4] => string(3) "get"
}
3、通過容器中 rule_name 類 執行 set 方法,將解析的變量放入到 $this->item 屬性中,
/**
* 註冊路由標識
* @access public
* @param string $name 路由標識
* @param array $value 路由規則
* @param bool $first 是否置頂
* @return void
*/
public function set($name, $value, $first = false)
{
if ($first && isset($this->item[$name])) {
array_unshift($this->item[$name], $value);
} else {
$this->item[$name][] = $value;
}
}
4、註冊路由規則, 生成對應類型的變量。
/**
* 註冊路由規則
* @access public
* @param string $rule 路由規則
* @param RuleItem $route 路由
* @return void
*/
public function setRule($rule, $route)
{
$this->rule[$route->getDomain()][$rule][$route->getMethod()] = $route;
}
array(1) {
["localhost"] => array(1) {
["api"] => array(1) {
["get"] => object(think\route\RuleItem)#9 (10) {
["hasSetRule"] => NULL
["name"] => NULL
["rule"] => string(3) "api"
["method"] => string(3) "get"
["vars"] => array(0) {
}
["option"] => array(0) {
}
["pattern"] => array(0) {
}
["mergeOptions"] => array(6) {
[0] => string(5) "after"
[1] => string(5) "model"
[2] => string(6) "header"
[3] => string(8) "response"
[4] => string(6) "append"
[5] => string(10) "middleware"
}
["doAfter"] => NULL
["lockOption"] => bool(false)
}
}
}
}
7、最後在定位到 RouteGroup 方法,執行 $this->RuleItem,並返回RouteItem 實列對象
$this->addRuleItem($ruleItem, $method);
return $ruleItem;
public function addRuleItem($rule, $method = '*')
{
if (strpos($method, '|')) {
$rule->method($method);
$method = '*';
}
$this->rules[$method][] = $rule;
return $this;
}
array(8) {
["*"] => array(0) {
}
["get"] => array(1) {
[0] => object(think\route\RuleItem)#9 (10) {
["hasSetRule"] => bool(true)
["name"] => NULL
["rule"] => string(3) "api"
["method"] => string(3) "get"
["vars"] => array(0) {
}
["option"] => array(0) {
}
["pattern"] => array(0) {
}
["mergeOptions"] => array(6) {
[0] => string(5) "after"
[1] => string(5) "model"
[2] => string(6) "header"
[3] => string(8) "response"
[4] => string(6) "append"
[5] => string(10) "middleware"
}
["doAfter"] => NULL
["lockOption"] => bool(false)
}
}
["post"] => array(0) {
}
["put"] => array(0) {
}
["patch"] => array(0) {
}
["delete"] => array(0) {
}
["head"] => array(0) {
}
["options"] => array(0) {
}
}