window 127.0.0.1绑定到路由_ThinkPHP5.1 源码分析(六)- 路由解读

继续上一章讲到了

<?php
// 路由初始化
$this->routeInit();

开发手册:https://www.kancloud.cn/manual/thinkphp5_1/353962

route目录下的任何路由定义文件都是有效的,默认的路由定义文件是route.php,但你完全可以更改文件名,或者添加多个路由定义文件(你可以进行模块定义区分,但最终都会一起加载)。routeInit方法会扫描route目录下的所有文件,将其include进来

    /**
     * 路由初始化 导入路由定义规则
     * @access public
     * @return void
     */
    public function routeInit()
    {
        // 路由检测
        $files = scandir($this->routePath);
        foreach ($files as $file) {
            if (strpos($file, '.php')) {
                $filename = $this->routePath . $file;
                // 导入路由配置
                $rules = include $filename; // 如果$rules不是数组,那么include返回值是int(1),失败返回false
                if (is_array($rules)) {
                    $this->route->import($rules);
                }
            }
        }

        if ($this->route->config('route_annotation')) {
            // 自动生成路由定义
            if ($this->appDebug) {
                $suffix = $this->route->config('controller_suffix') || $this->route->config('class_suffix');
                $this->build->buildRoute($suffix);
            }

            $filename = $this->runtimePath . 'build_route.php';

            if (is_file($filename)) {
                include $filename;
            }
        }
    }

从代码说起:

在路由文件中定义下面的路由规则,使用门面模式调用Route类下的get方法

// routeroute.php
<?php
//Route::get('think', function () {
//    return 'hello,ThinkPHP5!';
//});

// :对应动态参数
Route::get('hello/:name', 'index/hello');
// 上面的写法等同于
//Route::rule('hello/:name', 'index/hello', 'get');
// 可选参数
//Route::get('blog/:year/[:month]','Blog/archive');
// ...
// 更多使用方法看手册

这里以Route::get('hello/:name','index/hello');为测试用例进行代码分析,贴出每一步代码执行对应的值,复习的时候看看注释就好。

// thinkphp/library/think/Route.php
<?php
    /**
     * 注册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);
    }

    /**
     * 注册路由规则
     * @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 = [])
    {
        // $rule = 'hello/:name'
        // $route = 'index/hello'
        // $method = 'GET'
        // $option = []
        // $pattern = []
        return $this->group->addRule($rule, $route, $method, $option, $pattern);
    }

说明:为什么可以直接通过$this->group->addRule()调用方法,在哪里定义了成员属性?

我们可以找到构造方法中调用了$this->setDefaultDomain(),在这个方法中将new Domain($this, $this->host)的实例赋值给了$this->group,但是在Domain()类中并没有addRule()方法,所以会再找到Domain类的父类RuleGroup类中的addRule()方法。

// thinkphp/library/think/route/RuleGroup.php
<?php
    /**
     * 添加分组下的路由规则或者子分组
     * @access public
     * @param  string    $rule       路由规则
     * @param  string    $route      路由地址
     * @param  string    $method     请求类型
     * @param  array     $option     路由参数
     * @param  array     $pattern    变量规则
     * @return $this
     */
    public function addRule($rule, $route, $method = '*', $option = [], $pattern = [])
    {
        // $rule = 'hello/:name';$route = 'index/hello';$method = 'GET';$option = [];$pattern = []
        // 读取路由标识
        if (is_array($rule)) {
            $name = $rule[0];
            $rule = $rule[1];
        } elseif (is_string($route)) {
            $name = $route;
        } else {
            $name = null;
        }
        // $name = 'index/hello';
        $method = strtolower($method);
        // $method = 'get';

        if ('/' === $rule || '' === $rule) {
            // 首页自动完整匹配
            $rule .= '$'; // /$ 或者 $
        }

        // 创建路由规则实例
        // 说明  $this->router为Route类对象,在构造方法中赋值的,$this 本类  $name='index/hello' $method='get' $option=[] $pattern=[] 
        $ruleItem = new RuleItem($this->router, $this, $name, $rule, $route, $method, $option, $pattern);

        // 跨域相关设置
        if (!empty($option['cross_domain'])) {
            $this->router->setCrossDomainRule($ruleItem, $method);
        }

        $this->addRuleItem($ruleItem, $method);

        return $ruleItem;
    }
   
    public function addRuleItem($rule, $method = '*')
    {
        if (strpos($method, '|')) {
            /** @see RuleItem::method() */
            $rule->method($method);
            $method = '*';
        }

        $this->rules[$method][] = $rule;

        return $this;
    }
