From 35e763c8ff70f8b5bfb2978db064edd19c9de03a Mon Sep 17 00:00:00 2001 From: Lin07ux Date: Sun, 5 Nov 2017 15:21:42 +0800 Subject: [PATCH] =?UTF-8?q?=E6=A0=BC=E5=BC=8F=E5=8C=96=20start=E3=80=81bas?= =?UTF-8?q?e=E3=80=81traits=20=E5=92=8C=20App=E3=80=81Config=E3=80=81Error?= =?UTF-8?q?=E3=80=81Loader=20=E4=BB=A3=E7=A0=81=E7=9A=84=E6=A0=B7=E5=BC=8F?= =?UTF-8?q?=E3=80=82=E5=85=B6=E4=BB=96=E4=BB=A3=E7=A0=81=E7=9A=84=E6=A0=B7?= =?UTF-8?q?=E5=BC=8F=E5=BE=85=E5=A4=84=E7=90=86=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- base.php | 2 + library/think/App.php | 419 ++++++++++++++++------------ library/think/Config.php | 161 ++++++----- library/think/Error.php | 72 ++--- library/think/Loader.php | 343 +++++++++++++---------- library/traits/controller/Jump.php | 87 +++--- library/traits/model/SoftDelete.php | 73 +++-- library/traits/think/Instance.php | 33 ++- start.php | 5 +- 9 files changed, 682 insertions(+), 513 deletions(-) diff --git a/base.php b/base.php index 1819d72e..465500ce 100644 --- a/base.php +++ b/base.php @@ -40,8 +40,10 @@ require CORE_PATH . 'Loader.php'; // 加载环境变量配置文件 if (is_file(ROOT_PATH . '.env')) { $env = parse_ini_file(ROOT_PATH . '.env', true); + foreach ($env as $key => $val) { $name = ENV_PREFIX . strtoupper($key); + if (is_array($val)) { foreach ($val as $k => $v) { $item = $name . '_' . strtoupper($k); diff --git a/library/think/App.php b/library/think/App.php index 615be241..6389e74e 100644 --- a/library/think/App.php +++ b/library/think/App.php @@ -18,7 +18,7 @@ use think\exception\RouteNotFoundException; /** * App 应用管理 - * @author liu21st + * @author liu21st */ class App { @@ -57,24 +57,32 @@ class App */ protected static $routeMust; + /** + * @var array 请求调度分发 + */ protected static $dispatch; + + /** + * @var array 额外加载文件 + */ protected static $file = []; /** * 执行应用程序 * @access public - * @param Request $request Request对象 + * @param Request $request 请求对象 * @return Response * @throws Exception */ public static function run(Request $request = null) { - is_null($request) && $request = Request::instance(); + $request = is_null($request) ? Request::instance() : $request; try { $config = self::initCommon(); + + // 模块/控制器绑定 if (defined('BIND_MODULE')) { - // 模块/控制器绑定 BIND_MODULE && Route::bind(BIND_MODULE); } elseif ($config['auto_bind_module']) { // 入口自动绑定 @@ -88,10 +96,8 @@ class App // 默认语言 Lang::range($config['default_lang']); - if ($config['lang_switch_on']) { - // 开启多语言机制 检测当前语言 - Lang::detect(); - } + // 开启多语言机制 检测当前语言 + $config['lang_switch_on'] && Lang::detect(); $request->langset(Lang::range()); // 加载系统语言包 @@ -102,10 +108,11 @@ class App // 获取应用调度信息 $dispatch = self::$dispatch; + // 未设置调度信息则进行 URL 路由检测 if (empty($dispatch)) { - // 进行URL路由检测 $dispatch = self::routeCheck($request, $config); } + // 记录当前调度信息 $request->dispatch($dispatch); @@ -116,10 +123,15 @@ class App Log::record('[ PARAM ] ' . var_export($request->param(), true), 'info'); } - // 监听app_begin + // 监听 app_begin Hook::listen('app_begin', $dispatch); + // 请求缓存检查 - $request->cache($config['request_cache'], $config['request_cache_expire'], $config['request_cache_except']); + $request->cache( + $config['request_cache'], + $config['request_cache_expire'], + $config['request_cache_except'] + ); $data = self::exec($dispatch, $config); } catch (HttpResponseException $exception) { @@ -134,24 +146,144 @@ class App $response = $data; } elseif (!is_null($data)) { // 默认自动识别响应输出类型 - $isAjax = $request->isAjax(); - $type = $isAjax ? Config::get('default_ajax_return') : Config::get('default_return_type'); + $type = $request->isAjax() ? + Config::get('default_ajax_return') : + Config::get('default_return_type'); + $response = Response::create($data, $type); } else { $response = Response::create(); } - // 监听app_end + // 监听 app_end Hook::listen('app_end', $response); return $response; } + /** + * 初始化应用,并返回配置信息 + * @access public + * @return mixed + */ + public static function initCommon() + { + if (empty(self::$init)) { + if (defined('APP_NAMESPACE')) self::$namespace = APP_NAMESPACE; + + Loader::addNamespace(self::$namespace, APP_PATH); + + // 初始化应用 + $config = self::init(); + self::$suffix = $config['class_suffix']; + + // 应用调试模式 + self::$debug = Env::get('app_debug', Config::get('app_debug')); + + if (!self::$debug) { + ini_set('display_errors', 'Off'); + } elseif (!IS_CLI) { + // 重新申请一块比较大的 buffer + if (ob_get_level() > 0) $output = ob_get_clean(); + + ob_start(); + + if (!empty($output)) echo $output; + } + + if (!empty($config['root_namespace'])) { + Loader::addNamespace($config['root_namespace']); + } + + // 加载额外文件 + if (!empty($config['extra_file_list'])) { + foreach ($config['extra_file_list'] as $file) { + $file = strpos($file, '.') ? $file : APP_PATH . $file . EXT; + if (is_file($file) && !isset(self::$file[$file])) { + include $file; + self::$file[$file] = true; + } + } + } + + // 设置系统时区 + date_default_timezone_set($config['default_timezone']); + + // 监听 app_init + Hook::listen('app_init'); + + self::$init = true; + } + + return Config::get(); + } + + /** + * 初始化应用或模块 + * @access public + * @param string $module 模块名 + * @return array + */ + private static function init($module = '') + { + // 定位模块目录 + $module = $module ? $module . DS : ''; + + // 加载初始化文件 + if (is_file(APP_PATH . $module . 'init' . EXT)) { + include APP_PATH . $module . 'init' . EXT; + } elseif (is_file(RUNTIME_PATH . $module . 'init' . EXT)) { + include RUNTIME_PATH . $module . 'init' . EXT; + } else { + // 加载模块配置 + $config = Config::load(CONF_PATH . $module . 'config' . CONF_EXT); + + // 读取数据库配置文件 + $filename = CONF_PATH . $module . 'database' . CONF_EXT; + Config::load($filename, 'database'); + + // 读取扩展配置文件 + if (is_dir(CONF_PATH . $module . 'extra')) { + $dir = CONF_PATH . $module . 'extra'; + $files = scandir($dir); + foreach ($files as $file) { + if ('.' . pathinfo($file, PATHINFO_EXTENSION) === CONF_EXT) { + $filename = $dir . DS . $file; + Config::load($filename, pathinfo($file, PATHINFO_FILENAME)); + } + } + } + + // 加载应用状态配置 + if ($config['app_status']) { + Config::load(CONF_PATH . $module . $config['app_status'] . CONF_EXT); + } + + // 加载行为扩展文件 + if (is_file(CONF_PATH . $module . 'tags' . EXT)) { + Hook::import(include CONF_PATH . $module . 'tags' . EXT); + } + + // 加载公共文件 + $path = APP_PATH . $module; + if (is_file($path . 'common' . EXT)) { + include $path . 'common' . EXT; + } + + // 加载当前模块语言包 + if ($module) { + Lang::load($path . 'lang' . DS . Request::instance()->langset() . EXT); + } + } + + return Config::get(); + } + /** * 设置当前请求的调度信息 * @access public * @param array|string $dispatch 调度信息 - * @param string $type 调度类型 + * @param string $type 调度类型 * @return void */ public static function dispatch($dispatch, $type = 'module') @@ -170,8 +302,10 @@ class App { $reflect = new \ReflectionFunction($function); $args = self::bindParams($reflect, $vars); + // 记录执行信息 self::$debug && Log::record('[ RUN ] ' . $reflect->__toString(), 'info'); + return $reflect->invokeArgs($args); } @@ -191,28 +325,27 @@ class App // 静态方法 $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); } /** * 调用反射执行类的实例化 支持依赖注入 * @access public - * @param string $class 类名 - * @param array $vars 变量 + * @param string $class 类名 + * @param array $vars 变量 * @return mixed */ public static function invokeClass($class, $vars = []) { - $reflect = new \ReflectionClass($class); + $reflect = new \ReflectionClass($class); $constructor = $reflect->getConstructor(); - if ($constructor) { - $args = self::bindParams($constructor, $vars); - } else { - $args = []; - } + $args = $constructor ? self::bindParams($constructor, $vars) : []; + return $reflect->newInstanceArgs($args); } @@ -225,52 +358,58 @@ class App */ private static function bindParams($reflect, $vars = []) { + // 自动获取请求变量 if (empty($vars)) { - // 自动获取请求变量 - if (Config::get('url_param_type')) { - $vars = Request::instance()->route(); - } else { - $vars = Request::instance()->param(); - } + $vars = Config::get('url_param_type') ? + Request::instance()->route() : + Request::instance()->param(); } + $args = []; if ($reflect->getNumberOfParameters() > 0) { // 判断数组类型 数字数组时按顺序绑定参数 reset($vars); $type = key($vars) === 0 ? 1 : 0; - $params = $reflect->getParameters(); - foreach ($params as $param) { + + foreach ($reflect->getParameters() as $param) { $args[] = self::getParamValue($param, $vars, $type); } } + return $args; } /** * 获取参数值 * @access private - * @param \ReflectionParameter $param - * @param array $vars 变量 - * @param string $type + * @param \ReflectionParameter $param 参数 + * @param array $vars 变量 + * @param string $type 类别 * @return array */ private static function getParamValue($param, &$vars, $type) { $name = $param->getName(); $class = $param->getClass(); + if ($class) { $className = $class->getName(); $bind = Request::instance()->$name; + if ($bind instanceof $className) { $result = $bind; } else { if (method_exists($className, 'invoke')) { $method = new \ReflectionMethod($className, 'invoke'); + if ($method->isPublic() && $method->isStatic()) { return $className::invoke(Request::instance()); } } - $result = method_exists($className, 'instance') ? $className::instance() : new $className; + + $result = method_exists($className, 'instance') ? + $className::instance() : + new $className; } } elseif (1 == $type && !empty($vars)) { $result = array_shift($vars); @@ -281,65 +420,83 @@ class App } else { throw new \InvalidArgumentException('method param miss:' . $name); } + return $result; } + /** + * 执行调用分发 + * @access protected + * @param array $dispatch 调用信息 + * @param array $config 配置信息 + * @return Response|mixed + * @throws \InvalidArgumentException + */ protected static function exec($dispatch, $config) { switch ($dispatch['type']) { - case 'redirect': - // 执行重定向跳转 - $data = Response::create($dispatch['url'], 'redirect')->code($dispatch['status']); + case 'redirect': // 重定向跳转 + $data = Response::create($dispatch['url'], 'redirect') + ->code($dispatch['status']); break; - case 'module': - // 模块/控制器/操作 - $data = self::module($dispatch['module'], $config, isset($dispatch['convert']) ? $dispatch['convert'] : null); + case 'module': // 模块/控制器/操作 + $data = self::module( + $dispatch['module'], + $config, + isset($dispatch['convert']) ? $dispatch['convert'] : null + ); break; - case 'controller': - // 执行控制器操作 + case 'controller': // 执行控制器操作 $vars = array_merge(Request::instance()->param(), $dispatch['var']); - $data = Loader::action($dispatch['controller'], $vars, $config['url_controller_layer'], $config['controller_suffix']); + $data = Loader::action( + $dispatch['controller'], + $vars, + $config['url_controller_layer'], + $config['controller_suffix'] + ); break; - case 'method': - // 执行回调方法 + case 'method': // 回调方法 $vars = array_merge(Request::instance()->param(), $dispatch['var']); $data = self::invokeMethod($dispatch['method'], $vars); break; - case 'function': - // 执行闭包 + case 'function': // 闭包 $data = self::invokeFunction($dispatch['function']); break; - case 'response': + case 'response': // Response 实例 $data = $dispatch['response']; break; default: throw new \InvalidArgumentException('dispatch type not support'); } + return $data; } /** * 执行模块 * @access public - * @param array $result 模块/控制器/操作 - * @param array $config 配置参数 + * @param array $result 模块/控制器/操作 + * @param array $config 配置参数 * @param bool $convert 是否自动转换控制器和操作名 * @return mixed + * @throws HttpException */ public static function module($result, $config, $convert = null) { - if (is_string($result)) { - $result = explode('/', $result); - } + if (is_string($result)) $result = explode('/', $result); + $request = Request::instance(); + if ($config['app_multi_module']) { // 多模块部署 - $module = strip_tags(strtolower($result[0] ?: $config['default_module'])); - $bind = Route::getBind('module'); + $module = strip_tags(strtolower($result[0] ?: $config['default_module'])); + $bind = Route::getBind('module'); $available = false; + if ($bind) { // 绑定模块 list($bindModule) = explode('/', $bind); + if (empty($result[0])) { $module = $bindModule; $available = true; @@ -355,8 +512,13 @@ class App // 初始化模块 $request->module($module); $config = self::init($module); + // 模块请求缓存检查 - $request->cache($config['request_cache'], $config['request_cache_expire'], $config['request_cache_except']); + $request->cache( + $config['request_cache'], + $config['request_cache_expire'], + $config['request_cache_except'] + ); } else { throw new HttpException(404, 'module not exists:' . $module); } @@ -365,11 +527,13 @@ class App $module = ''; $request->module($module); } + // 当前模块路径 App::$modulePath = APP_PATH . ($module ? $module . DS : ''); // 是否自动转换控制器和操作名 $convert = is_bool($convert) ? $convert : $config['url_convert']; + // 获取控制器名 $controller = strip_tags($result[1] ?: $config['default_controller']); $controller = $convert ? strtolower($controller) : $controller; @@ -385,7 +549,12 @@ class App Hook::listen('module_init', $request); try { - $instance = Loader::controller($controller, $config['url_controller_layer'], $config['controller_suffix'], $config['empty_controller']); + $instance = Loader::controller( + $controller, + $config['url_controller_layer'], + $config['controller_suffix'], + $config['empty_controller'] + ); } catch (ClassNotFoundException $e) { throw new HttpException(404, 'controller not exists:' . $e->getClass()); } @@ -411,125 +580,11 @@ class App return self::invokeMethod($call, $vars); } - /** - * 初始化应用 - */ - public static function initCommon() - { - if (empty(self::$init)) { - if (defined('APP_NAMESPACE')) { - self::$namespace = APP_NAMESPACE; - } - Loader::addNamespace(self::$namespace, APP_PATH); - - // 初始化应用 - $config = self::init(); - self::$suffix = $config['class_suffix']; - - // 应用调试模式 - self::$debug = Env::get('app_debug', Config::get('app_debug')); - if (!self::$debug) { - ini_set('display_errors', 'Off'); - } elseif (!IS_CLI) { - //重新申请一块比较大的buffer - if (ob_get_level() > 0) { - $output = ob_get_clean(); - } - ob_start(); - if (!empty($output)) { - echo $output; - } - } - - if (!empty($config['root_namespace'])) { - Loader::addNamespace($config['root_namespace']); - } - - // 加载额外文件 - if (!empty($config['extra_file_list'])) { - foreach ($config['extra_file_list'] as $file) { - $file = strpos($file, '.') ? $file : APP_PATH . $file . EXT; - if (is_file($file) && !isset(self::$file[$file])) { - include $file; - self::$file[$file] = true; - } - } - } - - // 设置系统时区 - date_default_timezone_set($config['default_timezone']); - - // 监听app_init - Hook::listen('app_init'); - - self::$init = true; - } - return Config::get(); - } - - /** - * 初始化应用或模块 - * @access public - * @param string $module 模块名 - * @return array - */ - private static function init($module = '') - { - // 定位模块目录 - $module = $module ? $module . DS : ''; - - // 加载初始化文件 - if (is_file(APP_PATH . $module . 'init' . EXT)) { - include APP_PATH . $module . 'init' . EXT; - } elseif (is_file(RUNTIME_PATH . $module . 'init' . EXT)) { - include RUNTIME_PATH . $module . 'init' . EXT; - } else { - $path = APP_PATH . $module; - // 加载模块配置 - $config = Config::load(CONF_PATH . $module . 'config' . CONF_EXT); - // 读取数据库配置文件 - $filename = CONF_PATH . $module . 'database' . CONF_EXT; - Config::load($filename, 'database'); - // 读取扩展配置文件 - if (is_dir(CONF_PATH . $module . 'extra')) { - $dir = CONF_PATH . $module . 'extra'; - $files = scandir($dir); - foreach ($files as $file) { - if ('.' . pathinfo($file, PATHINFO_EXTENSION) === CONF_EXT) { - $filename = $dir . DS . $file; - Config::load($filename, pathinfo($file, PATHINFO_FILENAME)); - } - } - } - - // 加载应用状态配置 - if ($config['app_status']) { - $config = Config::load(CONF_PATH . $module . $config['app_status'] . CONF_EXT); - } - - // 加载行为扩展文件 - if (is_file(CONF_PATH . $module . 'tags' . EXT)) { - Hook::import(include CONF_PATH . $module . 'tags' . EXT); - } - - // 加载公共文件 - if (is_file($path . 'common' . EXT)) { - include $path . 'common' . EXT; - } - - // 加载当前模块语言包 - if ($module) { - Lang::load($path . 'lang' . DS . Request::instance()->langset() . EXT); - } - } - return Config::get(); - } - /** * URL路由检测(根据PATH_INFO) * @access public - * @param \think\Request $request - * @param array $config + * @param \think\Request $request 请求实例 + * @param array $config 配置信息 * @return array * @throws \think\Exception */ @@ -538,6 +593,7 @@ class App $path = $request->path(); $depr = $config['pathinfo_depr']; $result = false; + // 路由检测 $check = !is_null(self::$routeCheck) ? self::$routeCheck : $config['url_route_on']; if ($check) { @@ -545,34 +601,33 @@ class App if (is_file(RUNTIME_PATH . 'route.php')) { // 读取路由缓存 $rules = include RUNTIME_PATH . 'route.php'; - if (is_array($rules)) { - Route::rules($rules); - } + is_array($rules) && Route::rules($rules); } else { $files = $config['route_config_file']; foreach ($files as $file) { if (is_file(CONF_PATH . $file . CONF_EXT)) { // 导入路由配置 $rules = include CONF_PATH . $file . CONF_EXT; - if (is_array($rules)) { - Route::import($rules); - } + is_array($rules) && Route::import($rules); } } } // 路由检测(根据路由定义返回不同的URL调度) $result = Route::check($request, $path, $depr, $config['url_domain_deploy']); - $must = !is_null(self::$routeMust) ? self::$routeMust : $config['url_route_must']; + $must = !is_null(self::$routeMust) ? self::$routeMust : $config['url_route_must']; + if ($must && false === $result) { // 路由无效 throw new RouteNotFoundException(); } } + + // 路由无效 解析模块/控制器/操作/参数... 支持控制器自动搜索 if (false === $result) { - // 路由无效 解析模块/控制器/操作/参数... 支持控制器自动搜索 $result = Route::parseUrl($path, $depr, $config['controller_auto_search']); } + return $result; } diff --git a/library/think/Config.php b/library/think/Config.php index 1fa5d4af..6e690f0a 100644 --- a/library/think/Config.php +++ b/library/think/Config.php @@ -13,70 +13,84 @@ namespace think; class Config { - // 配置参数 + /** + * @var array 配置参数 + */ private static $config = []; - // 参数作用域 + + /** + * @var string 参数作用域 + */ private static $range = '_sys_'; - // 设定配置参数的作用域 + /** + * 设定配置参数的作用域 + * @param string $range 作用域 + * @return void + */ public static function range($range) { self::$range = $range; - if (!isset(self::$config[$range])) { - self::$config[$range] = []; - } + + if (!isset(self::$config[$range])) self::$config[$range] = []; } /** * 解析配置文件或内容 - * @param string $config 配置文件路径或内容 - * @param string $type 配置解析类型 - * @param string $name 配置名(如设置即表示二级配置) - * @param string $range 作用域 + * @param string $config 配置文件路径或内容 + * @param string $type 配置解析类型 + * @param string $name 配置名(如设置即表示二级配置) + * @param string $range 作用域 * @return mixed */ public static function parse($config, $type = '', $name = '', $range = '') { $range = $range ?: self::$range; - if (empty($type)) { - $type = pathinfo($config, PATHINFO_EXTENSION); - } - $class = false !== strpos($type, '\\') ? $type : '\\think\\config\\driver\\' . ucwords($type); + + if (empty($type)) $type = pathinfo($config, PATHINFO_EXTENSION); + + $class = false !== strpos($type, '\\') ? + $type : + '\\think\\config\\driver\\' . ucwords($type); + return self::set((new $class())->parse($config), $name, $range); } /** * 加载配置文件(PHP格式) - * @param string $file 配置文件名 - * @param string $name 配置名(如设置即表示二级配置) - * @param string $range 作用域 + * @param string $file 配置文件名 + * @param string $name 配置名(如设置即表示二级配置) + * @param string $range 作用域 * @return mixed */ public static function load($file, $name = '', $range = '') { $range = $range ?: self::$range; - if (!isset(self::$config[$range])) { - self::$config[$range] = []; - } + + if (!isset(self::$config[$range])) self::$config[$range] = []; + if (is_file($file)) { $name = strtolower($name); $type = pathinfo($file, PATHINFO_EXTENSION); + if ('php' == $type) { return self::set(include $file, $name, $range); - } elseif ('yaml' == $type && function_exists('yaml_parse_file')) { - return self::set(yaml_parse_file($file), $name, $range); - } else { - return self::parse($file, $type, $name, $range); } - } else { - return self::$config[$range]; + + if ('yaml' == $type && function_exists('yaml_parse_file')) { + return self::set(yaml_parse_file($file), $name, $range); + } + + return self::parse($file, $type, $name, $range); } + + return self::$config[$range]; } /** * 检测配置是否存在 - * @param string $name 配置参数名(支持二级配置 .号分割) - * @param string $range 作用域 + * @param string $name 配置参数名(支持二级配置 . 号分割) + * @param string $range 作用域 * @return bool */ public static function has($name, $range = '') @@ -85,90 +99,105 @@ class Config if (!strpos($name, '.')) { return isset(self::$config[$range][strtolower($name)]); - } else { - // 二维数组设置和获取支持 - $name = explode('.', $name, 2); - return isset(self::$config[$range][strtolower($name[0])][$name[1]]); } + + // 二维数组设置和获取支持 + $name = explode('.', $name, 2); + return isset(self::$config[$range][strtolower($name[0])][$name[1]]); } /** * 获取配置参数 为空则获取所有配置 - * @param string $name 配置参数名(支持二级配置 .号分割) - * @param string $range 作用域 + * @param string $name 配置参数名(支持二级配置 . 号分割) + * @param string $range 作用域 * @return mixed */ public static function get($name = null, $range = '') { $range = $range ?: self::$range; + // 无参数时获取所有 if (empty($name) && isset(self::$config[$range])) { return self::$config[$range]; } + // 非二级配置时直接返回 if (!strpos($name, '.')) { $name = strtolower($name); return isset(self::$config[$range][$name]) ? self::$config[$range][$name] : null; - } else { - // 二维数组设置和获取支持 - $name = explode('.', $name, 2); - $name[0] = strtolower($name[0]); - - if (!isset(self::$config[$range][$name[0]])) { - // 动态载入额外配置 - $module = Request::instance()->module(); - $file = CONF_PATH . ($module ? $module . DS : '') . 'extra' . DS . $name[0] . CONF_EXT; - - is_file($file) && self::load($file, $name[0]); - } - - return isset(self::$config[$range][$name[0]][$name[1]]) ? self::$config[$range][$name[0]][$name[1]] : null; } + + // 二维数组设置和获取支持 + $name = explode('.', $name, 2); + $name[0] = strtolower($name[0]); + + if (!isset(self::$config[$range][$name[0]])) { + // 动态载入额外配置 + $module = Request::instance()->module(); + $file = CONF_PATH . ($module ? $module . DS : '') . 'extra' . DS . $name[0] . CONF_EXT; + + is_file($file) && self::load($file, $name[0]); + } + + return isset(self::$config[$range][$name[0]][$name[1]]) ? + self::$config[$range][$name[0]][$name[1]] : + null; } /** - * 设置配置参数 name为数组则为批量设置 - * @param string|array $name 配置参数名(支持二级配置 .号分割) - * @param mixed $value 配置值 - * @param string $range 作用域 + * 设置配置参数 name 为数组则为批量设置 + * @param string|array $name 配置参数名(支持二级配置 . 号分割) + * @param mixed $value 配置值 + * @param string $range 作用域 * @return mixed */ public static function set($name, $value = null, $range = '') { $range = $range ?: self::$range; - if (!isset(self::$config[$range])) { - self::$config[$range] = []; - } + + if (!isset(self::$config[$range])) self::$config[$range] = []; + + // 字符串则表示单个配置设置 if (is_string($name)) { if (!strpos($name, '.')) { self::$config[$range][strtolower($name)] = $value; } else { - // 二维数组设置和获取支持 - $name = explode('.', $name, 2); + // 二维数组 + $name = explode('.', $name, 2); self::$config[$range][strtolower($name[0])][$name[1]] = $value; } - return; - } elseif (is_array($name)) { - // 批量设置 + + return $value; + } + + // 数组则表示批量设置 + if (is_array($name)) { if (!empty($value)) { self::$config[$range][$value] = isset(self::$config[$range][$value]) ? - array_merge(self::$config[$range][$value], $name) : $name; + array_merge(self::$config[$range][$value], $name) : + $name; + return self::$config[$range][$value]; - } else { - return self::$config[$range] = array_merge(self::$config[$range], array_change_key_case($name)); } - } else { - // 为空直接返回 已有配置 - return self::$config[$range]; + + return self::$config[$range] = array_merge( + self::$config[$range], array_change_key_case($name) + ); } + + // 为空直接返回已有配置 + return self::$config[$range]; } /** * 重置配置参数 + * @param string $range 作用域 + * @return void */ public static function reset($range = '') { $range = $range ?: self::$range; + if (true === $range) { self::$config = []; } else { diff --git a/library/think/Error.php b/library/think/Error.php index 9eda5442..84386f81 100644 --- a/library/think/Error.php +++ b/library/think/Error.php @@ -31,53 +31,55 @@ class Error } /** - * Exception Handler - * @param \Exception|\Throwable $e + * 异常处理 + * @param \Exception|\Throwable $e 异常 + * @return void */ public static function appException($e) { - if (!$e instanceof \Exception) { - $e = new ThrowableError($e); - } + if (!$e instanceof \Exception) $e = new ThrowableError($e); + + $handler = self::getExceptionHandler(); + $handler->report($e); - self::getExceptionHandler()->report($e); if (IS_CLI) { - self::getExceptionHandler()->renderForConsole(new ConsoleOutput, $e); + $handler->renderForConsole(new ConsoleOutput, $e); } else { - self::getExceptionHandler()->render($e)->send(); + $handler->render($e)->send(); } } /** - * Error Handler - * @param integer $errno 错误编号 - * @param integer $errstr 详细错误信息 - * @param string $errfile 出错的文件 - * @param integer $errline 出错行号 - * @param array $errcontext + * 错误处理 + * @param integer $errno 错误编号 + * @param integer $errstr 详细错误信息 + * @param string $errfile 出错的文件 + * @param integer $errline 出错行号 + * @param array $errcontext 出错上下文 + * @return void * @throws ErrorException */ public static function appError($errno, $errstr, $errfile = '', $errline = 0, $errcontext = []) { $exception = new ErrorException($errno, $errstr, $errfile, $errline, $errcontext); - if (error_reporting() & $errno) { - // 将错误信息托管至 think\exception\ErrorException - throw $exception; - } else { - self::getExceptionHandler()->report($exception); - } + + // 符合异常处理的则将错误信息托管至 think\exception\ErrorException + if (error_reporting() & $errno) throw $exception; + + self::getExceptionHandler()->report($exception); } /** - * Shutdown Handler + * 异常中止处理 + * @return void */ public static function appShutdown() { + // 将错误信息托管至 think\ErrorException if (!is_null($error = error_get_last()) && self::isFatal($error['type'])) { - // 将错误信息托管至think\ErrorException - $exception = new ErrorException($error['type'], $error['message'], $error['file'], $error['line']); - - self::appException($exception); + self::appException(new ErrorException( + $error['type'], $error['message'], $error['file'], $error['line'] + )); } // 写入日志 @@ -86,8 +88,7 @@ class Error /** * 确定错误类型是否致命 - * - * @param int $type + * @param int $type * @return bool */ protected static function isFatal($type) @@ -96,25 +97,28 @@ class Error } /** - * Get an instance of the exception handler. - * + * 获取异常处理的实例 * @return Handle */ public static function getExceptionHandler() { static $handle; + if (!$handle) { - // 异常处理handle + // 异常处理 handle $class = Config::get('exception_handle'); - if ($class && is_string($class) && class_exists($class) && is_subclass_of($class, "\\think\\exception\\Handle")) { + + if ($class && is_string($class) && class_exists($class) && + is_subclass_of($class, "\\think\\exception\\Handle") + ) { $handle = new $class; } else { $handle = new Handle; - if ($class instanceof \Closure) { - $handle->setRender($class); - } + + if ($class instanceof \Closure) $handle->setRender($class); } } + return $handle; } } diff --git a/library/think/Loader.php b/library/think/Loader.php index b4f39bf5..f42f4418 100644 --- a/library/think/Loader.php +++ b/library/think/Loader.php @@ -15,7 +15,9 @@ use think\exception\ClassNotFoundException; class Loader { + // 实例 protected static $instance = []; + // 类名映射 protected static $map = []; @@ -34,7 +36,12 @@ class Loader // 自动加载的文件 private static $autoloadFiles = []; - // 自动加载 + /** + * 自动加载 + * @access public + * @param string $class 类名 + * @return bool + */ public static function autoload($class) { // 检测命名空间别名 @@ -48,34 +55,34 @@ class Loader } } - if ($file = self::findFile($class)) { - - // Win环境严格区分大小写 - if (IS_WIN && pathinfo($file, PATHINFO_FILENAME) != pathinfo(realpath($file), PATHINFO_FILENAME)) { - return false; - } + $file = self::findFile($class); + $path = pathinfo($file, PATHINFO_FILENAME); + $realPath = pathinfo(realpath($file), PATHINFO_FILENAME); + // 非 Win 环境不严格区分大小写 + if ($file && (!IS_WIN || $path == $realPath)) { __include_file($file); return true; } + + return false; } /** * 查找文件 - * @param $class + * @access private + * @param string $class 类名 * @return bool */ private static function findFile($class) { - if (!empty(self::$map[$class])) { - // 类库映射 - return self::$map[$class]; - } + // 类库映射 + if (!empty(self::$map[$class])) return self::$map[$class]; // 查找 PSR-4 $logicalPathPsr4 = strtr($class, '\\', DS) . EXT; - $first = $class[0]; + if (isset(self::$prefixLengthsPsr4[$first])) { foreach (self::$prefixLengthsPsr4[$first] as $prefix => $length) { if (0 === strpos($class, $prefix)) { @@ -97,9 +104,9 @@ class Loader // 查找 PSR-0 if (false !== $pos = strrpos($class, '\\')) { - // namespaced class name + // namespace class name $logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1) - . strtr(substr($logicalPathPsr4, $pos + 1), '_', DS); + . strtr(substr($logicalPathPsr4, $pos + 1), '_', DS); } else { // PEAR-like class name $logicalPathPsr0 = strtr($class, '_', DS) . EXT; @@ -127,7 +134,13 @@ class Loader return self::$map[$class] = false; } - // 注册classmap + /** + * 注册 classmap + * @access public + * @param string|array $class 类名 + * @param string $map 映射 + * @return void + */ public static function addClassMap($class, $map = '') { if (is_array($class)) { @@ -137,7 +150,13 @@ class Loader } } - // 注册命名空间 + /** + * 注册命名空间 + * @access public + * @param string|array $namespace 命名空间 + * @param string $path 路径 + * @return void + */ public static function addNamespace($namespace, $path = '') { if (is_array($namespace)) { @@ -149,84 +168,77 @@ class Loader } } - // 添加Ps0空间 + /** + * 添加 Ps0 空间 + * @access private + * @param array|null $prefix 空间前缀 + * @param array $paths 路径 + * @param bool $prepend 预先设置的优先级更高 + * @return void + */ private static function addPsr0($prefix, $paths, $prepend = false) { if (!$prefix) { - if ($prepend) { - self::$fallbackDirsPsr0 = array_merge( - (array) $paths, - self::$fallbackDirsPsr0 - ); - } else { - self::$fallbackDirsPsr0 = array_merge( - self::$fallbackDirsPsr0, - (array) $paths - ); - } - - return; - } - - $first = $prefix[0]; - if (!isset(self::$prefixesPsr0[$first][$prefix])) { - self::$prefixesPsr0[$first][$prefix] = (array) $paths; - - return; - } - if ($prepend) { - self::$prefixesPsr0[$first][$prefix] = array_merge( - (array) $paths, - self::$prefixesPsr0[$first][$prefix] - ); + self::$fallbackDirsPsr0 = $prepend ? + array_merge((array) $paths, self::$fallbackDirsPsr0) : + array_merge(self::$fallbackDirsPsr0, (array) $paths); } else { - self::$prefixesPsr0[$first][$prefix] = array_merge( - self::$prefixesPsr0[$first][$prefix], - (array) $paths - ); + $first = $prefix[0]; + + if (!isset(self::$prefixesPsr0[$first][$prefix])) { + self::$prefixesPsr0[$first][$prefix] = (array) $paths; + } else { + self::$prefixesPsr0[$first][$prefix] = $prepend ? + array_merge((array) $paths, self::$prefixesPsr0[$first][$prefix]) : + array_merge(self::$prefixesPsr0[$first][$prefix], (array) $paths); + } } } - // 添加Psr4空间 + /** + * 添加 Ps4 空间 + * @access private + * @param array|string $prefix 空间前缀 + * @param string $paths 路径 + * @param bool $prepend 预先设置的优先级更高 + * @return void + */ private static function addPsr4($prefix, $paths, $prepend = false) { if (!$prefix) { // Register directories for the root namespace. - if ($prepend) { - self::$fallbackDirsPsr4 = array_merge( - (array) $paths, - self::$fallbackDirsPsr4 - ); - } else { - self::$fallbackDirsPsr4 = array_merge( - self::$fallbackDirsPsr4, - (array) $paths - ); - } + self::$fallbackDirsPsr4 = $prepend ? + array_merge((array) $paths, self::$fallbackDirsPsr4) : + array_merge(self::$fallbackDirsPsr4, (array) $paths); + } elseif (!isset(self::$prefixDirsPsr4[$prefix])) { // Register directories for a new namespace. $length = strlen($prefix); if ('\\' !== $prefix[$length - 1]) { - throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator."); + throw new \InvalidArgumentException( + "A non-empty PSR-4 prefix must end with a namespace separator." + ); } + self::$prefixLengthsPsr4[$prefix[0]][$prefix] = $length; self::$prefixDirsPsr4[$prefix] = (array) $paths; - } elseif ($prepend) { - // Prepend directories for an already registered namespace. - self::$prefixDirsPsr4[$prefix] = array_merge( - (array) $paths, - self::$prefixDirsPsr4[$prefix] - ); + } else { - // Append directories for an already registered namespace. - self::$prefixDirsPsr4[$prefix] = array_merge( - self::$prefixDirsPsr4[$prefix], - (array) $paths - ); + self::$prefixDirsPsr4[$prefix] = $prepend ? + // Prepend directories for an already registered namespace. + array_merge((array) $paths, self::$prefixDirsPsr4[$prefix]) : + // Append directories for an already registered namespace. + array_merge(self::$prefixDirsPsr4[$prefix], (array) $paths); } } - // 注册命名空间别名 + /** + * 注册命名空间别名 + * @access public + * @param array|string $namespace 命名空间 + * @param string $original 源文件 + * @return void + */ public static function addNamespaceAlias($namespace, $original = '') { if (is_array($namespace)) { @@ -236,32 +248,41 @@ class Loader } } - // 注册自动加载机制 - public static function register($autoload = '') + /** + * 注册自动加载机制 + * @access public + * @param callable $autoload 自动加载处理方法 + * @return void + */ + public static function register($autoload = null) { // 注册系统自动加载 spl_autoload_register($autoload ?: 'think\\Loader::autoload', true, true); + + // 加载类库映射文件 + if (is_file(RUNTIME_PATH . 'classmap' . EXT)) { + self::addClassMap(__include_file(RUNTIME_PATH . 'classmap' . EXT)); + } + + // Composer 自动加载支持 + if (is_dir(VENDOR_PATH . 'composer')) self::registerComposerLoader(); + // 注册命名空间定义 self::addNamespace([ 'think' => LIB_PATH . 'think' . DS, 'behavior' => LIB_PATH . 'behavior' . DS, 'traits' => LIB_PATH . 'traits' . DS, ]); - // 加载类库映射文件 - if (is_file(RUNTIME_PATH . 'classmap' . EXT)) { - self::addClassMap(__include_file(RUNTIME_PATH . 'classmap' . EXT)); - } - // Composer自动加载支持 - if (is_dir(VENDOR_PATH . 'composer')) { - self::registerComposerLoader(); - } - - // 自动加载extend目录 + // 自动加载 extend 目录 self::$fallbackDirsPsr4[] = rtrim(EXTEND_PATH, DS); } - // 注册composer自动加载 + /** + * 注册 composer 自动加载 + * @access private + * @return void + */ private static function registerComposerLoader() { if (is_file(VENDOR_PATH . 'composer/autoload_namespaces.php')) { @@ -280,9 +301,7 @@ class Loader if (is_file(VENDOR_PATH . 'composer/autoload_classmap.php')) { $classMap = require VENDOR_PATH . 'composer/autoload_classmap.php'; - if ($classMap) { - self::addClassMap($classMap); - } + if ($classMap) self::addClassMap($classMap); } if (is_file(VENDOR_PATH . 'composer/autoload_files.php')) { @@ -297,20 +316,20 @@ class Loader } /** - * 导入所需的类库 同java的Import 本函数有缓存功能 + * 导入所需的类库 同 Java 的 Import 本函数有缓存功能 + * @access public * @param string $class 类库命名空间字符串 * @param string $baseUrl 起始路径 * @param string $ext 导入的文件扩展名 - * @return boolean + * @return bool */ public static function import($class, $baseUrl = '', $ext = EXT) { static $_file = []; - $key = $class . $baseUrl; - $class = str_replace(['.', '#'], [DS, '.'], $class); - if (isset($_file[$key])) { - return true; - } + $key = $class . $baseUrl; + $class = str_replace(['.', '#'], [DS, '.'], $class); + + if (isset($_file[$key])) return true; if (empty($baseUrl)) { list($name, $class) = explode(DS, $class, 2); @@ -319,7 +338,7 @@ class Loader // 注册的命名空间 $baseUrl = self::$prefixDirsPsr4[$name . '\\']; } elseif ('@' == $name) { - //加载当前模块应用类库 + // 加载当前模块应用类库 $baseUrl = App::$modulePath; } elseif (is_dir(EXTEND_PATH . $name)) { $baseUrl = EXTEND_PATH . $name . DS; @@ -330,32 +349,34 @@ class Loader } elseif (substr($baseUrl, -1) != DS) { $baseUrl .= DS; } - // 如果类存在 则导入类库文件 + + // 如果类存在则导入类库文件 if (is_array($baseUrl)) { foreach ($baseUrl as $path) { $filename = $path . DS . $class . $ext; - if (is_file($filename)) { - break; - } + + if (is_file($filename)) break; } } else { $filename = $baseUrl . $class . $ext; } - if (!empty($filename) && is_file($filename)) { - // 开启调试模式Win环境严格区分大小写 - if (IS_WIN && pathinfo($filename, PATHINFO_FILENAME) != pathinfo(realpath($filename), PATHINFO_FILENAME)) { - return false; - } + if (!empty($filename) && + is_file($filename) && + (!IS_WIN || pathinfo($filename, PATHINFO_FILENAME) == pathinfo(realpath($filename), PATHINFO_FILENAME)) + ) { __include_file($filename); $_file[$key] = true; + return true; } + return false; } /** * 实例化(分层)模型 + * @access public * @param string $name Model名称 * @param string $layer 业务层名称 * @param bool $appendSuffix 是否添加类名后缀 @@ -365,27 +386,30 @@ class Loader */ public static function model($name = '', $layer = 'model', $appendSuffix = false, $common = 'common') { - $guid = $name . $layer; - if (isset(self::$instance[$guid])) { - return self::$instance[$guid]; - } + $uid = $name . $layer; + + if (isset(self::$instance[$uid])) return self::$instance[$uid]; + list($module, $class) = self::getModuleAndClass($name, $layer, $appendSuffix); + if (class_exists($class)) { $model = new $class(); } else { $class = str_replace('\\' . $module . '\\', '\\' . $common . '\\', $class); + if (class_exists($class)) { $model = new $class(); } else { throw new ClassNotFoundException('class not exists:' . $class, $class); } } - self::$instance[$guid] = $model; - return $model; + + return self::$instance[$uid] = $model; } /** * 实例化(分层)控制器 格式:[模块名/]控制器名 + * @access public * @param string $name 资源地址 * @param string $layer 控制层名称 * @param bool $appendSuffix 是否添加类名后缀 @@ -396,17 +420,23 @@ class Loader public static function controller($name, $layer = 'controller', $appendSuffix = false, $empty = '') { list($module, $class) = self::getModuleAndClass($name, $layer, $appendSuffix); - if (class_exists($class)) { - return App::invokeClass($class); - } elseif ($empty && class_exists($emptyClass = self::parseClass($module, $layer, $empty, $appendSuffix))) { - return new $emptyClass(Request::instance()); - } else { - throw new ClassNotFoundException('class not exists:' . $class, $class); + + if (class_exists($class)) return App::invokeClass($class); + + if ($empty) { + $emptyClass = self::parseClass($module, $layer, $empty, $appendSuffix); + + if (class_exists($emptyClass)) { + return new $emptyClass(Request::instance()); + } } + + throw new ClassNotFoundException('class not exists:' . $class, $class); } /** * 实例化验证类 格式:[模块名/]验证器名 + * @access public * @param string $name 资源地址 * @param string $layer 验证层名称 * @param bool $appendSuffix 是否添加类名后缀 @@ -417,30 +447,31 @@ class Loader public static function validate($name = '', $layer = 'validate', $appendSuffix = false, $common = 'common') { $name = $name ?: Config::get('default_validate'); - if (empty($name)) { - return new Validate; - } - $guid = $name . $layer; - if (isset(self::$instance[$guid])) { - return self::$instance[$guid]; - } + if (empty($name)) return new Validate; + + $uid = $name . $layer; + if (isset(self::$instance[$uid])) return self::$instance[$uid]; + list($module, $class) = self::getModuleAndClass($name, $layer, $appendSuffix); + if (class_exists($class)) { $validate = new $class; } else { $class = str_replace('\\' . $module . '\\', '\\' . $common . '\\', $class); + if (class_exists($class)) { $validate = new $class; } else { throw new ClassNotFoundException('class not exists:' . $class, $class); } } - self::$instance[$guid] = $validate; - return $validate; + + return self::$instance[$uid] = $validate; } /** * 解析模块和类名 + * @access protected * @param string $name 资源地址 * @param string $layer 验证层名称 * @param bool $appendSuffix 是否添加类名后缀 @@ -457,15 +488,18 @@ class Loader } else { $module = Request::instance()->module(); } + $class = self::parseClass($module, $layer, $name, $appendSuffix); } + return [$module, $class]; } /** * 数据库初始化 并取得数据库类实例 - * @param mixed $config 数据库配置 - * @param bool|string $name 连接标识 true 强制重新连接 + * @access public + * @param mixed $config 数据库配置 + * @param bool|string $name 连接标识 true 强制重新连接 * @return \think\db\Connection */ public static function db($config = [], $name = false) @@ -475,6 +509,7 @@ class Loader /** * 远程调用模块的操作方法 参数格式 [模块/控制器/]操作 + * @access public * @param string $url 调用地址 * @param string|array $vars 调用参数 支持字符串和数组 * @param string $layer 要调用的控制层名称 @@ -487,6 +522,7 @@ class Loader $action = $info['basename']; $module = '.' != $info['dirname'] ? $info['dirname'] : Request::instance()->controller(); $class = self::controller($module, $layer, $appendSuffix); + if ($class) { if (is_scalar($vars)) { if (strpos($vars, '=')) { @@ -495,15 +531,19 @@ class Loader $vars = [$vars]; } } + return App::invokeMethod([$class, $action . Config::get('action_suffix')], $vars); } + + return false; } /** * 字符串命名风格转换 - * type 0 将Java风格转换为C的风格 1 将C风格转换为Java的风格 - * @param string $name 字符串 - * @param integer $type 转换类型 + * type 0 将 Java 风格转换为 C 的风格 1 将 C 风格转换为 Java 的风格 + * @access public + * @param string $name 字符串 + * @param integer $type 转换类型 * @param bool $ucfirst 首字母是否大写(驼峰规则) * @return string */ @@ -513,31 +553,38 @@ class Loader $name = preg_replace_callback('/_([a-zA-Z])/', function ($match) { return strtoupper($match[1]); }, $name); + return $ucfirst ? ucfirst($name) : lcfirst($name); - } else { - return strtolower(trim(preg_replace("/[A-Z]/", "_\\0", $name), "_")); } + + return strtolower(trim(preg_replace("/[A-Z]/", "_\\0", $name), "_")); } /** * 解析应用类的类名 - * @param string $module 模块名 - * @param string $layer 层名 controller model ... - * @param string $name 类名 - * @param bool $appendSuffix + * @access public + * @param string $module 模块名 + * @param string $layer 层名 controller model ... + * @param string $name 类名 + * @param bool $appendSuffix 是否添加类名后缀 * @return string */ public static function parseClass($module, $layer, $name, $appendSuffix = false) { - $name = str_replace(['/', '.'], '\\', $name); - $array = explode('\\', $name); - $class = self::parseName(array_pop($array), 1) . (App::$suffix || $appendSuffix ? ucfirst($layer) : ''); + + $array = explode('\\', str_replace(['/', '.'], '\\', $name)); + $class = self::parseName(array_pop($array), 1); + $class = $class . (App::$suffix || $appendSuffix ? ucfirst($layer) : ''); $path = $array ? implode('\\', $array) . '\\' : ''; - return App::$namespace . '\\' . ($module ? $module . '\\' : '') . $layer . '\\' . $path . $class; + + return App::$namespace . '\\' . + ($module ? $module . '\\' : '') . + $layer . '\\' . $path . $class; } /** * 初始化类的实例 + * @access public * @return void */ public static function clearInstance() @@ -546,10 +593,11 @@ class Loader } } +// 作用范围隔离 + /** - * 作用范围隔离 - * - * @param $file + * include + * @param string $file 文件路径 * @return mixed */ function __include_file($file) @@ -557,6 +605,11 @@ function __include_file($file) return include $file; } +/** + * require + * @param string $file 文件路径 + * @return mixed + */ function __require_file($file) { return require $file; diff --git a/library/traits/controller/Jump.php b/library/traits/controller/Jump.php index 472f23d1..6a572246 100644 --- a/library/traits/controller/Jump.php +++ b/library/traits/controller/Jump.php @@ -1,5 +1,4 @@ server('HTTP_REFERER'))) { $url = Request::instance()->server('HTTP_REFERER'); - } elseif ('' !== $url) { - $url = (strpos($url, '://') || 0 === strpos($url, '/')) ? $url : Url::build($url); + } elseif ('' !== $url && !strpos($url, '://') && 0 !== strpos($url, '/')) { + $url = Url::build($url); } + + $type = $this->getResponseType(); $result = [ 'code' => 1, 'msg' => $msg, @@ -49,32 +51,39 @@ trait Jump 'wait' => $wait, ]; - $type = $this->getResponseType(); if ('html' == strtolower($type)) { - $result = ViewTemplate::instance(Config::get('template'), Config::get('view_replace_str')) + $template = Config::get('template'); + $view = Config::get('view_replace_str'); + + $result = ViewTemplate::instance($template, $view) ->fetch(Config::get('dispatch_success_tmpl'), $result); } + $response = Response::create($result, $type)->header($header); + throw new HttpResponseException($response); } /** * 操作错误跳转的快捷方法 * @access protected - * @param mixed $msg 提示信息 - * @param string $url 跳转的URL地址 - * @param mixed $data 返回的数据 - * @param integer $wait 跳转等待时间 - * @param array $header 发送的Header信息 + * @param mixed $msg 提示信息 + * @param string $url 跳转的 URL 地址 + * @param mixed $data 返回的数据 + * @param int $wait 跳转等待时间 + * @param array $header 发送的 Header 信息 * @return void + * @throws HttpResponseException */ protected function error($msg = '', $url = null, $data = '', $wait = 3, array $header = []) { if (is_null($url)) { $url = Request::instance()->isAjax() ? '' : 'javascript:history.back(-1);'; - } elseif ('' !== $url) { - $url = (strpos($url, '://') || 0 === strpos($url, '/')) ? $url : Url::build($url); + } elseif ('' !== $url && !strpos($url, '://') && 0 !== strpos($url, '/')) { + $url = Url::build($url); } + + $type = $this->getResponseType(); $result = [ 'code' => 0, 'msg' => $msg, @@ -83,24 +92,29 @@ trait Jump 'wait' => $wait, ]; - $type = $this->getResponseType(); if ('html' == strtolower($type)) { - $result = ViewTemplate::instance(Config::get('template'), Config::get('view_replace_str')) + $template = Config::get('template'); + $view = Config::get('view_replace_str'); + + $result = ViewTemplate::instance($template, $view) ->fetch(Config::get('dispatch_error_tmpl'), $result); } + $response = Response::create($result, $type)->header($header); + throw new HttpResponseException($response); } /** - * 返回封装后的API数据到客户端 + * 返回封装后的 API 数据到客户端 * @access protected - * @param mixed $data 要返回的数据 - * @param integer $code 返回的code - * @param mixed $msg 提示信息 - * @param string $type 返回数据格式 - * @param array $header 发送的Header信息 + * @param mixed $data 要返回的数据 + * @param int $code 返回的 code + * @param mixed $msg 提示信息 + * @param string $type 返回数据格式 + * @param array $header 发送的 Header 信息 * @return void + * @throws HttpResponseException */ protected function result($data, $code = 0, $msg = '', $type = '', array $header = []) { @@ -112,37 +126,42 @@ trait Jump ]; $type = $type ?: $this->getResponseType(); $response = Response::create($result, $type)->header($header); + throw new HttpResponseException($response); } /** - * URL重定向 + * URL 重定向 * @access protected - * @param string $url 跳转的URL表达式 - * @param array|integer $params 其它URL参数 - * @param integer $code http code - * @param array $with 隐式传参 + * @param string $url 跳转的 URL 表达式 + * @param array|int $params 其它 URL 参数 + * @param int $code http code + * @param array $with 隐式传参 * @return void + * @throws HttpResponseException */ protected function redirect($url, $params = [], $code = 302, $with = []) { - $response = new Redirect($url); if (is_integer($params)) { $code = $params; $params = []; } + + $response = new Redirect($url); $response->code($code)->params($params)->with($with); + throw new HttpResponseException($response); } /** - * 获取当前的response 输出类型 + * 获取当前的 response 输出类型 * @access protected * @return string */ protected function getResponseType() { - $isAjax = Request::instance()->isAjax(); - return $isAjax ? Config::get('default_ajax_return') : Config::get('default_return_type'); + return Request::instance()->isAjax() + ? Config::get('default_ajax_return') + : Config::get('default_return_type'); } } diff --git a/library/traits/model/SoftDelete.php b/library/traits/model/SoftDelete.php index 5501bd40..753b2c8b 100644 --- a/library/traits/model/SoftDelete.php +++ b/library/traits/model/SoftDelete.php @@ -10,7 +10,6 @@ use think\Model; */ trait SoftDelete { - /** * 判断当前实例是否被软删除 * @access public @@ -19,22 +18,18 @@ trait SoftDelete public function trashed() { $field = $this->getDeleteTimeField(); - if (!empty($this->data[$field])) { - return true; - } - return false; + + return !empty($this->data[$field]); } /** - * 查询软删除数据 + * 查询包含软删除的数据 * @access public * @return Query */ public static function withTrashed() { - $model = new static(); - $field = $model->getDeleteTimeField(true); - return $model->getQuery(); + return (new static)->getQuery(); } /** @@ -46,31 +41,28 @@ trait SoftDelete { $model = new static(); $field = $model->getDeleteTimeField(true); - return $model->getQuery() - ->useSoftDelete($field, ['not null', '']); + + return $model->getQuery()->useSoftDelete($field, ['not null', '']); } /** * 删除当前的记录 * @access public - * @param bool $force 是否强制删除 + * @param bool $force 是否强制删除 * @return integer */ public function delete($force = false) { - if (false === $this->trigger('before_delete', $this)) { - return false; - } + if (false === $this->trigger('before_delete', $this)) return false; + $name = $this->getDeleteTimeField(); if (!$force) { // 软删除 $this->data[$name] = $this->autoWriteTimestamp($name); $result = $this->isUpdate()->save(); } else { - // 删除条件 - $where = $this->getWhere(); - // 删除当前模型数据 - $result = $this->getQuery()->where($where)->delete(); + // 强制删除当前模型数据 + $result = $this->getQuery()->where($this->getWhere())->delete(); } // 关联删除 @@ -78,47 +70,48 @@ trait SoftDelete foreach ($this->relationWrite as $key => $name) { $name = is_numeric($key) ? $name : $key; $model = $this->getAttr($name); - if ($model instanceof Model) { - $model->delete($force); - } + + if ($model instanceof Model) $model->delete(); } } $this->trigger('after_delete', $this); + // 清空原始数据 $this->origin = []; + return $result; } /** * 删除记录 * @access public - * @param mixed $data 主键列表 支持闭包查询条件 + * @param mixed $data 主键列表(支持闭包查询条件) * @param bool $force 是否强制删除 * @return integer 成功删除的记录数 */ public static function destroy($data, $force = false) { + if (is_null($data)) return 0; + // 包含软删除数据 $query = self::withTrashed(); if (is_array($data) && key($data) !== 0) { $query->where($data); $data = null; } elseif ($data instanceof \Closure) { - call_user_func_array($data, [ & $query]); + call_user_func_array($data, [&$query]); $data = null; - } elseif (is_null($data)) { - return 0; } - $resultSet = $query->select($data); - $count = 0; - if ($resultSet) { + $count = 0; + if ($resultSet = $query->select($data)) { foreach ($resultSet as $data) { $result = $data->delete($force); $count += $result; } } + return $count; } @@ -130,11 +123,13 @@ trait SoftDelete */ public function restore($where = []) { - $name = $this->getDeleteTimeField(); if (empty($where)) { $pk = $this->getPk(); $where[$pk] = $this->getData($pk); } + + $name = $this->getDeleteTimeField(); + // 恢复删除 return $this->getQuery() ->useSoftDelete($name, ['not null', '']) @@ -146,30 +141,32 @@ trait SoftDelete * 查询默认不包含软删除数据 * @access protected * @param Query $query 查询对象 - * @return void + * @return Query */ protected function base($query) { - $field = $this->getDeleteTimeField(true); - $query->useSoftDelete($field); + return $query->useSoftDelete($this->getDeleteTimeField(true)); } /** * 获取软删除字段 * @access public - * @param bool $read 是否查询操作 写操作的时候会自动去掉表别名 + * @param bool $read 是否查询操作(写操作的时候会自动去掉表别名) * @return string */ protected function getDeleteTimeField($read = false) { - $field = property_exists($this, 'deleteTime') && isset($this->deleteTime) ? $this->deleteTime : 'delete_time'; - if (!strpos($field, '.')) { - $field = '__TABLE__.' . $field; - } + $field = property_exists($this, 'deleteTime') && isset($this->deleteTime) ? + $this->deleteTime : + 'delete_time'; + + if (!strpos($field, '.')) $field = '__TABLE__.' . $field; + if (!$read && strpos($field, '.')) { $array = explode('.', $field); $field = array_pop($array); } + return $field; } } diff --git a/library/traits/think/Instance.php b/library/traits/think/Instance.php index ba45ddd8..7bad5d04 100644 --- a/library/traits/think/Instance.php +++ b/library/traits/think/Instance.php @@ -15,31 +15,40 @@ use think\Exception; trait Instance { + /** + * @var null|static 实例对象 + */ protected static $instance = null; /** - * @param array $options + * 获取示例 + * @param array $options 实例配置 * @return static */ public static function instance($options = []) { - if (is_null(self::$instance)) { - self::$instance = new self($options); - } + if (is_null(self::$instance)) self::$instance = new self($options); + return self::$instance; } - // 静态调用 - public static function __callStatic($method, $params) + /** + * 静态调用 + * @param string $method 调用方法 + * @param array $params 调用参数 + * @return mixed + * @throws Exception + */ + public static function __callStatic($method, array $params) { - if (is_null(self::$instance)) { - self::$instance = new self(); - } + if (is_null(self::$instance)) self::$instance = new self(); + $call = substr($method, 1); - if (0 === strpos($method, '_') && is_callable([self::$instance, $call])) { - return call_user_func_array([self::$instance, $call], $params); - } else { + + if (0 !== strpos($method, '_') || !is_callable([self::$instance, $call])) { throw new Exception("method not exists:" . $method); } + + return call_user_func_array([self::$instance, $call], $params); } } diff --git a/start.php b/start.php index 8af62ef3..2e139409 100644 --- a/start.php +++ b/start.php @@ -12,7 +12,8 @@ namespace think; // ThinkPHP 引导文件 -// 加载基础文件 +// 1. 加载基础文件 require __DIR__ . '/base.php'; -// 执行应用 + +// 2. 执行应用 App::run()->send();