diff --git a/thinkphp/base.php b/thinkphp/base.php index aad321d6a..084dd74db 100644 --- a/thinkphp/base.php +++ b/thinkphp/base.php @@ -28,31 +28,6 @@ if (interface_exists('Psr\Log\LoggerInterface')) { {} } -// 注册核心类到容器 -Container::getInstance()->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, - 'url' => Url::class, - 'validate' => Validate::class, - 'view' => View::class, - 'rule_name' => route\RuleName::class, - // 接口依赖注入 - 'think\LoggerInterface' => Log::class, -]); - // 注册核心类的静态代理 Facade::bind([ facade\App::class => App::class, @@ -97,9 +72,3 @@ Loader::addClassAlias([ 'Validate' => facade\Validate::class, 'View' => facade\View::class, ]); - -// 加载惯例配置文件 -facade\Config::set(include __DIR__ . '/convention.php'); - -// 加载composer autofile文件 -Loader::loadComposerAutoloadFiles(); diff --git a/thinkphp/convention.php b/thinkphp/convention.php index 28b979862..fbce075e7 100644 --- a/thinkphp/convention.php +++ b/thinkphp/convention.php @@ -15,8 +15,8 @@ return [ 'app_trace' => false, // 应用模式状态 'app_status' => '', - // 是否支持多模块 - 'app_multi_module' => true, + // 是否HTTPS + 'is_https' => false, // 入口自动绑定模块 'auto_bind_module' => false, // 注册的根命名空间 @@ -33,56 +33,81 @@ return [ 'default_timezone' => 'Asia/Shanghai', // 是否开启多语言 'lang_switch_on' => false, - // 默认全局过滤方法 用逗号分隔多个 - 'default_filter' => '', + // 默认验证器 + 'default_validate' => '', // 默认语言 'default_lang' => 'zh-cn', - // 应用类库后缀 - 'class_suffix' => false, - // 控制器类后缀 - 'controller_suffix' => false, // +---------------------------------------------------------------------- // | 模块设置 // +---------------------------------------------------------------------- + // 自动搜索控制器 + 'controller_auto_search' => false, + // 操作方法前缀 + 'use_action_prefix' => false, + // 操作方法后缀 + 'action_suffix' => '', + // 默认的空控制器名 + 'empty_controller' => 'Error', + // 默认的空模块名 + 'empty_module' => '', // 默认模块名 'default_module' => 'index', + // 是否支持多模块 + 'app_multi_module' => true, // 禁止访问模块 'deny_module_list' => ['common'], // 默认控制器名 'default_controller' => 'Index', // 默认操作名 'default_action' => 'index', - // 默认验证器 - 'default_validate' => '', - // 默认的空模块名 - 'empty_module' => '', - // 默认的空控制器名 - 'empty_controller' => 'Error', - // 操作方法前缀 - 'use_action_prefix' => false, - // 操作方法后缀 - 'action_suffix' => '', - // 自动搜索控制器 - 'controller_auto_search' => false, + // 是否自动转换URL中的控制器和操作名 + 'url_convert' => true, + // 默认的访问控制器层 + 'url_controller_layer' => 'controller', + // 应用类库后缀 + 'class_suffix' => false, + // 控制器类后缀 + 'controller_suffix' => false, // +---------------------------------------------------------------------- - // | URL设置 + // | URL请求设置 // +---------------------------------------------------------------------- + // 默认全局过滤方法 用逗号分隔多个 + 'default_filter' => '', // PATHINFO变量名 用于兼容模式 'var_pathinfo' => 's', // 兼容PATH_INFO获取 'pathinfo_fetch' => ['ORIG_PATH_INFO', 'REDIRECT_PATH_INFO', 'REDIRECT_URL'], - // pathinfo分隔符 - 'pathinfo_depr' => '/', // HTTPS代理标识 'https_agent_name' => '', // IP代理获取标识 'http_agent_ip' => 'X-REAL-IP', // URL伪静态后缀 'url_html_suffix' => 'html', + // 域名根,如thinkphp.cn + 'url_domain_root' => '', + // 表单请求类型伪装变量 + 'var_method' => '_method', + // 表单ajax伪装变量 + 'var_ajax' => '_ajax', + // 表单pjax伪装变量 + 'var_pjax' => '_pjax', + // 是否开启请求缓存 true自动缓存 支持设置请求缓存规则 + 'request_cache' => false, + // 请求缓存有效期 + 'request_cache_expire' => null, + // 全局请求缓存排除规则 + 'request_cache_except' => [], + + // +---------------------------------------------------------------------- + // | 路由设置 + // +---------------------------------------------------------------------- + + // pathinfo分隔符 + 'pathinfo_depr' => '/', // URL普通方式参数 用于自动生成 'url_common_param' => false, // URL参数方式 0 按名称成对解析 1 按顺序解析 @@ -97,36 +122,22 @@ return [ 'route_complete_match' => false, // 使用注解路由 'route_annotation' => false, - // 域名根,如thinkphp.cn - 'url_domain_root' => '', - // 是否自动转换URL中的控制器和操作名 - 'url_convert' => true, - // 默认的访问控制器层 - 'url_controller_layer' => 'controller', - // 表单请求类型伪装变量 - 'var_method' => '_method', - // 表单ajax伪装变量 - 'var_ajax' => '_ajax', - // 表单pjax伪装变量 - 'var_pjax' => '_pjax', - // 是否开启请求缓存 true自动缓存 支持设置请求缓存规则 - 'request_cache' => false, - // 请求缓存有效期 - 'request_cache_expire' => null, - // 全局请求缓存排除规则 - 'request_cache_except' => [], - - // 默认跳转页面对应的模板文件 - 'dispatch_success_tmpl' => __DIR__ . '/tpl/dispatch_jump.tpl', - 'dispatch_error_tmpl' => __DIR__ . '/tpl/dispatch_jump.tpl', + // 默认的路由变量规则 + 'default_route_pattern' => '\w+', + // 是否开启路由缓存 + 'route_check_cache' => false, + // 路由缓存的Key自定义设置(闭包),默认为当前URL和请求类型的md5 + 'route_check_cache_key' => '', // +---------------------------------------------------------------------- // | 异常及错误设置 // +---------------------------------------------------------------------- + // 默认跳转页面对应的模板文件 + 'dispatch_success_tmpl' => __DIR__ . '/tpl/dispatch_jump.tpl', + 'dispatch_error_tmpl' => __DIR__ . '/tpl/dispatch_jump.tpl', // 异常页面的模板文件 'exception_tmpl' => __DIR__ . '/tpl/think_exception.tpl', - // 错误显示信息,非调试模式有效 'error_message' => '页面错误!请稍后再试~', // 显示错误信息 @@ -180,6 +191,7 @@ return [ // +---------------------------------------------------------------------- // | Trace设置 开启 app_trace 后 有效 // +---------------------------------------------------------------------- + 'trace' => [ // 内置Html Console 支持扩展 'type' => 'Html', @@ -222,6 +234,7 @@ return [ // +---------------------------------------------------------------------- // | Cookie设置 // +---------------------------------------------------------------------- + 'cookie' => [ // cookie 名称前缀 'prefix' => '', diff --git a/thinkphp/helper.php b/thinkphp/helper.php index 8a965036c..372357f12 100644 --- a/thinkphp/helper.php +++ b/thinkphp/helper.php @@ -101,7 +101,7 @@ if (!function_exists('bind')) { */ function bind($abstract, $concrete = null) { - return Container::getInstance()->bind($abstract, $concrete); + return Container::getInstance()->bindTo($abstract, $concrete); } } diff --git a/thinkphp/library/think/App.php b/thinkphp/library/think/App.php index 0a0d6e748..e70f70073 100644 --- a/thinkphp/library/think/App.php +++ b/thinkphp/library/think/App.php @@ -18,9 +18,9 @@ use think\route\Dispatch; /** * App 应用管理 */ -class App implements \ArrayAccess +class App extends Container { - const VERSION = '5.1.13'; + const VERSION = '5.1.14'; /** * 当前模块路径 @@ -32,7 +32,7 @@ class App implements \ArrayAccess * 应用调试模式 * @var bool */ - protected $debug = true; + protected $appDebug = true; /** * 应用开始时间 @@ -112,22 +112,15 @@ class App implements \ArrayAccess */ protected $dispatch; - /** - * 容器对象实例 - * @var Container - */ - protected $container; - /** * 绑定模块(控制器) * @var string */ - protected $bind; + protected $bindModule; public function __construct($appPath = '') { - $this->appPath = $appPath ? realpath($appPath) . DIRECTORY_SEPARATOR : $this->getAppPath(); - $this->container = Container::getInstance(); + $this->appPath = $appPath ? realpath($appPath) . DIRECTORY_SEPARATOR : $this->getAppPath(); $this->thinkPath = dirname(dirname(__DIR__)) . DIRECTORY_SEPARATOR; $this->rootPath = dirname($this->appPath) . DIRECTORY_SEPARATOR; @@ -144,7 +137,7 @@ class App implements \ArrayAccess */ public function bind($bind) { - $this->bind = $bind; + $this->bindModule = $bind; return $this; } @@ -160,6 +153,39 @@ class App implements \ArrayAccess return $this; } + /** + * 注册核心容器实例 + * @access public + * @return void + */ + public function registerCoreContainer() + { + // 注册核心类到容器 + $this->bindTo([ + '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, + 'url' => Url::class, + 'validate' => Validate::class, + 'view' => View::class, + 'rule_name' => route\RuleName::class, + // 接口依赖注入 + 'think\LoggerInterface' => Log::class, + ]); + } + /** * 初始化应用 * @access public @@ -170,6 +196,15 @@ class App implements \ArrayAccess $this->beginTime = microtime(true); $this->beginMem = memory_get_usage(); + static::setInstance($this); + + $this->registerCoreContainer(); + + $this->instance('app', $this); + + // 加载惯例配置文件 + $this->config->set(include $this->thinkPath . 'convention.php'); + // 设置路径环境变量 $this->env->set([ 'think_path' => $this->thinkPath, @@ -202,10 +237,10 @@ class App implements \ArrayAccess $this->suffix = $this->config('app.class_suffix'); // 应用调试模式 - $this->debug = $this->env->get('app_debug', $this->config('app.app_debug')); - $this->env->set('app_debug', $this->debug); + $this->appDebug = $this->env->get('app_debug', $this->config('app.app_debug')); + $this->env->set('app_debug', $this->appDebug); - if (!$this->debug) { + if (!$this->appDebug) { ini_set('display_errors', 'Off'); } elseif (PHP_SAPI != 'cli') { //重新申请一块比较大的buffer @@ -218,14 +253,25 @@ class App implements \ArrayAccess } } + // 注册异常处理类 + if ($this->config('app.exception_handle')) { + Error::setExceptionHandler($this->config('app.exception_handle')); + } + // 注册根命名空间 if (!empty($this->config('app.root_namespace'))) { Loader::addNamespace($this->config('app.root_namespace')); } + // 加载composer autofile文件 + Loader::loadComposerAutoloadFiles(); + // 注册类库别名 Loader::addClassAlias($this->config->pull('alias')); + // 数据库配置初始化 + Db::init($this->config->pull('database')); + // 设置系统时区 date_default_timezone_set($this->config('app.default_timezone')); @@ -284,7 +330,7 @@ class App implements \ArrayAccess if (is_file($path . 'provider.php')) { $provider = include $path . 'provider.php'; if (is_array($provider)) { - $this->container->bind($provider); + $this->bindTo($provider); } } @@ -307,7 +353,40 @@ class App implements \ArrayAccess $this->setModulePath($path); - $this->request->filter($this->config('app.default_filter')); + if ($module) { + // 对容器中的对象实例进行配置更新 + $this->containerConfigUpdate($module); + } + + } + + protected function containerConfigUpdate($module) + { + $config = $this->config->get(); + + // 注册异常处理类 + if ($config['app']['exception_handle']) { + Error::setExceptionHandler($config['app']['exception_handle']); + } + + Db::init($config['database']); + $this->request->init($config['app']); + $this->cookie->init($config['cookie']); + $this->view->init($config['template']); + $this->log->init($config['log']); + $this->session->setConfig($config['session']); + $this->debug->setConfig($config['trace']); + $this->cache->init($config['cache'], true); + + // 加载当前模块语言包 + $this->lang->load($this->appPath . $module . DIRECTORY_SEPARATOR . 'lang' . DIRECTORY_SEPARATOR . $this->request->langset() . '.php'); + + // 模块请求缓存检查 + $this->request->cache( + $config['app']['request_cache'], + $config['app']['request_cache_expire'], + $config['app']['request_cache_except'] + ); } /** @@ -322,9 +401,9 @@ class App implements \ArrayAccess // 初始化应用 $this->initialize(); - if ($this->bind) { + if ($this->bindModule) { // 模块/控制器绑定 - $this->route->bind($this->bind); + $this->route->bind($this->bindModule); } elseif ($this->config('app.auto_bind_module')) { // 入口自动绑定 $name = pathinfo($this->request->baseFile(), PATHINFO_FILENAME); @@ -337,22 +416,32 @@ class App implements \ArrayAccess $this->hook->listen('app_dispatch'); // 获取应用调度信息 + if (!$this->appDebug && $this->config->get('route_check_cache')) { + $routeKey = $this->getRouteCacheKey(); + + if ($this->cache->has($routeKey)) { + $this->dispatch = $this->cache->get($routeKey); + } + } + $dispatch = $this->dispatch; + if (empty($dispatch)) { // 路由检测 - $this->route - ->lazy($this->config('app.url_lazy_route')) - ->autoSearchController($this->config('app.controller_auto_search')) - ->mergeRuleRegex($this->config('app.route_rule_merge')); - $dispatch = $this->routeCheck(); + + try { + if (isset($routeKey)) { + $this->cache->tag('route_cache')->set($routeKey, $dispatch); + } + } catch (\Exception $e) {} } // 记录当前调度信息 $this->request->dispatch($dispatch); // 记录路由和请求信息 - if ($this->debug) { + if ($this->appDebug) { $this->log('[ ROUTE ] ' . var_export($this->request->routeInfo(), true)); $this->log('[ HEADER ] ' . var_export($this->request->header(), true)); $this->log('[ PARAM ] ' . var_export($this->request->param(), true)); @@ -363,9 +452,9 @@ class App implements \ArrayAccess // 请求缓存检查 $this->request->cache( - $this->config('app.request_cache'), - $this->config('app.request_cache_expire'), - $this->config('app.request_cache_except') + $this->config('request_cache'), + $this->config('request_cache_expire'), + $this->config('request_cache_except') ); $data = null; @@ -407,10 +496,23 @@ class App implements \ArrayAccess return $response; } + protected function getRouteCacheKey() + { + if ($this->config->get('route_check_cache_key')) { + $closure = $this->config->get('route_check_cache_key'); + $routeKey = $closure($this->request); + } else { + $routeKey = md5($this->request->baseUrl(true) . ':' . $this->request->method()); + } + + return $routeKey; + } + protected function loadLangPack() { // 读取默认语言 $this->lang->range($this->config('app.default_lang')); + if ($this->config('app.lang_switch_on')) { // 开启多语言机制 检测当前语言 $this->lang->detect(); @@ -446,7 +548,7 @@ class App implements \ArrayAccess */ public function log($msg, $type = 'info') { - $this->debug && $this->log->record($msg, $type); + $this->appDebug && $this->log->record($msg, $type); } /** @@ -468,7 +570,6 @@ class App implements \ArrayAccess public function routeCheck() { $path = $this->request->path(); - $depr = $this->config('app.pathinfo_depr'); // 路由检测 $files = scandir($this->routePath); @@ -483,10 +584,10 @@ class App implements \ArrayAccess } } - if ($this->config('app.route_annotation')) { + if ($this->config('route.route_annotation')) { // 自动生成路由定义 - if ($this->debug) { - $this->build->buildRoute($this->config('app.controller_suffix')); + if ($this->appDebug) { + $this->build->buildRoute($this->config('route.controller_suffix')); } $filename = $this->runtimePath . 'build_route.php'; @@ -501,10 +602,10 @@ class App implements \ArrayAccess } // 是否强制路由模式 - $must = !is_null($this->routeMust) ? $this->routeMust : $this->config('app.url_route_must'); + $must = !is_null($this->routeMust) ? $this->routeMust : $this->route->config('url_route_must'); // 路由检测 返回一个Dispatch对象 - return $this->route->check($path, $depr, $must, $this->config('app.route_complete_match')); + return $this->route->check($path, $must); } /** @@ -677,7 +778,7 @@ class App implements \ArrayAccess } } - return $this->container->invokeMethod([$class, $action . $this->config('action_suffix')], $vars); + return $this->invokeMethod([$class, $action . $this->config('action_suffix')], $vars); } /** @@ -716,7 +817,7 @@ class App implements \ArrayAccess */ public function isDebug() { - return $this->debug; + return $this->appDebug; } /** @@ -867,53 +968,4 @@ class App implements \ArrayAccess return $this->beginMem; } - /** - * 获取容器实例 - * @access public - * @return Container - */ - public function container() - { - return $this->container; - } - - public function __set($name, $value) - { - $this->container->bind($name, $value); - } - - public function __get($name) - { - return $this->container->make($name); - } - - public function __isset($name) - { - return $this->container->bound($name); - } - - public function __unset($name) - { - $this->container->delete($name); - } - - public function offsetExists($key) - { - return $this->__isset($key); - } - - public function offsetGet($key) - { - return $this->__get($key); - } - - public function offsetSet($key, $value) - { - $this->__set($key, $value); - } - - public function offsetUnset($key) - { - $this->__unset($key); - } } diff --git a/thinkphp/library/think/Cache.php b/thinkphp/library/think/Cache.php index 175beac4b..c7a7aa6e2 100644 --- a/thinkphp/library/think/Cache.php +++ b/thinkphp/library/think/Cache.php @@ -30,10 +30,10 @@ class Cache protected $instance = []; /** - * 应用对象 - * @var App + * 缓存配置 + * @var array */ - protected $app; + protected $config = []; /** * 操作句柄 @@ -41,9 +41,10 @@ class Cache */ protected $handler; - public function __construct(App $app) + public function __construct(array $config = []) { - $this->app = $app; + $this->config = $config; + $this->init($config); } /** @@ -55,23 +56,18 @@ class Cache */ public function connect(array $options = [], $name = false) { - $type = !empty($options['type']) ? $options['type'] : 'File'; - if (false === $name) { $name = md5(serialize($options)); } if (true === $name || !isset($this->instance[$name])) { - $class = false !== strpos($type, '\\') ? $type : '\\think\\cache\\driver\\' . ucwords($type); - - // 记录初始化信息 - $this->app->log('[ CACHE ] INIT ' . $type); + $type = !empty($options['type']) ? $options['type'] : 'File'; if (true === $name) { $name = md5(serialize($options)); } - $this->instance[$name] = new $class($options); + $this->instance[$name] = Loader::factory($type, '\\think\\cache\\driver\\', $options); } return $this->instance[$name]; @@ -81,19 +77,16 @@ class Cache * 自动初始化缓存 * @access public * @param array $options 配置数组 + * @param bool $force 强制更新 * @return Driver */ - public function init(array $options = []) + public function init(array $options = [], $force = false) { - if (is_null($this->handler)) { - // 自动初始化缓存 - $config = $this->app['config']; + if (is_null($this->handler) || $force) { - if (empty($options) && 'complex' == $config->get('cache.type')) { - $default = $config->get('cache.default'); - $options = $config->get('cache.' . $default['type']) ?: $default; - } elseif (empty($options)) { - $options = $config->pull('cache'); + if ('complex' == $options['type']) { + $default = $options['default']; + $options = isset($options[$default['type']]) ? $options[$default['type']] : $default; } $this->handler = $this->connect($options); @@ -102,6 +95,16 @@ class Cache return $this->handler; } + public static function __make(Config $config) + { + return new static($config->pull('cache')); + } + + public function setConfig(array $config) + { + $this->config = array_merge($this->config, $config); + } + /** * 切换缓存类型 需要配置 cache.type 为 complex * @access public @@ -110,8 +113,8 @@ class Cache */ public function store($name = '') { - if ('' !== $name && 'complex' == $this->app['config']->get('cache.type')) { - return $this->connect($this->app['config']->get('cache.' . $name), strtolower($name)); + if ('' !== $name && 'complex' == $this->config['type']) { + return $this->connect($this->config[$name], strtolower($name)); } return $this->init(); diff --git a/thinkphp/library/think/Config.php b/thinkphp/library/think/Config.php index 603c655f4..3fa9b136b 100644 --- a/thinkphp/library/think/Config.php +++ b/thinkphp/library/think/Config.php @@ -20,11 +20,22 @@ class Config implements \ArrayAccess private $config = []; /** - * 缓存前缀 + * 配置前缀 * @var string */ private $prefix = 'app'; + /** + * 应用对象 + * @var App + */ + protected $app; + + public function __construct(App $app) + { + $this->app = $app; + } + /** * 设置配置参数默认前缀 * @access public @@ -50,9 +61,9 @@ class Config implements \ArrayAccess $type = pathinfo($config, PATHINFO_EXTENSION); } - $class = false !== strpos($type, '\\') ? $type : '\\think\\config\\driver\\' . ucwords($type); + $object = Loader::factory($type, '\\think\\config\\driver\\', $config); - return $this->set((new $class())->parse($config), $name); + return $this->set($object->parse(), $name); } /** @@ -88,15 +99,14 @@ class Config implements \ArrayAccess protected function autoLoad($name) { // 如果尚未载入 则动态加载配置文件 - $module = Container::get('request')->module(); + $module = $this->app->request->module(); $module = $module ? $module . DIRECTORY_SEPARATOR : ''; - $app = Container::get('app'); - $path = $app->getAppPath() . $module; + $path = $this->app->getAppPath() . $module; if (is_dir($path . 'config')) { - $file = $path . 'config' . DIRECTORY_SEPARATOR . $name . $app->getConfigExt(); - } elseif (is_dir($app->getConfigPath() . $module)) { - $file = $app->getConfigPath() . $module . $name . $app->getConfigExt(); + $file = $path . 'config' . DIRECTORY_SEPARATOR . $name . $this->app->getConfigExt(); + } elseif (is_dir($this->app->getConfigPath() . $module)) { + $file = $this->app->getConfigPath() . $module . $name . $this->app->getConfigExt(); } if (isset($file) && is_file($file)) { diff --git a/thinkphp/library/think/Container.php b/thinkphp/library/think/Container.php index 6929350a0..94cf449e3 100644 --- a/thinkphp/library/think/Container.php +++ b/thinkphp/library/think/Container.php @@ -19,7 +19,7 @@ use ReflectionFunction; use ReflectionMethod; use think\exception\ClassNotFoundException; -class Container +class Container implements \ArrayAccess { /** * 容器对象实例 @@ -37,7 +37,14 @@ class Container * 容器绑定标识 * @var array */ - protected $bind = []; + protected $bind = [ + 'app' => 'think\App', + 'config' => 'think\Config', + 'lang' => 'think\Lang', + 'log' => 'think\Log', + 'request' => 'think\Request', + 'response' => 'think\Response', + ]; /** * 容器标识别名 @@ -59,6 +66,17 @@ class Container return static::$instance; } + /** + * 设置当前容器的实例 + * @access public + * @param object $instance + * @return void + */ + public static function setInstance($instance) + { + static::$instance = $instance; + } + /** * 获取容器中的对象实例 * @access public @@ -81,7 +99,7 @@ class Container */ public static function set($abstract, $concrete = null) { - return static::getInstance()->bind($abstract, $concrete); + return static::getInstance()->bindTo($abstract, $concrete); } /** @@ -112,7 +130,7 @@ class Container * @param mixed $concrete 要绑定的类、闭包或者实例 * @return $this */ - public function bind($abstract, $concrete = null) + public function bindTo($abstract, $concrete = null) { if (is_array($abstract)) { $this->bind = array_merge($this->bind, $abstract); @@ -378,8 +396,7 @@ class Container $class = $param->getClass(); if ($class) { - $className = $class->getName(); - $args[] = $this->make($className); + $args[] = $this->getObjectParam($class->getName(), $vars); } elseif (1 == $type && !empty($vars)) { $args[] = array_shift($vars); } elseif (0 == $type && isset($vars[$name])) { @@ -394,4 +411,64 @@ class Container return $args; } + /** + * 获取对象类型的参数值 + * @access protected + * @param string $className 类名 + * @param array $vars 参数 + * @return mixed + */ + protected function getObjectParam($className, &$vars) + { + $value = array_shift($vars); + + if ($value instanceof $className) { + $result = $value; + } else { + array_unshift($vars, $value); + $result = $this->make($className); + } + + return $result; + } + + public function __set($name, $value) + { + $this->bindTo($name, $value); + } + + public function __get($name) + { + return $this->make($name); + } + + public function __isset($name) + { + return $this->bound($name); + } + + public function __unset($name) + { + $this->delete($name); + } + + public function offsetExists($key) + { + return $this->__isset($key); + } + + public function offsetGet($key) + { + return $this->__get($key); + } + + public function offsetSet($key, $value) + { + $this->__set($key, $value); + } + + public function offsetUnset($key) + { + $this->__unset($key); + } } diff --git a/thinkphp/library/think/Controller.php b/thinkphp/library/think/Controller.php index ffa381866..0220aee4a 100644 --- a/thinkphp/library/think/Controller.php +++ b/thinkphp/library/think/Controller.php @@ -30,12 +30,6 @@ class Controller */ protected $request; - /** - * 应用实例 - * @var \think\App - */ - protected $app; - /** * 验证失败是否抛出异常 * @var bool @@ -58,13 +52,11 @@ class Controller * 构造方法 * @access public */ - public function __construct() + public function __construct(App $app = null) { - $this->request = Container::get('request'); - $this->app = Container::get('app'); - $this->view = Container::get('view')->init( - $this->app['config']->pull('template') - ); + $this->app = $app ?: Container::get('app'); + $this->request = $this->app['request']; + $this->view = $this->app['view']; // 控制器初始化 $this->initialize(); diff --git a/thinkphp/library/think/Cookie.php b/thinkphp/library/think/Cookie.php index c645fde69..2fd8c31b6 100644 --- a/thinkphp/library/think/Cookie.php +++ b/thinkphp/library/think/Cookie.php @@ -35,10 +35,13 @@ class Cookie ]; /** - * 是否初始化 - * @var bool + * 构造方法 + * @access public */ - protected $init; + public function __construct(array $config = []) + { + $this->init($config); + } /** * Cookie初始化 @@ -48,17 +51,16 @@ class Cookie */ public function init(array $config = []) { - if (empty($config)) { - $config = Container::get('config')->pull('cookie'); - } - $this->config = array_merge($this->config, array_change_key_case($config)); if (!empty($this->config['httponly'])) { ini_set('session.cookie_httponly', 1); } + } - $this->init = true; + public static function __make(Config $config) + { + return new static($config->pull('cookie')); } /** @@ -87,8 +89,6 @@ class Cookie */ public function set($name, $value = '', $option = null) { - !isset($this->init) && $this->init(); - // 参数设置(会覆盖黙认设置) if (!is_null($option)) { if (is_numeric($option)) { @@ -147,8 +147,6 @@ class Cookie */ public function has($name, $prefix = null) { - !isset($this->init) && $this->init(); - $prefix = !is_null($prefix) ? $prefix : $this->config['prefix']; $name = $prefix . $name; @@ -164,8 +162,6 @@ class Cookie */ public function get($name = '', $prefix = null) { - !isset($this->init) && $this->init(); - $prefix = !is_null($prefix) ? $prefix : $this->config['prefix']; $key = $prefix . $name; @@ -204,8 +200,6 @@ class Cookie */ public function delete($name, $prefix = null) { - !isset($this->init) && $this->init(); - $config = $this->config; $prefix = !is_null($prefix) ? $prefix : $config['prefix']; $name = $prefix . $name; @@ -231,8 +225,6 @@ class Cookie return; } - !isset($this->init) && $this->init(); - // 要删除的cookie前缀,不指定则删除config设置的指定前缀 $config = $this->config; $prefix = !is_null($prefix) ? $prefix : $config['prefix']; diff --git a/thinkphp/library/think/Db.php b/thinkphp/library/think/Db.php index 911501c9e..e86e6e034 100644 --- a/thinkphp/library/think/Db.php +++ b/thinkphp/library/think/Db.php @@ -11,6 +11,8 @@ namespace think; +use think\db\Connection; + /** * Class Db * @package think @@ -57,6 +59,18 @@ namespace think; */ class Db { + /** + * 当前数据库连接对象 + * @var Connection + */ + protected static $connection; + + /** + * 数据库配置 + * @var array + */ + protected static $config = []; + /** * 查询次数 * @var integer @@ -69,12 +83,108 @@ class Db */ public static $executeTimes = 0; + /** + * 配置 + * @access public + * @param mixed $config + * @return void + */ + public static function init($config = []) + { + self::$config = $config; + + if (empty($config['query'])) { + self::$config['query'] = '\\think\\db\\Query'; + } + } + + /** + * 获取数据库配置 + * @access public + * @return array + */ + public static function getConfig() + { + return self::$config; + } + + /** + * 切换数据库连接 + * @access public + * @param mixed $config 连接配置 + * @param bool|string $name 连接标识 true 强制重新连接 + * @param string $query 查询对象类名 + * @return mixed 返回查询对象实例 + * @throws Exception + */ + public static function connect($config = [], $name = false, $query = '') + { + // 解析配置参数 + $options = self::parseConfig($config ?: self::$config); + $query = $query ?: self::$config['query']; + + // 创建数据库连接对象实例 + self::$connection = Connection::instance($options, $name); + + return new $query(self::$connection); + } + + /** + * 数据库连接参数解析 + * @access private + * @param mixed $config + * @return array + */ + private static function parseConfig($config) + { + if (is_string($config) && false === strpos($config, '/')) { + // 支持读取配置参数 + $config = isset(self::$config[$config]) ? self::$config[$config] : self::$config; + } + + if (is_string($config)) { + return self::parseDsnConfig($config); + } else { + return $config; + } + } + + /** + * DSN解析 + * 格式: mysql://username:passwd@localhost:3306/DbName?param1=val1¶m2=val2#utf8 + * @access private + * @param string $dsnStr + * @return array + */ + private static function parseDsnConfig($dsnStr) + { + $info = parse_url($dsnStr); + + if (!$info) { + return []; + } + + $dsn = [ + 'type' => $info['scheme'], + 'username' => isset($info['user']) ? $info['user'] : '', + 'password' => isset($info['pass']) ? $info['pass'] : '', + 'hostname' => isset($info['host']) ? $info['host'] : '', + 'hostport' => isset($info['port']) ? $info['port'] : '', + 'database' => !empty($info['path']) ? ltrim($info['path'], '/') : '', + 'charset' => isset($info['fragment']) ? $info['fragment'] : 'utf8', + ]; + + if (isset($info['query'])) { + parse_str($info['query'], $dsn['params']); + } else { + $dsn['params'] = []; + } + + return $dsn; + } + public static function __callStatic($method, $args) { - $class = Container::get('config')->get('database.query') ?: '\\think\\db\\Query'; - - $query = new $class(); - - return call_user_func_array([$query, $method], $args); + return call_user_func_array([static::connect(), $method], $args); } } diff --git a/thinkphp/library/think/Debug.php b/thinkphp/library/think/Debug.php index 75003770b..91a25d961 100644 --- a/thinkphp/library/think/Debug.php +++ b/thinkphp/library/think/Debug.php @@ -11,12 +11,17 @@ namespace think; -use think\exception\ClassNotFoundException; use think\model\Collection as ModelCollection; use think\response\Redirect; class Debug { + /** + * 配置参数 + * @var array + */ + protected $config = []; + /** * 区间时间信息 * @var array @@ -35,9 +40,20 @@ class Debug */ protected $app; - public function __construct(App $app) + public function __construct(App $app, array $config = []) { - $this->app = $app; + $this->app = $app; + $this->config = $config; + } + + public static function __make(App $app, Config $config) + { + return new static($app, $config->pull('trace')); + } + + public function setConfig(array $config) + { + $this->config = array_merge($this->config, $config); } /** @@ -221,7 +237,7 @@ class Debug $output = '
' . $label . $output . ''; } if ($echo) { - echo($output); + echo ($output); return; } return $output; @@ -229,16 +245,12 @@ class Debug public function inject(Response $response, &$content) { - $config = $this->app['config']->pull('trace'); + $config = $this->config; $type = isset($config['type']) ? $config['type'] : 'Html'; - $class = false !== strpos($type, '\\') ? $type : '\\think\\debug\\' . ucwords($type); + unset($config['type']); - if (class_exists($class)) { - $trace = new $class($config); - } else { - throw new ClassNotFoundException('class not exists:' . $class, $class); - } + $trace = Loader::factory($type, '\\think\\debug\\', $config); if ($response instanceof Redirect) { //TODO 记录 diff --git a/thinkphp/library/think/Error.php b/thinkphp/library/think/Error.php index b8c8fc585..ea3328eec 100644 --- a/thinkphp/library/think/Error.php +++ b/thinkphp/library/think/Error.php @@ -18,6 +18,12 @@ use think\exception\ThrowableError; class Error { + /** + * 配置参数 + * @var array + */ + protected static $exceptionHandler; + /** * 注册异常处理 * @access public @@ -100,6 +106,18 @@ class Error return in_array($type, [E_ERROR, E_CORE_ERROR, E_COMPILE_ERROR, E_PARSE]); } + /** + * 设置异常处理类 + * + * @access public + * @param mixed $handle + * @return void + */ + public static function setExceptionHandler($handle) + { + self::$exceptionHandler = $handle; + } + /** * Get an instance of the exception handler. * @@ -112,7 +130,8 @@ class Error if (!$handle) { // 异常处理handle - $class = Container::get('config')->get('exception_handle'); + $class = self::$exceptionHandler; + if ($class && is_string($class) && class_exists($class) && is_subclass_of($class, "\\think\\exception\\Handle")) { $handle = new $class; } else { diff --git a/thinkphp/library/think/Facade.php b/thinkphp/library/think/Facade.php index 28fe667bb..f467e0f81 100644 --- a/thinkphp/library/think/Facade.php +++ b/thinkphp/library/think/Facade.php @@ -85,15 +85,13 @@ class Facade /** * 带参数实例化当前Facade类 * @access public - * @return object + * @return mixed */ public static function instance(...$args) { if (__CLASS__ != static::class) { - return self::__callStatic('instance', $args); + return self::createFacade('', $args); } - - return self::createFacade('', $args); } /** @@ -102,7 +100,7 @@ class Facade * @param string $class 类名或者标识 * @param array|true $args 变量 * @param bool $newInstance 是否每次创建新的实例 - * @return object + * @return mixed */ public static function make($class, $args = [], $newInstance = false) { diff --git a/thinkphp/library/think/Hook.php b/thinkphp/library/think/Hook.php index b82fb5a09..58791c815 100644 --- a/thinkphp/library/think/Hook.php +++ b/thinkphp/library/think/Hook.php @@ -31,6 +31,17 @@ class Hook */ private static $portal = 'run'; + /** + * 应用对象 + * @var App + */ + protected $app; + + public function __construct(App $app) + { + $this->app = $app; + } + /** * 指定入口方法名称 * @access public @@ -163,7 +174,7 @@ class Hook $method = [$class, self::$portal]; } - return Container::getInstance()->invoke($method, [$params]); + return $this->app->invoke($method, [$params]); } /** @@ -176,9 +187,7 @@ class Hook */ protected function execTag($class, $tag = '', $params = null) { - $app = Container::get('app'); - - $app->isDebug() && $app['debug']->remark('behavior_start', 'time'); + $this->app->isDebug() && $this->app['debug']->remark('behavior_start', 'time'); $method = Loader::parseName($tag, 1, false); @@ -198,12 +207,12 @@ class Hook $class = $class . '->' . $method; } - $result = Container::getInstance()->invoke($call, [$params]); + $result = $this->app->invoke($call, [$params]); - if ($app->isDebug()) { - $debug = $app['debug']; + if ($this->app->isDebug()) { + $debug = $this->app['debug']; $debug->remark('behavior_end', 'time'); - $app->log('[ BEHAVIOR ] Run ' . $class . ' @' . $tag . ' [ RunTime:' . $debug->getRangeTime('behavior_start', 'behavior_end') . 's ]'); + $this->app->log('[ BEHAVIOR ] Run ' . $class . ' @' . $tag . ' [ RunTime:' . $debug->getRangeTime('behavior_start', 'behavior_end') . 's ]'); } return $result; diff --git a/thinkphp/library/think/Lang.php b/thinkphp/library/think/Lang.php index 2168c13a5..5d8d9d99e 100644 --- a/thinkphp/library/think/Lang.php +++ b/thinkphp/library/think/Lang.php @@ -51,6 +51,17 @@ class Lang 'zh-hans-cn' => 'zh-cn', ]; + /** + * 应用对象 + * @var App + */ + protected $app; + + public function __construct(App $app) + { + $this->app = $app; + } + // 设定当前的语言 public function range($range = '') { @@ -108,7 +119,7 @@ class Lang foreach ($file as $_file) { if (is_file($_file)) { // 记录加载信息 - Container::get('app')->log('[ LANG ] ' . $_file); + $this->app->log('[ LANG ] ' . $_file); $_lang = include $_file; if (is_array($_lang)) { $lang = array_change_key_case($_lang) + $lang; @@ -200,11 +211,8 @@ class Lang } elseif (isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) { // 自动侦测浏览器语言 preg_match('/^([a-z\d\-]+)/i', $_SERVER['HTTP_ACCEPT_LANGUAGE'], $matches); - $langSet = strtolower($matches[1]); - $acceptLangs = Container::get('config')->get('header_accept_lang'); - if (isset($acceptLangs[$langSet])) { - $langSet = $acceptLangs[$langSet]; - } elseif (isset($this->acceptLanguage[$langSet])) { + $langSet = strtolower($matches[1]); + if (isset($this->acceptLanguage[$langSet])) { $langSet = $this->acceptLanguage[$langSet]; } } @@ -258,8 +266,19 @@ class Lang * @param array $list 语言列表 * @return void */ - public function setAllowLangList($list) + public function setAllowLangList(array $list) { $this->allowLangList = $list; } + + /** + * 设置转义的语言列表 + * @access public + * @param array $list 语言列表 + * @return void + */ + public function setAcceptLanguage(array $list) + { + $this->acceptLanguage = array_merge($this->acceptLanguage, $list); + } } diff --git a/thinkphp/library/think/Loader.php b/thinkphp/library/think/Loader.php index b048ca743..d807db640 100644 --- a/thinkphp/library/think/Loader.php +++ b/thinkphp/library/think/Loader.php @@ -11,6 +11,8 @@ namespace think; +use think\exception\ClassNotFoundException; + class Loader { /** @@ -378,6 +380,24 @@ class Loader return strtolower(trim(preg_replace("/[A-Z]/", "_\\0", $name), "_")); } + + /** + * 创建工厂对象实例 + * @access public + * @param string $name 工厂类名 + * @param string $namespace 默认命名空间 + * @return mixed + */ + public static function factory($name, $namespace = '', ...$args) + { + $class = false !== strpos($name, '\\') ? $name : $namespace . ucwords($name); + + if (class_exists($class)) { + return Container::getInstance()->invokeClass($class, $args); + } else { + throw new ClassNotFoundException('class not exists:' . $class, $class); + } + } } /** diff --git a/thinkphp/library/think/Log.php b/thinkphp/library/think/Log.php index b584ee78f..1c2e9d5c8 100644 --- a/thinkphp/library/think/Log.php +++ b/thinkphp/library/think/Log.php @@ -11,8 +11,6 @@ namespace think; -use think\exception\ClassNotFoundException; - class Log implements LoggerInterface { const EMERGENCY = 'emergency'; @@ -66,6 +64,11 @@ class Log implements LoggerInterface $this->app = $app; } + public static function __make(App $app, Config $config) + { + return (new static($app))->init($config->pull('log')); + } + /** * 日志初始化 * @access public @@ -74,24 +77,17 @@ class Log implements LoggerInterface */ public function init($config = []) { - $type = isset($config['type']) ? $config['type'] : 'File'; - $class = false !== strpos($type, '\\') ? $type : '\\think\\log\\driver\\' . ucwords($type); + $type = isset($config['type']) ? $config['type'] : 'File'; $this->config = $config; unset($config['type']); + if (!empty($config['close'])) { $this->allowWrite = false; } - if (class_exists($class)) { - $this->driver = new $class($config); - } else { - throw new ClassNotFoundException('class not exists:' . $class, $class); - } - - // 记录初始化信息 - $this->app->isDebug() && $this->record('[ LOG ] INIT ' . $type); + $this->driver = Loader::factory($type, '\\think\\log\\driver\\', $config); return $this; } @@ -200,14 +196,10 @@ class Log implements LoggerInterface */ public function save() { - if (empty($this->log) || !$this->allowWrite) { + if (empty($this->log) || !$this->allowWrite || !$this->driver) { return true; } - if (is_null($this->driver)) { - $this->init($this->app['config']->pull('log')); - } - if (!$this->check($this->config)) { // 检测日志写入权限 return false; @@ -261,10 +253,6 @@ class Log implements LoggerInterface // 监听log_write $this->app['hook']->listen('log_write', $log); - if (is_null($this->driver)) { - $this->init($this->app['config']->pull('log')); - } - // 写入日志 $result = $this->driver->save($log); diff --git a/thinkphp/library/think/Middleware.php b/thinkphp/library/think/Middleware.php index 6c2d22116..229ceaa43 100644 --- a/thinkphp/library/think/Middleware.php +++ b/thinkphp/library/think/Middleware.php @@ -18,6 +18,26 @@ use think\exception\HttpResponseException; class Middleware { protected $queue = []; + protected $app; + protected $config = [ + 'default_namespace' => 'app\\http\\middleware\\', + ]; + + public function __construct(App $app, array $config = []) + { + $this->app = $app; + $this->config = array_merge($this->config, $config); + } + + public static function __make(App $app, Config $config) + { + return new static($app, $config->pull('middleware')); + } + + public function setConfig(array $config) + { + $this->config = array_merge($this->config, $config); + } public function import(array $middlewares = []) { @@ -89,8 +109,11 @@ class Middleware } if (false === strpos($middleware, '\\')) { - $value = Container::get('config')->get('middleware.' . $middleware); - $middleware = $value ?: Container::get('app')->getNamespace() . '\\http\\middleware\\' . $middleware; + if (isset($this->config[$middleware])) { + $middleware = $this->config[$middleware]; + } else { + $middleware = $this->config['default_namespace'] . $middleware; + } } if (is_array($middleware)) { @@ -101,7 +124,7 @@ class Middleware list($middleware, $param) = explode(':', $middleware, 2); } - return [[Container::get($middleware), 'handle'], isset($param) ? $param : null]; + return [[$this->app->make($middleware), 'handle'], isset($param) ? $param : null]; } protected function resolve() diff --git a/thinkphp/library/think/Model.php b/thinkphp/library/think/Model.php index c1b2a625a..d2baf9995 100644 --- a/thinkphp/library/think/Model.php +++ b/thinkphp/library/think/Model.php @@ -32,6 +32,12 @@ abstract class Model implements \JsonSerializable, \ArrayAccess */ private $isUpdate = false; + /** + * 是否Replace + * @var bool + */ + private $replace = false; + /** * 是否强制更新所有数据 * @var bool @@ -141,13 +147,13 @@ abstract class Model implements \JsonSerializable, \ArrayAccess // 记录原始数据 $this->origin = $this->data; - $config = Container::get('config'); + $config = Db::getConfig(); if (empty($this->name)) { // 当前模型名 $name = str_replace('\\', '/', static::class); $this->name = basename($name); - if ($config->get('class_suffix')) { + if (Container::get('config')->get('class_suffix')) { $suffix = basename(dirname($name)); $this->name = substr($this->name, 0, -strlen($suffix)); } @@ -155,26 +161,26 @@ abstract class Model implements \JsonSerializable, \ArrayAccess if (is_null($this->autoWriteTimestamp)) { // 自动写入时间戳 - $this->autoWriteTimestamp = $config->get('database.auto_timestamp'); + $this->autoWriteTimestamp = $config['auto_timestamp']; } if (is_null($this->dateFormat)) { // 设置时间戳格式 - $this->dateFormat = $config->get('database.datetime_format'); + $this->dateFormat = $config['datetime_format']; } if (is_null($this->resultSetType)) { - $this->resultSetType = $config->get('database.resultset_type'); + $this->resultSetType = $config['resultset_type']; } if (is_null($this->query)) { // 设置查询对象 - $this->query = $config->get('database.query'); + $this->query = $config['query']; } if (!empty($this->connection) && is_array($this->connection)) { // 设置模型的数据库连接 - $this->connection = array_merge($config->pull('database'), $this->connection); + $this->connection = array_merge($config, $this->connection); } if ($this->observerClass) { @@ -232,9 +238,8 @@ abstract class Model implements \JsonSerializable, \ArrayAccess protected function buildQuery() { // 设置当前模型 确保查询返回模型对象 - $class = $this->query; - $query = (new $class())->connect($this->connection) - ->model($this) + $query = Db::connect($this->connection, false, $this->query); + $query->model($this) ->json($this->json) ->setJsonFieldType($this->jsonType); @@ -355,6 +360,18 @@ abstract class Model implements \JsonSerializable, \ArrayAccess return $this; } + /** + * 新增数据是否使用Replace + * @access public + * @param bool $replace + * @return $this + */ + public function replace($replace = true) + { + $this->replace = $replace; + return $this; + } + /** * 保存当前数据对象 * @access public @@ -559,7 +576,7 @@ abstract class Model implements \JsonSerializable, \ArrayAccess // 检查允许字段 $allowFields = $this->checkAllowFields(array_merge($this->auto, $this->insert)); - $result = $this->db(false)->strict(false)->field($allowFields)->insert($this->data, false, false, $sequence); + $result = $this->db(false)->strict(false)->field($allowFields)->insert($this->data, $this->replace, false, $sequence); // 获取自动增长主键 if ($result && $insertId = $this->db(false)->getLastInsID($sequence)) { @@ -780,9 +797,10 @@ abstract class Model implements \JsonSerializable, \ArrayAccess * @access public * @param array $data 数据数组 * @param array|true $field 允许字段 + * @param bool $replace 使用Replace * @return static */ - public static function create($data = [], $field = null) + public static function create($data = [], $field = null, $replace = false) { $model = new static(); @@ -790,7 +808,7 @@ abstract class Model implements \JsonSerializable, \ArrayAccess $model->allowField($field); } - $model->isUpdate(false)->save($data, []); + $model->isUpdate(false)->replace($replace)->save($data, []); return $model; } diff --git a/thinkphp/library/think/Request.php b/thinkphp/library/think/Request.php index 554623036..6a25c99f1 100644 --- a/thinkphp/library/think/Request.php +++ b/thinkphp/library/think/Request.php @@ -22,10 +22,16 @@ class Request protected $instance; /** - * 配置对象 - * @var Config + * 应用对象实例 + * @var App */ - protected $config; + protected $app; + + /** + * 配置参数 + * @var array + */ + protected $config = []; /** * 请求类型 @@ -262,24 +268,37 @@ class Request * @access public * @param array $options 参数 */ - public function __construct($options = []) + public function __construct(App $app, array $options = []) { - foreach ($options as $name => $item) { - if (property_exists($this, $name)) { - $this->$name = $item; - } - } - - $this->config = Container::get('config'); - - if (is_null($this->filter)) { - $this->filter = $this->config->get('default_filter'); - } + $this->app = $app; + $this->init($options); // 保存 php://input $this->input = file_get_contents('php://input'); } + public function init(array $options = []) + { + $this->config = array_merge($this->config, $options); + + if (is_null($this->filter) && !empty($this->config['default_filter'])) { + $this->filter = $this->config['default_filter']; + } + } + + public function config($name = null) + { + if (is_null($name)) { + return $this->config; + } + return isset($this->config[$name]) ? $this->config[$name] : null; + } + + public static function __make(App $app, Config $config) + { + return new static($app, $config->pull('app')); + } + public function __call($method, $args) { if (array_key_exists($method, $this->hook)) { @@ -431,7 +450,7 @@ class Request */ public function rootDomain() { - $root = $this->config->get('app.url_domain_root'); + $root = $this->config['url_domain_root']; if (!$root) { $item = explode('.', $this->host(true)); @@ -451,7 +470,7 @@ class Request { if (is_null($this->subDomain)) { // 获取当前主域名 - $rootDomain = $this->config->get('app.url_domain_root'); + $rootDomain = $this->config['url_domain_root']; if ($rootDomain) { // 配置域名根 例如 thinkphp.cn 163.com.cn 如果是国家级域名 com.cn net.cn 之类的域名需要配置 @@ -609,10 +628,10 @@ class Request public function pathinfo() { if (is_null($this->pathinfo)) { - if (isset($_GET[$this->config->get('var_pathinfo')])) { + if (isset($_GET[$this->config['var_pathinfo']])) { // 判断URL里面是否有兼容模式参数 - $_SERVER['PATH_INFO'] = $_GET[$this->config->get('var_pathinfo')]; - unset($_GET[$this->config->get('var_pathinfo')]); + $_SERVER['PATH_INFO'] = $_GET[$this->config['var_pathinfo']]; + unset($_GET[$this->config['var_pathinfo']]); } elseif ($this->isCli()) { // CLI模式下 index.php module/controller/action/params/... $_SERVER['PATH_INFO'] = isset($_SERVER['argv'][1]) ? $_SERVER['argv'][1] : ''; @@ -622,7 +641,7 @@ class Request // 分析PATHINFO信息 if (!isset($_SERVER['PATH_INFO'])) { - foreach ($this->config->get('pathinfo_fetch') as $type) { + foreach ($this->config['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]; @@ -645,7 +664,7 @@ class Request public function path() { if (is_null($this->path)) { - $suffix = $this->config->get('url_html_suffix'); + $suffix = $this->config['url_html_suffix']; $pathinfo = $this->pathinfo(); if (false === $suffix) { // 禁止伪静态访问 @@ -736,8 +755,8 @@ class Request // 获取原始请求类型 return $this->isCli() ? 'GET' : (isset($this->server['REQUEST_METHOD']) ? $this->server['REQUEST_METHOD'] : $_SERVER['REQUEST_METHOD']); } elseif (!$this->method) { - if (isset($_POST[$this->config->get('var_method')])) { - $this->method = strtoupper($_POST[$this->config->get('var_method')]); + if (isset($_POST[$this->config['var_method']])) { + $this->method = strtoupper($_POST[$this->config['var_method']]); $this->{$this->method}($_POST); } elseif (isset($_SERVER['HTTP_X_HTTP_METHOD_OVERRIDE'])) { $this->method = strtoupper($_SERVER['HTTP_X_HTTP_METHOD_OVERRIDE']); @@ -1033,7 +1052,7 @@ class Request public function session($name = '', $default = null, $filter = '') { if (empty($this->session)) { - $this->session = Container::get('session')->get(); + $this->session = $this->app['session']->get(); } if (is_array($name)) { @@ -1053,7 +1072,7 @@ class Request */ public function cookie($name = '', $default = null, $filter = '') { - $cookie = Container::get('cookie'); + $cookie = $this->app['cookie']; if (empty($this->cookie)) { $this->cookie = $cookie->get(); @@ -1190,7 +1209,7 @@ class Request public function env($name = '', $default = null, $filter = '') { if (empty($this->env)) { - $this->env = Container::get('env')->get(); + $this->env = $this->app['env']->get(); } if (is_array($name)) { @@ -1514,7 +1533,7 @@ class Request return true; } elseif (isset($server['HTTP_X_FORWARDED_PROTO']) && 'https' == $server['HTTP_X_FORWARDED_PROTO']) { return true; - } elseif ($this->config->get('https_agent_name') && isset($server[$this->config->get('https_agent_name')])) { + } elseif ($this->config['https_agent_name'] && isset($server[$this->config['https_agent_name']])) { return true; } @@ -1536,7 +1555,7 @@ class Request return $result; } - return $this->param($this->config->get('var_ajax')) ? true : $result; + return $this->param($this->config['var_ajax']) ? true : $result; } /** @@ -1553,7 +1572,7 @@ class Request return $result; } - return $this->param($this->config->get('var_pjax')) ? true : $result; + return $this->param($this->config['var_pjax']) ? true : $result; } /** @@ -1572,7 +1591,7 @@ class Request return $ip[$type]; } - $httpAgentIp = $this->config->get('http_agent_ip'); + $httpAgentIp = $this->config['http_agent_ip']; if ($httpAgentIp && isset($_SERVER[$httpAgentIp])) { $ip = $_SERVER[$httpAgentIp]; @@ -1866,7 +1885,7 @@ class Request header($name . ': ' . $token); } - Container::get('session')->set($name, $token); + $this->app['session']->set($name, $token); return $token; } @@ -1934,7 +1953,7 @@ class Request if (isset($fun)) { $key = $fun($key); } - $cache = Container::get('cache'); + $cache = $this->app['cache']; if (strtotime($this->server('HTTP_IF_MODIFIED_SINCE')) + $expire > $_SERVER['REQUEST_TIME']) { // 读取缓存 diff --git a/thinkphp/library/think/Response.php b/thinkphp/library/think/Response.php index de8feaac9..09cb6a924 100644 --- a/thinkphp/library/think/Response.php +++ b/thinkphp/library/think/Response.php @@ -21,6 +21,12 @@ class Response */ protected $data; + /** + * 应用对象实例 + * @var App + */ + protected $app; + /** * 当前contentType * @var string @@ -82,6 +88,7 @@ class Response $this->contentType($this->contentType, $this->charset); $this->code = $code; + $this->app = Container::get('app'); $this->header = array_merge($this->header, $header); } @@ -115,24 +122,24 @@ class Response public function send() { // 监听response_send - Container::get('hook')->listen('response_send', $this); + $this->app['hook']->listen('response_send', $this); // 处理输出数据 $data = $this->getContent(); // Trace调试注入 - if ('cli' != PHP_SAPI && Container::get('env')->get('app_trace', Container::get('app')->config('app.app_trace'))) { - Container::get('debug')->inject($this, $data); + if ('cli' != PHP_SAPI && $this->app['env']->get('app_trace', $this->app->config('app.app_trace'))) { + $this->app['debug']->inject($this, $data); } if (200 == $this->code && $this->allowCache) { - $cache = Container::get('request')->getCache(); + $cache = $this->app['request']->getCache(); if ($cache) { $this->header['Cache-Control'] = 'max-age=' . $cache[1] . ',must-revalidate'; $this->header['Last-Modified'] = gmdate('D, d M Y H:i:s') . ' GMT'; $this->header['Expires'] = gmdate('D, d M Y H:i:s', $_SERVER['REQUEST_TIME'] + $cache[1]) . ' GMT'; - Container::get('cache')->tag($cache[2])->set($cache[0], [$data, $this->header], $cache[1]); + $this->app['cache']->tag($cache[2])->set($cache[0], [$data, $this->header], $cache[1]); } } @@ -153,11 +160,11 @@ class Response } // 监听response_end - Container::get('hook')->listen('response_end', $this); + $this->app['hook']->listen('response_end', $this); // 清空当次请求有效的数据 if (!($this instanceof RedirectResponse)) { - Container::get('session')->flush(); + $this->app['session']->flush(); } } diff --git a/thinkphp/library/think/Route.php b/thinkphp/library/think/Route.php index a1c9f8766..4b403a15f 100644 --- a/thinkphp/library/think/Route.php +++ b/thinkphp/library/think/Route.php @@ -48,10 +48,10 @@ class Route ]; /** - * 配置对象 - * @var Config + * 应用对象 + * @var App */ - protected $config; + protected $app; /** * 请求对象 @@ -77,6 +77,12 @@ class Route */ protected $group; + /** + * 配置参数 + * @var array + */ + protected $config = []; + /** * 路由绑定 * @var array @@ -119,14 +125,37 @@ class Route */ protected $autoSearchController = true; - public function __construct(Request $request) + public function __construct(App $app, array $config = []) { - $this->request = $request; + $this->app = $app; + $this->request = $app['request']; + $this->config = $config; $this->host = $this->request->host(true); $this->setDefaultDomain(); } + public function config($name = null) + { + if (is_null($name)) { + return $this->config; + } + + return isset($this->config[$name]) ? $this->config[$name] : null; + } + + public static function __make(App $app, Config $config) + { + $config = $config->pull('app'); + $route = new static($app, $config); + + $route->lazy($config['url_lazy_route']) + ->autoSearchController($config['controller_auto_search']) + ->mergeRuleRegex($config['route_rule_merge']); + + return $route; + } + /** * 设置路由域名及分组(包括资源路由)是否延迟解析 * @access public @@ -346,7 +375,7 @@ class Route */ public function getName($name = null) { - return Container::get('rule_name')->get($name); + return $this->app['rule_name']->get($name); } /** @@ -357,7 +386,7 @@ class Route */ public function setName($name) { - Container::get('rule_name')->import($name); + $this->app['rule_name']->import($name); return $this; } @@ -761,23 +790,23 @@ class Route * 检测URL路由 * @access public * @param string $url URL地址 - * @param string $depr URL分隔符 * @param bool $must 是否强制路由 - * @param bool $completeMatch 路由是否完全匹配 * @return Dispatch * @throws RouteNotFoundException */ - public function check($url, $depr = '/', $must = false, $completeMatch = false) + public function check($url, $must = false) { // 自动检测域名路由 $domain = $this->checkDomain(); - $url = str_replace($depr, '|', $url); + $url = str_replace($this->config['pathinfo_depr'], '|', $url); - $result = $domain->check($this->request, $url, $depr, $completeMatch); + $completeMatch = $this->config['route_complete_match']; + + $result = $domain->check($this->request, $url, $completeMatch); if (false === $result && !empty($this->cross)) { // 检测跨域路由 - $result = $this->cross->check($this->request, $url, $depr, $completeMatch); + $result = $this->cross->check($this->request, $url, $completeMatch); } if (false !== $result) { @@ -789,7 +818,9 @@ class Route } // 默认路由解析 - return new UrlDispatch($url, ['depr' => $depr, 'auto_search' => $this->autoSearchController]); + $ruleItem = new RuleItem($this, $this->group, '', '', $url); + + return new UrlDispatch($this->request, $ruleItem, $url, ['auto_search' => $this->autoSearchController]); } /** diff --git a/thinkphp/library/think/Session.php b/thinkphp/library/think/Session.php index f52bbc623..2d05599c4 100644 --- a/thinkphp/library/think/Session.php +++ b/thinkphp/library/think/Session.php @@ -15,6 +15,12 @@ use think\exception\ClassNotFoundException; class Session { + /** + * 配置参数 + * @var array + */ + protected $config = []; + /** * 前缀 * @var string @@ -51,6 +57,11 @@ class Session */ protected $lock = false; + public function __construct(array $config = []) + { + $this->config = $config; + } + /** * 设置或者获取session作用域(前缀) * @access public @@ -68,6 +79,22 @@ class Session } } + public static function __make(Config $config) + { + return new static($config->pull('session')); + } + + /** + * 配置 + * @access public + * @param array $config + * @return void + */ + public function setConfig(array $config = []) + { + $this->config = array_merge($this->config, array_change_key_case($config)); + } + /** * session初始化 * @access public @@ -77,12 +104,8 @@ class Session */ public function init(array $config = []) { - if (empty($config)) { - $config = Container::get('config')->pull('session'); - } + $config = $config ?: $this->config; - // 记录初始化信息 - Container::get('app')->log('[ SESSION ] INIT ' . var_export($config, true)); $isDoStart = false; if (isset($config['use_trans_sid'])) { ini_set('session.use_trans_sid', $config['use_trans_sid'] ? 1 : 0); @@ -161,6 +184,8 @@ class Session } else { $this->init = false; } + + return $this; } /** @@ -253,8 +278,7 @@ class Session */ protected function initDriver() { - // 不在 init 方法中实例化lockDriver,是因为 init 方法不一定先于 set 或 get 方法调用 - $config = Container::get('config')->pull('session'); + $config = $this->config; if (!empty($config['type']) && isset($config['use_lock']) && $config['use_lock']) { // 读取session驱动 diff --git a/thinkphp/library/think/Template.php b/thinkphp/library/think/Template.php index ef4a197f4..50dad097e 100644 --- a/thinkphp/library/think/Template.php +++ b/thinkphp/library/think/Template.php @@ -20,6 +20,7 @@ use think\exception\TemplateNotFoundException; */ class Template { + protected $app; /** * 模板变量 * @var array @@ -83,9 +84,10 @@ class Template * @access public * @param array $config */ - public function __construct(array $config = []) + public function __construct(App $app, array $config = []) { - $this->config['cache_path'] = Container::get('app')->getRuntimePath() . 'temp/'; + $this->app = $app; + $this->config['cache_path'] = $app->getRuntimePath() . 'temp/'; $this->config = array_merge($this->config, $config); $this->config['taglib_begin_origin'] = $this->config['taglib_begin']; @@ -97,10 +99,14 @@ class Template $this->config['tpl_end'] = preg_quote($this->config['tpl_end'], '/'); // 初始化模板编译存储器 - $type = $this->config['compile_type'] ? $this->config['compile_type'] : 'File'; - $class = false !== strpos($type, '\\') ? $type : '\\think\\template\\driver\\' . ucwords($type); + $type = $this->config['compile_type'] ? $this->config['compile_type'] : 'File'; - $this->storage = new $class(); + $this->storage = Loader::factory($type, '\\think\\template\\driver\\', null); + } + + public static function __make(Config $config) + { + return new static($config->pull('template')); } /** @@ -189,7 +195,7 @@ class Template $this->config($config); } - $cache = Container::get('cache'); + $cache = $this->app['cache']; if (!empty($this->config['cache_id']) && $this->config['display_cache']) { // 读取渲染缓存 @@ -337,7 +343,7 @@ class Template { if ($cacheId && $this->config['display_cache']) { // 缓存页面输出 - return Container::get('cache')->has($cacheId); + return $this->app['cache']->has($cacheId); } return false; @@ -1218,10 +1224,10 @@ class Template } if ($this->config['view_base']) { - $module = isset($module) ? $module : Container::get('request')->module(); + $module = isset($module) ? $module : $this->app['request']->module(); $path = $this->config['view_base'] . ($module ? $module . DIRECTORY_SEPARATOR : ''); } else { - $path = isset($module) ? Container::get('app')->getAppPath() . $module . DIRECTORY_SEPARATOR . basename($this->config['view_path']) . DIRECTORY_SEPARATOR : $this->config['view_path']; + $path = isset($module) ? $this->app->getAppPath() . $module . DIRECTORY_SEPARATOR . basename($this->config['view_path']) . DIRECTORY_SEPARATOR : $this->config['view_path']; } $template = $path . $template . '.' . ltrim($this->config['view_suffix'], '.'); diff --git a/thinkphp/library/think/Url.php b/thinkphp/library/think/Url.php index 89e69f838..7cbdfffa5 100644 --- a/thinkphp/library/think/Url.php +++ b/thinkphp/library/think/Url.php @@ -13,6 +13,12 @@ namespace think; class Url { + /** + * 配置参数 + * @var array + */ + protected $config = []; + /** * ROOT地址 * @var string @@ -31,9 +37,10 @@ class Url */ protected $app; - public function __construct(App $app) + public function __construct(App $app, array $config = []) { - $this->app = $app; + $this->app = $app; + $this->config = $config; if (is_file($app->getRuntimePath() . 'route.php')) { // 读取路由映射文件 @@ -41,6 +48,22 @@ class Url } } + /** + * 初始化 + * @access public + * @param array $config + * @return void + */ + public function init(array $config = []) + { + $this->config = array_merge($this->config, array_change_key_case($config)); + } + + public static function __make(App $app, Config $config) + { + return new static($app, $config->pull('app')); + } + /** * URL生成 支持路由反射 * @access public @@ -105,7 +128,7 @@ class Url $url = $match[0]; if (!empty($match[1])) { - $host = $this->app['config']->get('app_host') ?: $this->app['request']->host(true); + $host = $this->config['app_host'] ?: $this->app['request']->host(true); if ($domain || $match[1] != $host) { $domain = $match[1]; } @@ -166,7 +189,7 @@ class Url } // 还原URL分隔符 - $depr = $this->app['config']->get('pathinfo_depr'); + $depr = $this->config['pathinfo_depr']; $url = str_replace('/', $depr, $url); // URL后缀 @@ -182,11 +205,11 @@ class Url // 参数组装 if (!empty($vars)) { // 添加参数 - if ($this->app['config']->get('url_common_param')) { + if ($this->config['url_common_param']) { $vars = http_build_query($vars); $url .= $suffix . '?' . $vars . $anchor; } else { - $paramType = $this->app['config']->get('url_param_type'); + $paramType = $this->config['url_param_type']; foreach ($vars as $var => $val) { if ('' !== trim($val)) { @@ -244,7 +267,7 @@ class Url $module = empty($path) ? $module : array_pop($path) . '/'; } - if ($this->app['config']->get('url_convert')) { + if ($this->config['url_convert']) { $action = strtolower($action); $controller = Loader::parseName($controller); } @@ -265,7 +288,7 @@ class Url $rootDomain = $this->app['request']->rootDomain(); if (true === $domain) { // 自动判断域名 - $domain = $this->app['config']->get('app_host') ?: $this->app['request']->host(true); + $domain = $this->config['app_host'] ?: $this->app['request']->host(true); $domains = $this->app['route']->getDomains(); @@ -302,7 +325,7 @@ class Url if (false !== strpos($domain, '://')) { $scheme = ''; } else { - $scheme = $this->app['request']->isSsl() || $this->app['config']->get('is_https') ? 'https://' : 'http://'; + $scheme = $this->app['request']->isSsl() || $this->config['is_https'] ? 'https://' : 'http://'; } @@ -313,7 +336,7 @@ class Url protected function parseSuffix($suffix) { if ($suffix) { - $suffix = true === $suffix ? $this->app['config']->get('url_html_suffix') : $suffix; + $suffix = true === $suffix ? $this->config['url_html_suffix'] : $suffix; if ($pos = strpos($suffix, '|')) { $suffix = substr($suffix, 0, $pos); @@ -332,7 +355,7 @@ class Url return [rtrim($url, '?/-'), $domain, $suffix]; } - $type = $this->app['config']->get('url_common_param'); + $type = $this->config['url_common_param']; foreach ($pattern as $key => $val) { if (isset($vars[$key])) { diff --git a/thinkphp/library/think/Validate.php b/thinkphp/library/think/Validate.php index bb1700459..bddbc69d7 100644 --- a/thinkphp/library/think/Validate.php +++ b/thinkphp/library/think/Validate.php @@ -1078,7 +1078,7 @@ class Validate */ public function requireCallback($value, $rule, $data) { - $result = call_user_func_array($rule, [$value, $data]); + $result = call_user_func_array([$this, $rule], [$value, $data]); if ($result) { return !empty($value) || '0' == $value; @@ -1447,12 +1447,12 @@ class Validate $scene = $this->currentScene; } - $this->only = $this->append = $this->remove = []; - if (empty($scene)) { return; } + $this->only = $this->append = $this->remove = []; + if (method_exists($this, 'scene' . $scene)) { call_user_func([$this, 'scene' . $scene]); } elseif (isset($this->scene[$scene])) { diff --git a/thinkphp/library/think/View.php b/thinkphp/library/think/View.php index 6127235d9..4212438f9 100644 --- a/thinkphp/library/think/View.php +++ b/thinkphp/library/think/View.php @@ -51,6 +51,11 @@ class View return $this; } + public static function __make(Config $config) + { + return (new static())->init($config->pull('template')); + } + /** * 模板变量静态赋值 * @access public @@ -102,13 +107,11 @@ class View $type = !empty($options['type']) ? $options['type'] : 'Think'; } - $class = false !== strpos($type, '\\') ? $type : '\\think\\view\\driver\\' . ucfirst($type); - if (isset($options['type'])) { unset($options['type']); } - $this->engine = new $class($options); + $this->engine = Loader::factory($type, '\\think\\view\\driver\\', $options); return $this; } diff --git a/thinkphp/library/think/config/driver/Ini.php b/thinkphp/library/think/config/driver/Ini.php index bcd12b697..b2a647d11 100644 --- a/thinkphp/library/think/config/driver/Ini.php +++ b/thinkphp/library/think/config/driver/Ini.php @@ -13,12 +13,19 @@ namespace think\config\driver; class Ini { - public function parse($config) + protected $config; + + public function __construct($config) { - if (is_file($config)) { - return parse_ini_file($config, true); + $this->config = $config; + } + + public function parse() + { + if (is_file($this->config)) { + return parse_ini_file($this->config, true); } else { - return parse_ini_string($config, true); + return parse_ini_string($this->config, true); } } } diff --git a/thinkphp/library/think/config/driver/Json.php b/thinkphp/library/think/config/driver/Json.php index 808bfff80..0d77c8edc 100644 --- a/thinkphp/library/think/config/driver/Json.php +++ b/thinkphp/library/think/config/driver/Json.php @@ -13,14 +13,19 @@ namespace think\config\driver; class Json { - public function parse($config) + protected $config; + + public function __construct($config) { if (is_file($config)) { $config = file_get_contents($config); } - $result = json_decode($config, true); + $this->config = $config; + } - return $result; + public function parse() + { + return json_decode($this->config, true); } } diff --git a/thinkphp/library/think/config/driver/Xml.php b/thinkphp/library/think/config/driver/Xml.php index b149b57fa..9d6963384 100644 --- a/thinkphp/library/think/config/driver/Xml.php +++ b/thinkphp/library/think/config/driver/Xml.php @@ -13,12 +13,19 @@ namespace think\config\driver; class Xml { - public function parse($config) + protected $config; + + public function __construct($config) { - if (is_file($config)) { - $content = simplexml_load_file($config); + $this->config = $config; + } + + public function parse() + { + if (is_file($this->config)) { + $content = simplexml_load_file($this->config); } else { - $content = simplexml_load_string($config); + $content = simplexml_load_string($this->config); } $result = (array) $content; diff --git a/thinkphp/library/think/console/command/Clear.php b/thinkphp/library/think/console/command/Clear.php index 7ee31ea73..144257593 100644 --- a/thinkphp/library/think/console/command/Clear.php +++ b/thinkphp/library/think/console/command/Clear.php @@ -15,6 +15,7 @@ use think\console\Input; use think\console\input\Option; use think\console\Output; use think\facade\App; +use think\facade\Cache; class Clear extends Command { @@ -25,6 +26,7 @@ class Clear extends Command ->setName('clear') ->addOption('path', 'd', Option::VALUE_OPTIONAL, 'path to clear', null) ->addOption('cache', 'c', Option::VALUE_NONE, 'clear cache file') + ->addOption('route', 'u', Option::VALUE_NONE, 'clear route cache') ->addOption('log', 'l', Option::VALUE_NONE, 'clear log file') ->addOption('dir', 'r', Option::VALUE_NONE, 'clear empty dir') ->setDescription('Clear runtime file'); @@ -32,16 +34,21 @@ class Clear extends Command protected function execute(Input $input, Output $output) { - if ($input->getOption('cache')) { - $path = App::getRuntimePath() . 'cache'; - } elseif ($input->getOption('log')) { - $path = App::getRuntimePath() . 'log'; + if ($input->getOption('route')) { + Cache::clear('route_cache'); } else { - $path = $input->getOption('path') ?: App::getRuntimePath(); + if ($input->getOption('cache')) { + $path = App::getRuntimePath() . 'cache'; + } elseif ($input->getOption('log')) { + $path = App::getRuntimePath() . 'log'; + } else { + $path = $input->getOption('path') ?: App::getRuntimePath(); + } + + $rmdir = $input->getOption('dir') ? true : false; + $this->clear(rtrim($path, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR, $rmdir); } - $rmdir = $input->getOption('dir') ? true : false; - $this->clear(rtrim($path, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR, $rmdir); $output->writeln("