// thinkphp/library/think/route/RuleItem.php
<?php
    /**
     * 架构函数
     * @access public
     * @param  Route             $router 路由实例
     * @param  RuleGroup         $parent 上级对象
     * @param  string            $name 路由标识
     * @param  string|array      $rule 路由规则
     * @param  string|Closure   $route 路由地址
     * @param  string            $method 请求类型
     * @param  array             $option 路由参数
     * @param  array             $pattern 变量规则
     */
    public function __construct(Route $router, RuleGroup $parent, $name, $rule, $route, $method = '*', $option = [], $pattern = [])
    {
        $this->router  = $router;
        $this->parent  = $parent;
        $this->name    = $name;
        $this->route   = $route;
        $this->method  = $method;
        $this->option  = $option;
        $this->pattern = $pattern;

        $this->setRule($rule);

        if (!empty($option['cross_domain'])) {
            $this->router->setCrossDomainRule($this, $method);
        }
    }

    /**
     * 路由规则预处理
     * @access public
     * @param  string      $rule     路由规则
     * @return void
     */
    public function setRule($rule)
    {
        // 如果是完整匹配会往$this->option数组中压入complete_match = true
        // 这里也解释了为什么前面需要对$rule='/'的路由单独处理拼上'$'
        if ('$' == substr($rule, -1, 1)) {
            // 是否完整匹配
            $rule = substr($rule, 0, -1);
            $this->option['complete_match'] = true;
        }

        $rule = '/' != $rule ? ltrim($rule, '/') : '';
        // $rule = "hello/:name"
        if ($this->parent && $prefix = $this->parent->getFullName()) {
            $rule = $prefix . ($rule ? '/' . ltrim($rule, '/') : '');
        }

        if (false !== strpos($rule, ':')) {
            $this->rule = preg_replace(['/[:(w+)]/', '/:(w+)/'], ['<1?>', '<1>'], $rule);
           // $this->rule = "hello/<name>"
        } else {
            $this->rule = $rule;
        }

        // 生成路由标识的快捷访问
        $this->setRuleName();
    }

    /**
     * 设置路由标识 用于URL反解生成
     * @access protected
     * @param  bool     $first   是否插入开头
     * @return void
     */
    protected function setRuleName($first = false)
    {
        // $this->name = 'indexhello'
        if ($this->name) {
            // $var  array(1) {["name"] => int(1)} 为1 表示动态参数 为2 表示可选参数
            $vars = $this->parseVar($this->rule);
            $name = strtolower($this->name);

            // 路由参数处理 后面再补充
            if (isset($this->option['ext'])) {
                $suffix = $this->option['ext'];
            } elseif ($this->parent->getOption('ext')) {
                $suffix = $this->parent->getOption('ext');
            } else {
                $suffix = null;
            }

            $value = [$this->rule, $vars, $this->parent->getDomain(), $suffix, $this->method];
            //halt($value);
            /*
             * array(5) {
             *       [0] => string(12) "hello/<name>"
             *       [1] => array(1) {
             *               ["name"] => int(1)
             *           }
             *       [2] => string(9) "127.0.0.1"
             *       [3] => NULL
             *       [4] => string(3) "get"
             *  }
             */

            // 注册路由标识
            /** @see RuleName::set() */
            Container::get('rule_name')->set($name, $value, $first);
        }

        if (!$this->hasSetRule) {
            /** @see RuleName::setRule() */
            Container::get('rule_name')->setRule($this->rule, $this);
            $this->hasSetRule = true;
        }
    }

    /**
     * 分析路由规则中的变量
     * @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;
    }
// thinkphp/library/think/route/RuleName.php
<?php
    /**
     * 注册路由标识
     * @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;
        }
        // $this->item的值
        /* 
         array(1) {
            ["index/hello"] => array(1) {
                 [0] => array(5) {
                     [0] => string(12) "hello/<name>"
                     [1] => array(1) {
                          ["name"] => int(1)
                     }
                     [2] => string(9) "127.0.0.1"
                     [3] => NULL
                     [4] => string(3) "get"
                  }
            }
         }
         */
    }

    /**
     * 注册路由规则
     * @access public
     * @param  string   $rule      路由规则
     * @param  RuleItem $route     路由
     * @return void
     */
    public function setRule($rule, $route)
    {
        $this->rule[$route->getDomain()][$rule][$route->getMethod()] = $route;
    }

b4391ecfa5d1310d0376c53d7d190ec6.png
$this-&amp;amp;gt;rule

代码执行完,回到$this->addRuleItem($ruleItem, $method);打印$this->rules:

2abcab819f1966a17ee4c728d2b1e878.png

归纳流程:

63304497d3389e47e0c494bf4c9c6036.png
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值