-
tp5:thinkphp5源码解析-源码
2021-03-23 02:27:57thinkphp5源码解析 -
第三方素材解析源码,素材解析源码,tp5内核。
2020-01-11 20:15:42第三方素材解析源码分享给大家伙儿,仅限于研究哈。我也是朋友分享给我的。喜欢的自己拿走研究,tp内核。 -
TP5 源码分析-App类里面的$this解析
2020-12-03 20:14:02这个类里面有很这样的使用例如$this->hook->import(); $this->config->get(); $this->request->init();等等 你知道这个对象怎么来的吗?不急,亮仔一一道来: ...app类会继承容器Container(这是关键...这个类里面有很这样的使用例如$this->hook->import(); $this->config->get(); $this->request->init();等等
你知道这个对象怎么来的吗?不急,亮仔一一道来:- app类会继承容器Container(这是关键)
- 容器有个魔术方法很重要 例如当调用$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:285.设置路由规则 /** * 设置路由规则 * @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); }
-
-
PHP开发晋升课程 BAT资深工程师解析Tp5+Tp6底层源码
2020-05-05 08:07:401.自动加载。2.配置文件。3.IOC容器及Facade。4.框架执行流程以及路由解读。 5.控制器解读等等,一共11章。如果链接失效或者没有积分还想学习,可以关注并私聊我 -
php工程师做的tp架构,PHP开发晋升课程 BAT资深工程师解析Tp5+Tp6底层源码
2021-03-23 23:12:48如果开发者对框架底层源码有一定的了解,这个问题就很好解决。 为了解决这块的痛点并让大家对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工程师做的tp架构,PHP开发晋升课程BAT资深工程师解析Tp5+Tp6底层源码
2021-03-23 23:13:03如果开发者对框架底层源码有一定的了解,这个问题就很好解决。为了解决这块的痛点并让大家对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:121 标签库标签库,可以用来自定义模板文件中的标签解析方式在tp5中自定义了内置标签库(Cx.php)$taglib->__construct()标签库构造函数,创建标签库对象public function __construct($template) { $this-&... -
thinkphp加载route.php,Tp5源码5-8章节route.php中Route::get( )形式类静态访问方法解析
2021-03-30 08:15:31跟着源码课程5-8学习,学到App类初始化$this->initialize( )方法的时候,其中有一步是加载route目录下的route.php文件,发现这个文件里面可以调用:Route::get("test","test/index");Route::post("test","test/index... -
thinkphp5源码解析(1)数据库
2017-12-13 16:19:02前言tp5的数据库操作全部通过Db类完成,比较符合国人的习惯,比如...select(),下面就通过源码来了解其工作流程看代码之前,先看看涉及到的类都有哪些,tp5的数据库相关的类有以下几个:Db(用户接口)Connection... -
[Singwa]PHP开发晋升课程 BAT资深工程师解析Tp5.1+Tp6底层源码,反射
2021-01-05 17:57:21第2章 【TP5灵魂】自动加载Loader 深度分析(重点章节,请认真听,建议多次回听) 1.关于PHP中spl_autoload_register()函数用法详解 https://www.php.cn/php-weizijiaocheng-400053.html