精华内容
下载资源
问答
  • thinkphp5源码解析
  • 第三方素材解析源码分享给大家伙儿,仅限于研究哈。我也是朋友分享给我的。喜欢的自己拿走研究,tp内核。
  • 这个类里面有很这样的使用例如$this->hook->import(); $this->config->get(); $this->request->init();等等 你知道这个对象怎么来的吗?不急,亮仔一一道来: ...app类会继承容器Container(这是关键...

    这个类里面有很这样的使用例如$this->hook->import(); $this->config->get(); $this->request->init();等等
    你知道这个对象怎么来的吗?不急,亮仔一一道来:

    1. app类会继承容器Container(这是关键)
    2. 容器有个魔术方法很重要 例如当调用$this->hook时找不到会调用魔术方法
        public function __get($name)
        {
            return $this->make($name);
        }
    

    3.接着就是容器Container里面的make方法 ,这个make方法里面就是搞事情返回对象

     public function make($abstract, $vars = [], $newInstance = false)
        {
            if (true === $vars) {
                // 总是创建新的实例化对象
                $newInstance = true;
                $vars        = [];
            }
             //容器标识别名有没有
            $abstract = isset($this->name[$abstract]) ? $this->name[$abstract] : $abstract;
    
            //容器里有的话 就从容器里拿出来
            if (isset($this->instances[$abstract]) && !$newInstance) {
                return $this->instances[$abstract];
            }
    
            //容器绑定标识
            if (isset($this->bind[$abstract])) {
                $concrete = $this->bind[$abstract]; //think\App
    
                if ($concrete instanceof Closure) { //闭包
                    $object = $this->invokeFunction($concrete, $vars);
                } else {
                    $this->name[$abstract] = $concrete; //放入容器标识  app =>
                    return $this->make($concrete, $vars, $newInstance);
                }
            } else {
                $object = $this->invokeClass($abstract, $vars);
            }
    
            if (!$newInstance) {
                $this->instances[$abstract] = $object;
            }
            return $object;
        }
    

    4.make 方法里面有个容器绑定标识$this->bind其实就是属性定义好的,你细细品一下

    /**容器绑定标识
         *
         * @var array
         */
        protected $bind = [
            'app'                   => App::class,
            'build'                 => Build::class,
            'cache'                 => Cache::class,
            'config'                => Config::class,
            'cookie'                => Cookie::class,
            'debug'                 => Debug::class,
            'env'                   => Env::class,
            'hook'                  => Hook::class,
            'lang'                  => Lang::class,
            'log'                   => Log::class,
            'middleware'            => Middleware::class,
            'request'               => Request::class,
            'response'              => Response::class,
            'route'                 => Route::class,
            'session'               => Session::class,
            'template'              => Template::class,
            'url'                   => Url::class,
            'validate'              => Validate::class,
            'view'                  => View::class,
            'rule_name'             => route\RuleName::class,
            // 接口依赖注入
            'think\LoggerInterface' => Log::class,
        ];
    
    展开全文
  • tp5底层源码分析之路由解析

    千次阅读 2019-07-14 11:05:28
    5.设置路由规则 /** * 设置路由规则 * @access public * @param string|array $rule 路由规则 * @param string $route 路由地址 * @param string $type 请求类型 * @param array $option 路由参数 * @param...
    • 流程(下载)
      在这里插入图片描述

    • 相关函数
      1.path

     /**
         * 获取当前请求URL的pathinfo信息(不含URL后缀)
         * @access public
         * @return string
         */
        public function path()
        {
    
            if (is_null($this->path)) {
                $suffix   = Config::get('url_html_suffix');
                $pathinfo = $this->pathinfo();
                if (false === $suffix) {
                    // 禁止伪静态访问
                    $this->path = $pathinfo;
                } elseif ($suffix) {
                    // 去除正常的URL后缀
                    $this->path = preg_replace('/\.(' . ltrim($suffix, '.') . ')$/i', '', $pathinfo);
                } else {
                    // 允许任何后缀访问
                    $this->path = preg_replace('/\.' . $this->ext() . '$/i', '', $pathinfo);
                }
            }
            return $this->path;
        }
    
    

    2.pathinfo

    /**
         * 获取当前请求URL的pathinfo信息(含URL后缀)
         * @access public
         * @return string
         */
        public function pathinfo()
        {
            if (is_null($this->pathinfo)) {
                if (isset($_GET[Config::get('var_pathinfo')])) {
                    // 判断URL里面是否有兼容模式参数
                    $_SERVER['PATH_INFO'] = $_GET[Config::get('var_pathinfo')];
                    unset($_GET[Config::get('var_pathinfo')]);
                } elseif (IS_CLI) {
                    // CLI模式下 index.php module/controller/action/params/...
                    $_SERVER['PATH_INFO'] = isset($_SERVER['argv'][1]) ? $_SERVER['argv'][1] : '';
                }
    
                // 分析PATHINFO信息
                if (!isset($_SERVER['PATH_INFO'])) {
                    foreach (Config::get('pathinfo_fetch') as $type) {
                        if (!empty($_SERVER[$type])) {
                            $_SERVER['PATH_INFO'] = (0 === strpos($_SERVER[$type], $_SERVER['SCRIPT_NAME'])) ?
                            substr($_SERVER[$type], strlen($_SERVER['SCRIPT_NAME'])) : $_SERVER[$type];
                            break;
                        }
                    }
                }
                $this->pathinfo = empty($_SERVER['PATH_INFO']) ? '/' : ltrim($_SERVER['PATH_INFO'], '/');
            }
            return $this->pathinfo;
        }
    
    

    3.导入配置文件

     /**
         * 导入配置文件的路由规则
         * @access public
         * @param array  $rule 路由规则
         * @param string $type 请求类型
         * @return void
         */
        public static function import(array $rule, $type = '*')
        {
            // 检查域名部署
            if (isset($rule['__domain__'])) {
                self::domain($rule['__domain__']);
                unset($rule['__domain__']);
            }
    
            // 检查变量规则
            if (isset($rule['__pattern__'])) {
                self::pattern($rule['__pattern__']);
                unset($rule['__pattern__']);
            }
    
            // 检查路由别名
            if (isset($rule['__alias__'])) {
                self::alias($rule['__alias__']);
                unset($rule['__alias__']);
            }
    
            // 检查资源路由
            if (isset($rule['__rest__'])) {
                self::resource($rule['__rest__']);
                unset($rule['__rest__']);
            }
    
            self::registerRules($rule, strtolower($type));
        }
    

    4.批量注册

     /**
         * 导入配置文件的路由规则
         * @access public
         * @param array  $rule 路由规则
         * @param string $type 请求类型
         * @return void
         */
        public static function import(array $rule, $type = '*')
        {
            // 检查域名部署
            if (isset($rule['__domain__'])) {
                self::domain($rule['__domain__']);
                unset($rule['__domain__']);
            }
    
            // 检查变量规则
            if (isset($rule['__pattern__'])) {
                self::pattern($rule['__pattern__']);
                unset($rule['__pattern__']);
            }
    
            // 检查路由别名
            if (isset($rule['__alias__'])) {
                self::alias($rule['__alias__']);
                unset($rule['__alias__']);
            }
    
            // 检查资源路由
            if (isset($rule['__rest__'])) {
                self::resource($rule['__rest__']);
                unset($rule['__rest__']);
            }
    
            self::registerRules($rule, strtolower($type));
        }
    

    5.设置路由规则

    /**
         * 设置路由规则
         * @access public
         * @param string|array $rule    路由规则
         * @param string       $route   路由地址
         * @param string       $type    请求类型
         * @param array        $option  路由参数
         * @param array        $pattern 变量规则
         * @param string       $group   所属分组
         * @return void
         */
        protected static function setRule($rule, $route, $type = '*', $option = [], $pattern = [], $group = '')
        {
            if (is_array($rule)) {
                $name = $rule[0];
                $rule = $rule[1];
            } elseif (is_string($route)) {
                $name = $route;
            }
            if (!isset($option['complete_match'])) {
                if (Config::get('route_complete_match')) {
                    $option['complete_match'] = true;
                } elseif ('$' == substr($rule, -1, 1)) {
                    // 是否完整匹配
                    $option['complete_match'] = true;
                }
            } elseif (empty($option['complete_match']) && '$' == substr($rule, -1, 1)) {
                // 是否完整匹配
                $option['complete_match'] = true;
            }
    
            if ('$' == substr($rule, -1, 1)) {
                $rule = substr($rule, 0, -1);
            }
    
            if ('/' != $rule || $group) {
                $rule = trim($rule, '/');
            }
            $vars = self::parseVar($rule);
            if (isset($name)) {
                $key    = $group ? $group . ($rule ? '/' . $rule : '') : $rule;
                $suffix = isset($option['ext']) ? $option['ext'] : null;
                self::name($name, [$key, $vars, self::$domain, $suffix]);
            }
            if (isset($option['modular'])) {
                $route = $option['modular'] . '/' . $route;
            }
            if ($group) {
                if ('*' != $type) {
                    $option['method'] = $type;
                }
                if (self::$domain) {
                    self::$rules['domain'][self::$domain]['*'][$group]['rule'][] = ['rule' => $rule, 'route' => $route, 'var' => $vars, 'option' => $option, 'pattern' => $pattern];
                } else {
                    self::$rules['*'][$group]['rule'][] = ['rule' => $rule, 'route' => $route, 'var' => $vars, 'option' => $option, 'pattern' => $pattern];
                }
            } else {
                if ('*' != $type && isset(self::$rules['*'][$rule])) {
                    unset(self::$rules['*'][$rule]);
                }
                if (self::$domain) {
                    self::$rules['domain'][self::$domain][$type][$rule] = ['rule' => $rule, 'route' => $route, 'var' => $vars, 'option' => $option, 'pattern' => $pattern];
                } else {
                    self::$rules[$type][$rule] = ['rule' => $rule, 'route' => $route, 'var' => $vars, 'option' => $option, 'pattern' => $pattern];
                }
                if ('*' == $type) {
                    // 注册路由快捷方式
                    foreach (['get', 'post', 'put', 'delete', 'patch', 'head', 'options'] as $method) {
                        if (self::$domain && !isset(self::$rules['domain'][self::$domain][$method][$rule])) {
                            self::$rules['domain'][self::$domain][$method][$rule] = true;
                        } elseif (!self::$domain && !isset(self::$rules[$method][$rule])) {
                            self::$rules[$method][$rule] = true;
                        }
                    }
                }
            }
        }
    

    6.注册路由分组

     /**
         * 注册路由分组
         * @access public
         * @param string|array   $name    分组名称或者参数
         * @param array|\Closure $routes  路由地址
         * @param array          $option  路由参数
         * @param array          $pattern 变量规则
         * @return void
         */
        public static function group($name, $routes, $option = [], $pattern = [])
        {
            if (is_array($name)) {
                $option = $name;
                $name   = isset($option['name']) ? $option['name'] : '';
            }
            // 分组
            $currentGroup = self::getGroup('name');
            if ($currentGroup) {
                $name = $currentGroup . ($name ? '/' . ltrim($name, '/') : '');
            }
            if (!empty($name)) {
                if ($routes instanceof \Closure) {
                    $currentOption  = self::getGroup('option');
                    $currentPattern = self::getGroup('pattern');
                    self::setGroup($name, array_merge($currentOption, $option), array_merge($currentPattern, $pattern));
                    call_user_func_array($routes, []);
                    self::setGroup($currentGroup, $currentOption, $currentPattern);
                    if ($currentGroup != $name) {
                        self::$rules['*'][$name]['route']   = '';
                        self::$rules['*'][$name]['var']     = self::parseVar($name);
                        self::$rules['*'][$name]['option']  = $option;
                        self::$rules['*'][$name]['pattern'] = $pattern;
                    }
                } else {
                    $item          = [];
                    $completeMatch = Config::get('route_complete_match');
                    foreach ($routes as $key => $val) {
                        if (is_numeric($key)) {
                            $key = array_shift($val);
                        }
                        if (is_array($val)) {
                            $route    = $val[0];
                            $option1  = array_merge($option, isset($val[1]) ? $val[1] : []);
                            $pattern1 = array_merge($pattern, isset($val[2]) ? $val[2] : []);
                        } else {
                            $route = $val;
                        }
    
                        $options  = isset($option1) ? $option1 : $option;
                        $patterns = isset($pattern1) ? $pattern1 : $pattern;
                        if ('$' == substr($key, -1, 1)) {
                            // 是否完整匹配
                            $options['complete_match'] = true;
                            $key                       = substr($key, 0, -1);
                        } elseif ($completeMatch) {
                            $options['complete_match'] = true;
                        }
                        $key    = trim($key, '/');
                        $vars   = self::parseVar($key);
                        $item[] = ['rule' => $key, 'route' => $route, 'var' => $vars, 'option' => $options, 'pattern' => $patterns];
                        // 设置路由标识
                        $suffix = isset($options['ext']) ? $options['ext'] : null;
                        self::name($route, [$name . ($key ? '/' . $key : ''), $vars, self::$domain, $suffix]);
                    }
                    self::$rules['*'][$name] = ['rule' => $item, 'route' => '', 'var' => [], 'option' => $option, 'pattern' => $pattern];
                }
    
                foreach (['get', 'post', 'put', 'delete', 'patch', 'head', 'options'] as $method) {
                    if (!isset(self::$rules[$method][$name])) {
                        self::$rules[$method][$name] = true;
                    } elseif (is_array(self::$rules[$method][$name])) {
                        self::$rules[$method][$name] = array_merge(self::$rules['*'][$name], self::$rules[$method][$name]);
                    }
                }
    
            } elseif ($routes instanceof \Closure) {
                // 闭包注册
                $currentOption  = self::getGroup('option');
                $currentPattern = self::getGroup('pattern');
                self::setGroup('', array_merge($currentOption, $option), array_merge($currentPattern, $pattern));
                call_user_func_array($routes, []);
                self::setGroup($currentGroup, $currentOption, $currentPattern);
            } else {
                // 批量注册路由
                self::rule($routes, '', '*', $option, $pattern);
            }
        }
    
    

    7.解析模块的URL地址

      /**
         * 解析模块的URL地址 [模块/控制器/操作?]参数1=值1&参数2=值2...
         * @access public
         * @param string $url        URL地址
         * @param string $depr       URL分隔符
         * @param bool   $autoSearch 是否自动深度搜索控制器
         * @return array
         */
        public static function parseUrl($url, $depr = '/', $autoSearch = false)
        {
    
            if (isset(self::$bind['module'])) {
                $bind = str_replace('/', $depr, self::$bind['module']);
                // 如果有模块/控制器绑定
                $url = $bind . ('.' != substr($bind, -1) ? $depr : '') . ltrim($url, $depr);
            }
            $url              = str_replace($depr, '|', $url);
            list($path, $var) = self::parseUrlPath($url);
            $route            = [null, null, null];
            if (isset($path)) {
                // 解析模块
                $module = Config::get('app_multi_module') ? array_shift($path) : null;
                if ($autoSearch) {
                    // 自动搜索控制器
                    $dir    = APP_PATH . ($module ? $module . DS : '') . Config::get('url_controller_layer');
                    $suffix = App::$suffix || Config::get('controller_suffix') ? ucfirst(Config::get('url_controller_layer')) : '';
                    $item   = [];
                    $find   = false;
                    foreach ($path as $val) {
                        $item[] = $val;
                        $file   = $dir . DS . str_replace('.', DS, $val) . $suffix . EXT;
                        $file   = pathinfo($file, PATHINFO_DIRNAME) . DS . Loader::parseName(pathinfo($file, PATHINFO_FILENAME), 1) . EXT;
                        if (is_file($file)) {
                            $find = true;
                            break;
                        } else {
                            $dir .= DS . Loader::parseName($val);
                        }
                    }
                    if ($find) {
                        $controller = implode('.', $item);
                        $path       = array_slice($path, count($item));
                    } else {
                        $controller = array_shift($path);
                    }
                } else {
                    // 解析控制器
                    $controller = !empty($path) ? array_shift($path) : null;
                }
                // 解析操作
                $action = !empty($path) ? array_shift($path) : null;
                // 解析额外参数
                self::parseUrlParams(empty($path) ? '' : implode('|', $path));
                // 封装路由
                $route = [$module, $controller, $action];
                // 检查地址是否被定义过路由
                $name  = strtolower($module . '/' . Loader::parseName($controller, 1) . '/' . $action);
                $name2 = '';
                if (empty($module) || isset($bind) && $module == $bind) {
                    $name2 = strtolower(Loader::parseName($controller, 1) . '/' . $action);
                }
    
                if (isset(self::$rules['name'][$name]) || isset(self::$rules['name'][$name2])) {
                    throw new HttpException(404, 'invalid request:' . str_replace('|', $depr, $url));
                }
            }
            return ['type' => 'module', 'module' => $route];
        }
    
    

    8.解析URL的pathinfo参数和变量

     /**
         * 解析URL的pathinfo参数和变量
         * @access private
         * @param string $url URL地址
         * @return array
         */
        private static function parseUrlPath($url)
        {
            // 分隔符替换 确保路由定义使用统一的分隔符
            $url = str_replace('|', '/', $url);
            $url = trim($url, '/');
            $var = [];
            if (false !== strpos($url, '?')) {
                // [模块/控制器/操作?]参数1=值1&参数2=值2...
                $info = parse_url($url);
                $path = explode('/', $info['path']);
                parse_str($info['query'], $var);
            } elseif (strpos($url, '/')) {
                // [模块/控制器/操作]
                $path = explode('/', $url);
            } else {
                $path = [$url];
            }
            return [$path, $var];
        }
    

    9.检测URL和规则路由是否匹配

     /**
         * 检测URL和规则路由是否匹配
         * @access private
         * @param string $url     URL地址
         * @param string $rule    路由规则
         * @param array  $pattern 变量规则
         * @return array|false
         */
        private static function match($url, $rule, $pattern)
        {
            $m2 = explode('/', $rule);
            $m1 = explode('|', $url);
    
            $var = [];
            foreach ($m2 as $key => $val) {
                // val中定义了多个变量 <id><name>
                if (false !== strpos($val, '<') && preg_match_all('/<(\w+(\??))>/', $val, $matches)) {
                    $value   = [];
                    $replace = [];
                    foreach ($matches[1] as $name) {
                        if (strpos($name, '?')) {
                            $name      = substr($name, 0, -1);
                            $replace[] = '(' . (isset($pattern[$name]) ? $pattern[$name] : '\w+') . ')?';
                        } else {
                            $replace[] = '(' . (isset($pattern[$name]) ? $pattern[$name] : '\w+') . ')';
                        }
                        $value[] = $name;
                    }
                    $val = str_replace($matches[0], $replace, $val);
                    if (preg_match('/^' . $val . '$/', isset($m1[$key]) ? $m1[$key] : '', $match)) {
                        array_shift($match);
                        foreach ($value as $k => $name) {
                            if (isset($match[$k])) {
                                $var[$name] = $match[$k];
                            }
                        }
                        continue;
                    } else {
                        return false;
                    }
                }
    
                if (0 === strpos($val, '[:')) {
                    // 可选参数
                    $val      = substr($val, 1, -1);
                    $optional = true;
                } else {
                    $optional = false;
                }
                if (0 === strpos($val, ':')) {
                    // URL变量
                    $name = substr($val, 1);
                    if (!$optional && !isset($m1[$key])) {
                        return false;
                    }
                    if (isset($m1[$key]) && isset($pattern[$name])) {
                        // 检查变量规则
                        if ($pattern[$name] instanceof \Closure) {
                            $result = call_user_func_array($pattern[$name], [$m1[$key]]);
                            if (false === $result) {
                                return false;
                            }
                        } elseif (!preg_match(0 === strpos($pattern[$name], '/') ? $pattern[$name] : '/^' . $pattern[$name] . '$/', $m1[$key])) {
                            return false;
                        }
                    }
                    $var[$name] = isset($m1[$key]) ? $m1[$key] : '';
                } elseif (!isset($m1[$key]) || 0 !== strcasecmp($val, $m1[$key])) {
                    return false;
                }
            }
            // 成功匹配后返回URL中的动态变量数组
            return $var;
        }
    

    10.解析规则路由

    /**
         * 解析规则路由
         * @access private
         * @param string $rule      路由规则
         * @param string $route     路由地址
         * @param string $pathinfo  URL地址
         * @param array  $option    路由参数
         * @param array  $matches   匹配的变量
         * @param bool   $fromCache 通过缓存解析
         * @return array
         */
        private static function parseRule($rule, $route, $pathinfo, $option = [], $matches = [], $fromCache = false)
        {
            $request = Request::instance();
    
            //保存解析缓存
            if (Config::get('route_check_cache') && !$fromCache) {
                try {
                    $key = self::getCheckCacheKey($request);
                    Cache::tag('route_check')->set($key, [$rule, $route, $pathinfo, $option, $matches]);
                } catch (\Exception $e) {
    
                }
            }
    
            // 解析路由规则
            if ($rule) {
                $rule = explode('/', $rule);
                // 获取URL地址中的参数
                $paths = explode('|', $pathinfo);
                foreach ($rule as $item) {
                    $fun = '';
                    if (0 === strpos($item, '[:')) {
                        $item = substr($item, 1, -1);
                    }
                    if (0 === strpos($item, ':')) {
                        $var           = substr($item, 1);
                        $matches[$var] = array_shift($paths);
                    } else {
                        // 过滤URL中的静态变量
                        array_shift($paths);
                    }
                }
            } else {
                $paths = explode('|', $pathinfo);
            }
    
            // 获取路由地址规则
            if (is_string($route) && isset($option['prefix'])) {
                // 路由地址前缀
                $route = $option['prefix'] . $route;
            }
            // 替换路由地址中的变量
            if (is_string($route) && !empty($matches)) {
                foreach ($matches as $key => $val) {
                    if (false !== strpos($route, ':' . $key)) {
                        $route = str_replace(':' . $key, $val, $route);
                    }
                }
            }
    
            // 绑定模型数据
            if (isset($option['bind_model'])) {
                $bind = [];
                foreach ($option['bind_model'] as $key => $val) {
                    if ($val instanceof \Closure) {
                        $result = call_user_func_array($val, [$matches]);
                    } else {
                        if (is_array($val)) {
                            $fields    = explode('&', $val[1]);
                            $model     = $val[0];
                            $exception = isset($val[2]) ? $val[2] : true;
                        } else {
                            $fields    = ['id'];
                            $model     = $val;
                            $exception = true;
                        }
                        $where = [];
                        $match = true;
                        foreach ($fields as $field) {
                            if (!isset($matches[$field])) {
                                $match = false;
                                break;
                            } else {
                                $where[$field] = $matches[$field];
                            }
                        }
                        if ($match) {
                            $query  = strpos($model, '\\') ? $model::where($where) : Loader::model($model)->where($where);
                            $result = $query->failException($exception)->find();
                        }
                    }
                    if (!empty($result)) {
                        $bind[$key] = $result;
                    }
                }
                $request->bind($bind);
            }
    
            if (!empty($option['response'])) {
                Hook::add('response_send', $option['response']);
            }
    
            // 解析额外参数
            self::parseUrlParams(empty($paths) ? '' : implode('|', $paths), $matches);
            // 记录匹配的路由信息
            $request->routeInfo(['rule' => $rule, 'route' => $route, 'option' => $option, 'var' => $matches]);
    
            // 检测路由after行为
            if (!empty($option['after_behavior'])) {
                if ($option['after_behavior'] instanceof \Closure) {
                    $result = call_user_func_array($option['after_behavior'], []);
                } else {
                    foreach ((array) $option['after_behavior'] as $behavior) {
                        $result = Hook::exec($behavior, '');
                        if (!is_null($result)) {
                            break;
                        }
                    }
                }
                // 路由规则重定向
                if ($result instanceof Response) {
                    return ['type' => 'response', 'response' => $result];
                } elseif (is_array($result)) {
                    return $result;
                }
            }
    
            if ($route instanceof \Closure) {
                // 执行闭包
                $result = ['type' => 'function', 'function' => $route];
            } elseif (0 === strpos($route, '/') || strpos($route, '://')) {
                // 路由到重定向地址
                $result = ['type' => 'redirect', 'url' => $route, 'status' => isset($option['status']) ? $option['status'] : 301];
            } elseif (false !== strpos($route, '\\')) {
                // 路由到方法
                list($path, $var) = self::parseUrlPath($route);
                $route            = str_replace('/', '@', implode('/', $path));
                $method           = strpos($route, '@') ? explode('@', $route) : $route;
                $result           = ['type' => 'method', 'method' => $method, 'var' => $var];
            } elseif (0 === strpos($route, '@')) {
                // 路由到控制器
                $route             = substr($route, 1);
                list($route, $var) = self::parseUrlPath($route);
                $result            = ['type' => 'controller', 'controller' => implode('/', $route), 'var' => $var];
                $request->action(array_pop($route));
                $request->controller($route ? array_pop($route) : Config::get('default_controller'));
                $request->module($route ? array_pop($route) : Config::get('default_module'));
                App::$modulePath = APP_PATH . (Config::get('app_multi_module') ? $request->module() . DS : '');
            } else {
                // 路由到模块/控制器/操作
                $result = self::parseModule($route, isset($option['convert']) ? $option['convert'] : false);
            }
            // 开启请求缓存
            if ($request->isGet() && isset($option['cache'])) {
                $cache = $option['cache'];
                if (is_array($cache)) {
                    list($key, $expire, $tag) = array_pad($cache, 3, null);
                } else {
                    $key    = str_replace('|', '/', $pathinfo);
                    $expire = $cache;
                    $tag    = null;
                }
                $request->cache($key, $expire, $tag);
            }
            return $result;
        }
    

    11.解析URL地址为 模块/控制器/操作

      /**
         * 解析URL地址为 模块/控制器/操作
         * @access private
         * @param string $url     URL地址
         * @param bool   $convert 是否自动转换URL地址
         * @return array
         */
        private static function parseModule($url, $convert = false)
        {
            list($path, $var) = self::parseUrlPath($url);
            $action           = array_pop($path);
            $controller       = !empty($path) ? array_pop($path) : null;
            $module           = Config::get('app_multi_module') && !empty($path) ? array_pop($path) : null;
            $method           = Request::instance()->method();
            if (Config::get('use_action_prefix') && !empty(self::$methodPrefix[$method])) {
                // 操作方法前缀支持
                $action = 0 !== strpos($action, self::$methodPrefix[$method]) ? self::$methodPrefix[$method] . $action : $action;
            }
            // 设置当前请求的路由变量
            Request::instance()->route($var);
            // 路由到模块/控制器/操作
            return ['type' => 'module', 'module' => [$module, $controller, $action], 'convert' => $convert];
        }
    

    12.解析URL地址中的参数Request对象

      /**
         * 解析URL地址中的参数Request对象
         * @access private
         * @param string $url 路由规则
         * @param array  $var 变量
         * @return void
         */
        private static function parseUrlParams($url, &$var = [])
        {
            if ($url) {
                if (Config::get('url_param_type')) {
                    $var += explode('|', $url);
                } else {
                    preg_replace_callback('/(\w+)\|([^\|]+)/', function ($match) use (&$var) {
                        $var[$match[1]] = strip_tags($match[2]);
                    }, $url);
                }
            }
            // 设置当前请求的参数
            Request::instance()->route($var);
        }
    

    13.分析路由规则中的变量

        // 分析路由规则中的变量
        private static function parseVar($rule)
        {
            // 提取路由规则中的变量
            $var = [];
            foreach (explode('/', $rule) as $val) {
                $optional = false;
                if (false !== strpos($val, '<') && preg_match_all('/<(\w+(\??))>/', $val, $matches)) {
                    foreach ($matches[1] as $name) {
                        if (strpos($name, '?')) {
                            $name     = substr($name, 0, -1);
                            $optional = true;
                        } else {
                            $optional = false;
                        }
                        $var[$name] = $optional ? 2 : 1;
                    }
                }
    
                if (0 === strpos($val, '[:')) {
                    // 可选参数
                    $optional = true;
                    $val      = substr($val, 1, -1);
                }
                if (0 === strpos($val, ':')) {
                    // URL变量
                    $name       = substr($val, 1);
                    $var[$name] = $optional ? 2 : 1;
                }
            }
            return $var;
        }
    
    

    14.用反射执行类的方法 支持参数绑定

       /**
         * 调用反射执行类的方法 支持参数绑定
         * @access public
         * @param string|array $method 方法
         * @param array        $vars   变量
         * @return mixed
         */
        public static function invokeMethod($method, $vars = [])
        {
            if (is_array($method)) {
                $class   = is_object($method[0]) ? $method[0] : self::invokeClass($method[0]);
                $reflect = new \ReflectionMethod($class, $method[1]);
            } else {
                // 静态方法
                $reflect = new \ReflectionMethod($method);
            }
    
            $args = self::bindParams($reflect, $vars);
    
            self::$debug && Log::record('[ RUN ] ' . $reflect->class . '->' . $reflect->name . '[ ' . $reflect->getFileName() . ' ]', 'info');
    
            return $reflect->invokeArgs(isset($class) ? $class : null, $args);
        
        }
    

    15.调用反射执行类的实例化 支持依赖注入

     /**
         * 调用反射执行类的实例化 支持依赖注入
         * @access public
         * @param string $class 类名
         * @param array  $vars  变量
         * @return mixed
         */
        public static function invokeClass($class, $vars = [])
        {
            $reflect     = new \ReflectionClass($class);
            $constructor = $reflect->getConstructor();
            $args        = $constructor ? self::bindParams($constructor, $vars) : [];
    
            return $reflect->newInstanceArgs($args);
        }
    
    
    展开全文
  • 1.自动加载。2.配置文件。3.IOC容器及Facade。4.框架执行流程以及路由解读。 5.控制器解读等等,一共11章。如果链接失效或者没有积分还想学习,可以关注并私聊我
  • 如果开发者对框架底层源码有一定的了解,这个问题就很好解决。 为了解决这块的痛点并让大家对PHP以及底层框架有更深入的理解,singwa老师在本门课程为大家一步步分析ThinkPHP的底层源码,在分析的过程中,逐步提升...

    很多PHP工程师在工作中可以顺畅的使用TP框架进行业务开发,但当框架有升级或改动的时候就会不知所措。如果开发者对框架底层源码有一定的了解,这个问题就很好解决。 为了解决这块的痛点并让大家对PHP以及底层框架有更深入的理解,singwa老师在本门课程为大家一步步分析ThinkPHP的底层源码,在分析的过程中,逐步提升技术水平。轻松应对不同的TP版本和不同的框架,掌握课程所授内容,可基本达到百度T5的水平。

    适合人群

    工作经验2年以上的PHP开发

    希望提升PHP及相关框架开发水平的PHPer

    技术储备要求

    Linux基础

    PHP开发经验

    理解面向对象开发思想

    专题套餐

    全方位深度剖析PHP7底层源码

    TP6.0从0到1完整构建高并发电商服务系统

    辦法一:運用矩陣的(Kronecker) 積結構(Hadamard)矩陣

    定義2.1

    ​ 設(A=(a{ij}))爲一個(m\times p)的矩陣,(B=(b{ij}))爲一個(n\times q)矩陣,令:

    [A\times B=\begin{bmatrix} a{11}B & a{12}B & \dots & a{1p}B\ a{21}B & a{22}B & \dots & a{2p}B\ \vdots & \vdots & \ddots & \vdots\ a{m1}B & a{m2}B & \dots & a_{mp}B \end{bmatrix} ]

    這樣的方式(A\times B)被稱作爲直積,也被叫做(Kronecker)積

    引理

    設m爲一個常數,(A,A_1, A_2)爲(m\times p)矩陣,(B,B_1,B_2)爲(n\times q)的矩陣,C爲(p\times s)矩陣,D爲(q\times t)矩陣,則有下面這些定理的呈現

    [(1)m(A\times B)=(mA)\times B \ (2)A\times (B_1+ B_2)=A\times B_1 + A\times B_2\ (3)(A_1 + A_2)\times B = A_1 \times B + A_2\times B\ (4)(A\times B)^T=A^T \times B^T\ (5)(A\times B)(C\times D)=AC\times BD\ \ (這個與料想的不同) ]

    (1)~(4)顯然成立,如今證明(5)

    [A=\begin{bmatrix} a{11} & a{12} & \dots & a{1p}\ a{21} & a{22} & \dots & a{2p}\ \vdots& \vdots & \ddots & \vdots\ a{m1} & a{m2} & \dots & a{mp} \end{bmatrix}\ C=\begin{bmatrix} c{11} & c{12} & \dots & c{1s}\ c{21} & c{22} & \dots & c{2s}\ \vdots& \vdots & \ddots & \vdots\ c{p1} & c{p2} & \dots & c{ps} \end{bmatrix}\ (A\times B)(C\times D)=\begin{bmatrix} a{11}B & a{12}B & \dots & a{1p}B\ a{21}B & a{22}B & \dots & a{2p}B\ \vdots& \vdots & \ddots & \vdots\ a{m1}B & a{m2}B & \dots & a{mp}B \end{bmatrix}\begin{bmatrix} c{11}D & c{12}D& \dots & c{1s}D\ c{21}D & c{22}D & \dots & c{2s}D\ \vdots& \vdots & \ddots & \vdots\ c{p1}D & c{p2}D& \dots & c{ps}D \end{bmatrix}\ =\begin{bmatrix} \sum{i=1}^{p}a{1i}c{i1}BD & \sum{i=1}^{p}a{1i}c{i2}BD & \dots & \sum{i=1}^{p}a{1i}c{is}BD \ \vdots & \vdots & \dots & \vdots \ \sum{i=1}^{p}a{mi}c{i1}BD & \sum{i=1}^{p}a{mi}c{i2}BD & \dots & \sum{i=1}^{p}a{mi}c{is}BD \end{bmatrix}=(AC)\times (BD) ]

    所以不難證明這個定理是成立的。

    定理2.1

    設(H_1)與(H_2)分別爲(m)階與(n)階(H-矩陣),則(H_1 \times H_2)爲(mn)階(H-矩陣)

    證明:

    [\begin{eqnarray} (H_1\times H_2)(H_1\times H_2)^T && =(H_1\times H_2)(H_1^T\times H_2^T)\ && =(H_1H_1^T)\times (H_2H_2^T)\ && =(mI)\times (nI)\ && =mnI \end{eqnarray} ]

    推論1

    若H爲一個m階(H-矩陣),則(\begin{pmatrix}H & H\ H & -H\end{pmatrix})是一個2m階(H-矩陣)

    由於(H_2)是(\begin{pmatrix}1 & 1\ 1 & -1\end{pmatrix}),所以上述的結論顯然成立

    推論2

    恣意(t \geq 0, 2^i)階的(H-矩陣)都是一定存在的

    辦法二:應用矩陣的強直積結構(Hadamard)矩陣

    定義2.2.2 設(A)爲如下的(tm\times tm)矩陣

    [A= \begin{bmatrix} A{11} & A{12} & \dots & A{1t}\ A{21} & A{22} & \dots & A{2t}\ \vdots & \vdots & \ddots & \vdots\ A{t1} & A{t2} & \dots & A_{tt}\ \end{bmatrix}\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ A是一個m\times m階矩陣\ ]

    又設B爲如下的(tn\times tn)矩陣

    [B = \begin{bmatrix} B{11} & B{12} & \dots & B{1t}\ B{21} & B{22} & \dots & B{2t}\ \vdots & \vdots & \ddots & \vdots \ B{t1} & B{t2} & \dots & B_{tt}\ \end{bmatrix}\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ B是一個n\times n階矩陣 ]

    令下式成立:

    [A\otimes B=P= \begin{bmatrix} P{11} & P{12} & \dots & P{1t}\ P{21} & P{22} & \dots & P{2t}\ \vdots & \vdots & \ddots & \vdots \ P{t1} & P{t2} & \dots & P_{tt}\ \end{bmatrix} ]

    其中(P{ij}=\sum{k=1}^{t}A{ik}\times B{kj}(1\leq i, j\leq t))則稱(P)爲(A)與(B)的強直積

    元素換成矩陣的一種乘法

    引理2.2.2 定義2.2.2中(A)與(B)若滿足

    [AA^T=rI{tm};\ \ BB^T=sI{tm} ]

    [(A\otimes B)(A\otimes B)^T=rsI_{tmn} ]

    證明:設

    [(A\otimes B)(A\otimes B)^T= \begin{bmatrix} L{11} & L{12} & \dots & L{1t}\ L{21} & L{22} & \dots & L{2t}\ \vdots & \vdots & \ddots & \vdots\ L{t1} & L{t2} & \dots & L_{tt}\ \end{bmatrix} ]

    則有當(1\leq a, b \leq t),

    [\begin{eqnarray} L{ab} &&=\sum{k=1}^t(A{a1}\times B{1k} + A{a2}\times B{2k}+\dots+A{at}\times B{tk})(A{b1}^T\times B{1k}^T+A{b2}^T\times B{2k}^T+\dots + A{bt}^T\times B{tk}^T)\ &&=\sum{k=1}^{t}\sum{i=1}^{t}\sum{j=1}^{t}(A{ai}\times B{ik})(A{bj}^T\times B{jk}^T)\ &&=\sum{k=1}^{t}\sum{i=1}^{t}\sum{j=1}^{t}(A{ai}A{bj}^T)\times (B{ik}B{jk}^T)\ &&=\sum{k=1}^{t}\sum{i=1}^{t}(A{ai}A{bj}^T)\times\sum{j=1}^{t}(B{ik}B_{jk}^T) \end{eqnarray} ]

    剖析:

    [B{ik}B{jk}= \begin{cases} 0\ \ \ \ \ \ \ \ \ \ \ i\neq j\ sI_{n} \ \ \ \ \ \ \ i=j \end{cases} ]

    而:

    [A{ai}A{bj}= \begin{cases} 0\ \ \ \ \ \ \ \ \ \ \ a\neq b\ rI_{m} \ \ \ \ \ \ a=b \end{cases} ]

    則能夠晓得只要當(a=b)時分才有值不等於零,而這個值就是(rsImn), 證畢!

    定理2.2.2

    若(A)爲(2m)階的(H-矩陣),(B)爲(2n)階的(H-矩陣),則(2mn)階矩陣(H-矩陣)也必然存在。

    證明:

    [C=\frac{1}{2}A \begin{bmatrix} I_m & I_m\ I_m & -I_m \end{bmatrix} ]

    這麼設的目的完整是爲了結構

    則:

    [CC^T=\frac{1}{2}AA^TmI{2m}=mI{2m} ]

    易知:

    [BB^T=2nI_{2n} ]

    則經過引理晓得:

    [H=C\otimes B ]

    則:

    [HH^T=(C\otimes B)(C \otimes B)^T=2mnI_{2mn} ]

    所以說這個(2mn)階的(H-矩陣)一定存在的,證畢!

    辦法三: 應用反形(H-矩陣)和(H-矩陣)睦偶來結構(Hadamard)矩陣

    定義2.2.3

    若存在一個(H-矩陣)(H),滿足條件(H=S+I),(S^T=-S),則稱(H)是一個反形(H-矩陣)

    定義2.2.4

    若存在(H-矩陣)(H),若滿足(H^T=H),則稱(H-矩陣)是對稱(H-矩陣)

    定義2.2.5

    設(M)是一個反型(H-矩陣),(N)是一個同階的對稱(H-矩陣),假如滿足條件

    [MN=NM^T ]

    則稱(M)和(N)爲一對(Hadamard)矩陣睦偶,简稱一對(H-矩陣)睦偶

    也就是說這個MN矩陣是對稱矩陣

    定理2.2.3

    (1) (h)階反型(H-矩陣)(H=U+I);

    (2) (m)階(H-矩陣)睦偶(M=W+I), (N=N^T)

    (3)三個(l)(1, -1)矩陣(X,Y,Z)滿足

    [(XY^T)^T=XY^T, (YZ^T)^T=YZ^T,\ (ZX^T)^T=ZX^T,XX^T=aI+(l-a)J,\ YY^T=cI+(l-c)J,ZZ^T=(l+1)I-J; ]

    這里的,((m-1)c=m(l-h+1)-a),那麼矩陣

    [\overline{H}=U\times N\times Z + I_{n}\times W\times Y + I_n\times I_m \times X ]

    是一個(mlh)階的(H-矩陣)

    證明: 由(\overline{H})的結構式子可知,(\overline{H})是一個(1, -1)矩陣,另外一方面,由條件(1),(2)知:

    [U^T=-U,UU^T=(h-1)I_h;\W^T=-W,WW^T=(m-1)I_m\ MN=NM^T,MM^T=N^2=mI_m,WN=NW^T(下有简單證明) ]

    M,N都是兩個(Hadamard)矩陣,所以有(MM^T=NN^T=mI_m)

    [MN=NM^T\ (W+I)N=N(W+I)^T\ WN=NW^T\ ]

    ![VJV6CX3~CFFM1Y_1Z6TM84O.png]()

    所以這個(\overline{H})Hadamard矩陣存在

    Hadamard矩陣學習

    Hadamard矩陣引見就到這里

    ![image.png]()

    课後的一個習題

    假如說(Ax=0)那麼(A^TAx=0)所以說,(Ax=0)的解一定屬於(A^TAx=0)的解

    假如說(A^TAx=0),然後左右同時乘以(x^T)(\Rightarrow)(x^TA^TAx=0)(\Rightarrow)(||Ax||=0)也就是說這個(Ax=0)成立

    所以說這兩個矩陣(A^TA與A)矩陣同階

    假如說(A^2)與(A)具有同一個nullspace,那麼這個矩陣(A)一定就是方陣

    爲處理的問題:

    假如說N(A)是一個零向量,那麼也就是說這個(Ax=0)的列向量空間滿秩了,

    假如說B= (\begin{bmatrix}A & A & A\end{bmatrix})假如去找(Bx=0)的解,由於A曾經是列滿秩,那麼會多出來

    1.4 Elimination and (A = LU)

    高斯消變換元法: 只不過需求把變換矩陣寫出來

    (L)是一個變換矩陣(左下角三角矩陣),(U)是一個被變換矩陣(右上角三角矩陣)

    小小頭腦風暴

    前面學過的矩陣的合成,我們能夠晓得關於方程組(Ax=0)的解實践上是解的(A)的行向量空間的解,那麼我們天經地義的晓得(xA=0)的解是行空間的解。

    ![image.png]()

    運用之前學習的矩陣的(A=CMR)能夠對每一列的元素與之對應的行停止結構,使得一切的行與列都能夠結構出一個秩爲1的新矩陣,最後再加和起來就構成了矩陣的合成,有時分需求強調的是,矩陣合成過後不一定是兩個上下三角的矩陣,所以需求酌情停止行變換!留意是行變換

    這麼做的確是有點费事,我想要算矩陣的行列式,原本應該十分疾速(直接轉換稱爲上三角矩陣),但是這種辦法的益處在與把變換矩陣也順便存儲了下來,防止了矩陣行變換時分的變化招致的原矩陣與後來矩陣的不等關係

    ![image.png]()

    計算上類行列式公式:(|A|=a(b-a)(c-b)(d-c))也就是除了第一行元素以外的一切相對差值之積

    二次型的規範化的合同過程,由於對稱,所以兩個方向上的變換能夠由一個變換矩陣來描绘

    ![image.png]()

    關於選择矩陣拆分的時分,假如選择從左上角往右下角去拆,得到的將會是很規範的矩陣變換方式,但是假如從左下到右上角的變換,則會變成兩個不那麼規範的變換矩陣的乘積方式,所以引薦運用從左上到右下,也就是從第一行第一列開端變換

    1.5 Orthogonal Matrices and Subspaces

    左逆與右逆矩陣

    ![image.png]()

    ![image-20210118180049984]()

    關於左右僞逆矩陣,經過左右逆矩陣的方式結構出來的,例如左僞逆矩陣的(L=(A^TA)^{-1}A^H\Rightarrow (A^TA)^{-1}A^HA=I)

    顯然成立,這就是顯然成立

    實質上就是經過矩陣無法增維的想法,首先先結構一個滿秩的(n\times n)的矩陣空間,隨後逆過去,使得(A)作用於這個變換矩陣,最後得到我們的左僞逆。

    鏇轉矩陣與反射矩陣

    展开全文
  • 如果开发者对框架底层源码有一定的了解,这个问题就很好解决。为了解决这块的痛点并让大家对PHP以及底层框架有更深入的理解,singwa老师在本门课程为大家一步步分析ThinkPHP的底层源码,在分析的过程中,逐步提升...

    〖课程介绍〗

    很多PHP工程师在工作中可以顺畅的使用TP框架进行业务开发,但当框架有升级或改动的时候就会不知所措。如果开发者对框架底层源码有一定的了解,这个问题就很好解决。

    为了解决这块的痛点并让大家对PHP以及底层框架有更深入的理解,singwa老师在本门课程为大家一步步分析ThinkPHP的底层源码,在分析的过程中,逐步提升技术水平。轻松应对不同的TP版本和不同的框架,掌握课程所授内容,可基本达到百度T5的水平。

    〖课程目录〗

    第1章

    课程简介(一定要看,知道整体介绍,方能更好的学习后续课程)

    本章主要让大家知道本套课程的主线,

    导学内容,如何学习源码等,看完本章要让小伙伴觉得这个是必须要掌握的,并且对加薪有很大的帮助。

    1-1

    【必看小节,欢迎在问答区和QQ群与老师互动,祝您学习愉快】面试必备,加薪首选课 试看

    1-2

    【选择TP框架分析的原因】为什么要学习框架源码

    1-3

    【高效学习方法的指导】如何高效的学习框架源码

    1-4

    【让你不再纠结选择TP5还是TP6】版本要求以及框架获取和安装

    第2章 【TP5灵魂】自动加载Loader

    深度分析(重点章节,请认真听,建议多次回听)6 a& q# k1 b, B8 H6 v3 t

    本章主要讲解为什么要学习自动加载,带领大家看看TP框架的执行流程是什么样子。学习自动加载的原理以及TP5内部自动加载的代码分析、TP

    结合composer相关的加载逻辑注册类库相关别名如何处理最后带领大家做实战,巩固学过的知识。

    2-1

    【学习框架的第一步】类自动加载初始

    2-2

    【注册系统自动加载】spl_autoload_register初学习

    2-3

    【属性深度剖析】自动加载Loader深度分析

    2-4

    【类的别名设置】自动加载Loader深度分析

    2-5

    【类的自动加载】自动加载Loader深度分析

    2-6

    【实战】在框架中新增自定义类

    2-7

    【实战】composer下类的自动加载

    第3章 【你必须要掌握的配置文件】解读配置文件

    本章主要讲解配置文件的重要性、PHP底层

    arrayaccess类分析、如何高效管理配置文件,引入高性能配置文件,相关安装、类库分析、设置、获取相关的底层类库分析以及其他内容分析、最后给出一个具体的小实战,让大家真正意义理解配置。

    ...

    3-1

    【配置文件的种类】配置文件概述

    3-2

    【你应该掌握的底层】PHP底层ArrayAccess类巧用分析

    3-3

    【引入高性能Yaconf的原因】性能体现

    3-4

    【高性能配置的扩展】高性能yaconf编译安装

    3-5

    【Config底层类库分析一】load加载深度分析

    3-6

    【Config底层类库分析二】load加载深度分析

    3-7

    【yaml初体验】TP框架底层优化

    3-8

    【让代码更加优雅】config底层类库优化 试看

    3-9

    【config类库】其他内容源码分析

    第4章 TP5 IOC容器及Facade

    深度解析(掌握核心类库的使用,挑战高薪)

    本章主要讲解为什么要了解容器以及façade、如何理解他们、容器底层类库解析以及容器的具体实战

    4-1 【你必须要会的设计模式

    】单例模式

    4-2 【你应该掌握的设计模式

    】注册树模式

    4-3

    【提升内功】如何理解依赖注入和控制反转

    4-4

    【必学反射机制】PHP反射机制深入学习一

    4-5

    【必会反射机制】PHP反射机制深入学习二

    4-6

    【给你机会来玩】玩转自己的容器类9 ]

    4-7

    【Container容器类剖析】Countable巧用

    4-8

    【Container容器类剖析】获取容器里面的实例分析 试看

    4-9

    【实战】Container容器类实战

    4-10

    【门面模式Facade】类库分析

    4-11

    【门面模式Facade】 图例分析

    4-12 【门面模式Facade

    实战】让小伙伴真正意义理解门面模式

    4-13 【总结】本章小节

    第5章 【重点章节】框架执行流程以及路由解读

    本章主要先分析框架执行流程再分析什么是路由,路由可以帮大家解决什么问题,为什么要学习他、rule相关类库分析、route底层类库深度分析、资源路由分析最后实战让大家彻底理解路由。

    5-1

    【框架执行流程】初始化应用的数据设置

    5-2

    【框架执行流程初始化应用init分析】多次初始化解刨

    5-3

    框架执行流程初始化应用init分析 - 加载相关文件深度分析

    5-4

    框架执行流程初始化应用init分析 - 场景分析

    5-5

    对容器中的对象实例进行配置更新

    5-6

    调试模式以及代码冗余细讲

    5-7 路由初始化简单分析

    第6章 【如何轻松掌握控制器灵魂】控制器解读

    本章主要分析框架如何能找到业务模块下的控制器,让大家知道其中的奥妙、TP注册控制器中间件的分析和讲解、初始化分析、路由初始化解析、最终执行程序分析、php特性分析以及注册控制器中间件分析等。

    第7章

    【重点章节,建议多回听】模型以及视图层深度解读#

    本章主要讲解数据库如何链接、原始DB类库分析、模型数据转换处理解刨、模型数据驱动处理解刨、模型关联处理、标签库TagLib解析基类

    深度分析、CX标签库解析类深度分析,最终会带领大家实战。

    第8章

    【其他核心类库解读】异常处理、缓存(重点章节,不多看都不好意思说听明白)

    本章主要讲解核心类库异常处理、缓存等,让大家明白异常处理的机制到底是什么,缓存到底如何工作,让大家彻底掌握并提高工作效率。

    第9章 【课程升级】 Tp6版本剖析

    本章重点讲解TP6版本,让大家尝鲜感受到TP6带来的变化,同时和TP5作对比,让大家学习新技术,拥抱潮流,为跳槽面试储备存量。

    第10章 框架层面的面试技巧(教你轻轻松松搞定面试官,拿下offer

    )

    本章重点讲解框架层面的面试技巧,框架面试需要注意的内容以及如何在面试官面前表露核心技术点,让你掌握各种面试技巧,顺利通过面试,拿下offer。

    第11章 【高价值个人成长经验分享】课程总结

    本章主要给大家分享高价值的个人成长经验,尤其是工作中的经验,希望大家有所收获,并将其应用在自己的工作中,提高个人技术能力,让大家在互联网时代Y拥有硬本领,最后做课程总结。

    展开全文
  • tp5源码分析之视图

    2018-02-23 17:41:33
    视图可以用来存储模板变量最终调用模板引擎 将(模板变量) 与 (模板文件)解析为输出的Web界面View::instance()单例模式,创建全局唯一的视图对象public static function instance($engine = [], $replace = []) ...
  • tp5源码分析之模板标签库

    千次阅读 2018-02-23 17:43:12
    1 标签库标签库,可以用来自定义模板文件中的标签解析方式在tp5中自定义了内置标签库(Cx.php)$taglib-&gt;__construct()标签库构造函数,创建标签库对象public function __construct($template) { $this-&...
  • 跟着源码课程5-8学习,学到App类初始化$this->initialize( )方法的时候,其中有一步是加载route目录下的route.php文件,发现这个文件里面可以调用:Route::get("test","test/index");Route::post("test","test/index...
  • 前言tp5的数据库操作全部通过Db类完成,比较符合国人的习惯,比如...select(),下面就通过源码来了解其工作流程看代码之前,先看看涉及到的类都有哪些,tp5的数据库相关的类有以下几个:Db(用户接口)Connection...
  • 第2章 【TP5灵魂】自动加载Loader 深度分析(重点章节,请认真听,建议多次回听) 1.关于PHP中spl_autoload_register()函数用法详解 https://www.php.cn/php-weizijiaocheng-400053.html

空空如也

空空如也

1 2 3
收藏数 50
精华内容 20
关键字:

tp5源码解析