tp5.1 路由執行 (六)

 

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) {
  }
}

 

            

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章