Browse Source

[更新]composerUpdate

Anyon 7 years ago
parent
commit
ffa548b924
74 changed files with 1872 additions and 2819 deletions
  1. 1 1
      composer.json
  2. 6 5
      thinkphp/README.md
  3. 18 20
      thinkphp/base.php
  4. 1 9
      thinkphp/convention.php
  5. 2 7
      thinkphp/helper.php
  6. 1 6
      thinkphp/lang/zh-cn.php
  7. 40 72
      thinkphp/library/think/App.php
  8. 15 48
      thinkphp/library/think/Build.php
  9. 7 6
      thinkphp/library/think/Config.php
  10. 3 35
      thinkphp/library/think/Console.php
  11. 67 137
      thinkphp/library/think/Container.php
  12. 10 11
      thinkphp/library/think/Controller.php
  13. 1 3
      thinkphp/library/think/Db.php
  14. 2 1
      thinkphp/library/think/Debug.php
  15. 12 12
      thinkphp/library/think/Env.php
  16. 2 2
      thinkphp/library/think/Error.php
  17. 0 4
      thinkphp/library/think/Facade.php
  18. 52 52
      thinkphp/library/think/File.php
  19. 6 3
      thinkphp/library/think/Hook.php
  20. 2 2
      thinkphp/library/think/Lang.php
  21. 18 33
      thinkphp/library/think/Loader.php
  22. 28 51
      thinkphp/library/think/Log.php
  23. 13 13
      thinkphp/library/think/Model.php
  24. 2 2
      thinkphp/library/think/Paginator.php
  25. 104 172
      thinkphp/library/think/Request.php
  26. 4 4
      thinkphp/library/think/Response.php
  27. 314 130
      thinkphp/library/think/Route.php
  28. 65 29
      thinkphp/library/think/Template.php
  29. 10 9
      thinkphp/library/think/Url.php
  30. 27 28
      thinkphp/library/think/Validate.php
  31. 3 6
      thinkphp/library/think/cache/driver/File.php
  32. 1 36
      thinkphp/library/think/cache/driver/Redis.php
  33. 1 1
      thinkphp/library/think/console/command/Clear.php
  34. 1 1
      thinkphp/library/think/console/command/RunServer.php
  35. 2 9
      thinkphp/library/think/console/command/make/Controller.php
  36. 0 36
      thinkphp/library/think/console/command/make/Middleware.php
  37. 1 1
      thinkphp/library/think/console/command/make/Model.php
  38. 0 64
      thinkphp/library/think/console/command/make/stubs/controller.api.stub
  39. 0 10
      thinkphp/library/think/console/command/make/stubs/middleware.stub
  40. 2 15
      thinkphp/library/think/console/command/optimize/Config.php
  41. 2 4
      thinkphp/library/think/console/command/optimize/Route.php
  42. 1 1
      thinkphp/library/think/console/command/optimize/Schema.php
  43. 10 28
      thinkphp/library/think/db/Builder.php
  44. 250 270
      thinkphp/library/think/db/Connection.php
  45. 108 190
      thinkphp/library/think/db/Query.php
  46. 2 2
      thinkphp/library/think/db/builder/Mysql.php
  47. 1 1
      thinkphp/library/think/debug/Html.php
  48. 21 48
      thinkphp/library/think/http/middleware/Dispatcher.php
  49. 45 0
      thinkphp/library/think/http/middleware/DispatcherInterface.php
  50. 4 16
      thinkphp/library/think/http/middleware/MissingResponseException.php
  51. 69 0
      thinkphp/library/think/http/tests/middleware/DispatcherTest.php
  52. 7 24
      thinkphp/library/think/log/driver/File.php
  53. 12 0
      thinkphp/library/think/model/Collection.php
  54. 49 67
      thinkphp/library/think/model/concern/Attribute.php
  55. 4 4
      thinkphp/library/think/model/concern/RelationShip.php
  56. 4 3
      thinkphp/library/think/model/concern/SoftDelete.php
  57. 1 24
      thinkphp/library/think/model/relation/BelongsTo.php
  58. 2 28
      thinkphp/library/think/model/relation/HasOne.php
  59. 1 1
      thinkphp/library/think/model/relation/MorphMany.php
  60. 1 1
      thinkphp/library/think/process/pipes/Windows.php
  61. 1 0
      thinkphp/library/think/response/View.php
  62. 0 9
      thinkphp/library/think/response/Xml.php
  63. 0 126
      thinkphp/library/think/route/AliasRule.php
  64. 91 55
      thinkphp/library/think/route/Domain.php
  65. 24 22
      thinkphp/library/think/route/Resource.php
  66. 78 248
      thinkphp/library/think/route/Rule.php
  67. 79 309
      thinkphp/library/think/route/RuleGroup.php
  68. 136 154
      thinkphp/library/think/route/RuleItem.php
  69. 0 63
      thinkphp/library/think/route/RuleName.php
  70. 7 17
      thinkphp/library/think/route/dispatch/Module.php
  71. 1 1
      vendor/autoload.php
  72. 7 7
      vendor/composer/autoload_real.php
  73. 4 4
      vendor/composer/autoload_static.php
  74. 6 6
      vendor/composer/installed.json

+ 1 - 1
composer.json

@@ -18,7 +18,7 @@
   "require": {
     "php": ">=5.6.0",
     "endroid/qrcode": "^1.9",
-    "topthink/framework": "5.1.*",
+    "topthink/framework": "5.1.5",
     "zoujingli/ip2region": "dev-master",
     "aliyuncs/oss-sdk-php": "^2.2",
     "zoujingli/weopen-developer": "dev-master",

+ 6 - 5
thinkphp/README.md

@@ -1,11 +1,12 @@
-![](http://www.thinkphp.cn/Uploads/editor/2016-06-23/576b4732a6e04.png) 
-
-ThinkPHP 5.1 —— 12载初心,你值得信赖的PHP框架
+ThinkPHP 5.1
 ===============
 
+[![StyleCI](https://styleci.io/repos/48530411/shield?style=flat&branch=master)](https://styleci.io/repos/48530411)
 [![Build Status](https://travis-ci.org/top-think/framework.svg?branch=master)](https://travis-ci.org/top-think/framework)
+[![codecov.io](http://codecov.io/github/top-think/framework/coverage.svg?branch=master)](http://codecov.io/github/github/top-think/framework?branch=master)
 [![Total Downloads](https://poser.pugx.org/topthink/framework/downloads)](https://packagist.org/packages/topthink/framework)
 [![Latest Stable Version](https://poser.pugx.org/topthink/framework/v/stable)](https://packagist.org/packages/topthink/framework)
+[![Latest Unstable Version](https://poser.pugx.org/topthink/framework/v/unstable)](https://packagist.org/packages/topthink/framework)
 [![License](https://poser.pugx.org/topthink/framework/license)](https://packagist.org/packages/topthink/framework)
 
 ThinkPHP5.1对底层架构做了进一步的改进,减少依赖,其主要特性包括:
@@ -29,12 +30,12 @@ ThinkPHP5.1对底层架构做了进一步的改进,减少依赖,其主要特
  + 内置控制器扩展类
  + 模型自动验证
 
-> ThinkPHP5.1的运行环境要求PHP5.6+
+> ThinkPHP5的运行环境要求PHP5.6以上
 
 
 ## 在线手册
 
-+ [完全开发手册](https://www.kancloud.cn/manual/thinkphp5_1/content)
++ [完全开发手册](https://www.kancloud.cn/manual/thinkphp5_1)
 + [升级指导](https://www.kancloud.cn/manual/thinkphp5_1/354155) 
 
 ## 命名规范

+ 18 - 20
thinkphp/base.php

@@ -40,7 +40,6 @@ Container::getInstance()->bind([
     'hook'                  => Hook::class,
     'lang'                  => Lang::class,
     'log'                   => Log::class,
-    'middleware'            => Middleware::class,
     'request'               => Request::class,
     'response'              => Response::class,
     'route'                 => Route::class,
@@ -48,31 +47,30 @@ Container::getInstance()->bind([
     'url'                   => Url::class,
     'validate'              => Validate::class,
     'view'                  => View::class,
-    'rule_name'             => route\RuleName::class,
+    'middlewareDispatcher'  => http\middleware\Dispatcher::class,
     // 接口依赖注入
     'think\LoggerInterface' => Log::class,
 ]);
 
 // 注册核心类的静态代理
 Facade::bind([
-    facade\App::class        => App::class,
-    facade\Build::class      => Build::class,
-    facade\Cache::class      => Cache::class,
-    facade\Config::class     => Config::class,
-    facade\Cookie::class     => Cookie::class,
-    facade\Debug::class      => Debug::class,
-    facade\Env::class        => Env::class,
-    facade\Hook::class       => Hook::class,
-    facade\Lang::class       => Lang::class,
-    facade\Log::class        => Log::class,
-    facade\Middleware::class => Middleware::class,
-    facade\Request::class    => Request::class,
-    facade\Response::class   => Response::class,
-    facade\Route::class      => Route::class,
-    facade\Session::class    => Session::class,
-    facade\Url::class        => Url::class,
-    facade\Validate::class   => Validate::class,
-    facade\View::class       => View::class,
+    facade\App::class      => App::class,
+    facade\Build::class    => Build::class,
+    facade\Cache::class    => Cache::class,
+    facade\Config::class   => Config::class,
+    facade\Cookie::class   => Cookie::class,
+    facade\Debug::class    => Debug::class,
+    facade\Env::class      => Env::class,
+    facade\Hook::class     => Hook::class,
+    facade\Lang::class     => Lang::class,
+    facade\Log::class      => Log::class,
+    facade\Request::class  => Request::class,
+    facade\Response::class => Response::class,
+    facade\Route::class    => Route::class,
+    facade\Session::class  => Session::class,
+    facade\Url::class      => Url::class,
+    facade\Validate::class => Validate::class,
+    facade\View::class     => View::class,
 ]);
 
 // 注册类库别名

+ 1 - 9
thinkphp/convention.php

@@ -30,7 +30,7 @@ return [
         // 默认JSONP处理方法
         'var_jsonp_handler'      => 'callback',
         // 默认时区
-        'default_timezone'       => 'Asia/Shanghai',
+        'default_timezone'       => 'PRC',
         // 是否开启多语言
         'lang_switch_on'         => false,
         // 默认全局过滤方法 用逗号分隔多个
@@ -89,8 +89,6 @@ return [
         'url_lazy_route'         => false,
         // 是否强制使用路由
         'url_route_must'         => false,
-        // 合并路由规则
-        'route_rule_merge'       => false,
         // 路由是否完全匹配
         'route_complete_match'   => false,
         // 使用注解路由
@@ -291,10 +289,4 @@ return [
         'list_rows' => 15,
     ],
 
-    //控制台配置
-    'console'  => [
-        'name'    => 'Think Console',
-        'version' => '0.1',
-        'user'    => null,
-    ],
 ];

+ 2 - 7
thinkphp/helper.php

@@ -29,7 +29,6 @@ use think\facade\Request;
 use think\facade\Route;
 use think\facade\Session;
 use think\facade\Url;
-use think\Loader;
 use think\Response;
 use think\route\RuleItem;
 
@@ -371,7 +370,7 @@ if (!function_exists('input')) {
      * @param string    $filter 过滤方法
      * @return mixed
      */
-    function input($key = '', $default = null, $filter = '')
+    function input($key = '', $default = null, $filter = null)
     {
         if (0 === strpos($key, '?')) {
             $key = substr($key, 1);
@@ -654,15 +653,11 @@ if (!function_exists('view')) {
      * @param string    $template 模板文件
      * @param array     $vars 模板变量
      * @param integer   $code 状态码
-     * @param callable  $filter 内容过滤
+     * @param callable  $filer 内容过滤
      * @return \think\response\View
      */
     function view($template = '', $vars = [], $code = 200, $filter = null)
     {
-        if ('' === $template) {
-            $template = Loader::parseName(request()->action(true));
-        }
-
         return Response::create($template, 'view', $code)->assign($vars)->filter($filter);
     }
 }

+ 1 - 6
thinkphp/lang/zh-cn.php

@@ -24,7 +24,6 @@ return [
     'dispatch type not support'                                 => '不支持的调度类型',
     'method param miss'                                         => '方法参数错误',
     'method not exists'                                         => '方法不存在',
-    'function not exists'                                       => '函数不存在',
     'module not exists'                                         => '模块不存在',
     'controller not exists'                                     => '控制器不存在',
     'class not exists'                                          => '类不存在',
@@ -33,7 +32,7 @@ return [
     'illegal controller name'                                   => '非法的控制器名称',
     'illegal action name'                                       => '非法的操作名称',
     'url suffix deny'                                           => '禁止的URL后缀访问',
-    'Route Not Found'                                           => '当前访问路由未定义或不匹配',
+    'Route Not Found'                                           => '当前访问路由未定义',
     'Undefined db type'                                         => '未定义数据库类型',
     'variable type error'                                       => '变量类型错误',
     'PSR-4 error'                                               => 'PSR-4 规范错误',
@@ -67,8 +66,6 @@ return [
     'relation data not exists'                                  => '关联数据不存在',
     'relation not support'                                      => '关联不支持',
     'chunk not support order'                                   => 'Chunk不支持调用order方法',
-    'route pattern error'                                       => '路由变量规则定义错误',
-    'route behavior will not support'                           => '路由行为废弃(使用中间件替代)',
 
     // 上传错误信息
     'unknown upload error'                                      => '未知上传错误!',
@@ -86,8 +83,6 @@ return [
     'filesize not match'                                        => '上传文件大小不符!',
     'directory {:path} creation failed'                         => '目录 {:path} 创建失败!',
 
-    'The middleware must return Response instance'              => '中间件方法必须返回Response对象实例',
-    'The queue was exhausted, with no response returned'        => '中间件队列为空',
     // Validate Error Message
     ':attribute require'                                        => ':attribute不能为空',
     ':attribute must'                                           => ':attribute必须',

+ 40 - 72
thinkphp/library/think/App.php

@@ -20,7 +20,7 @@ use think\route\Dispatch;
  */
 class App implements \ArrayAccess
 {
-    const VERSION = '5.1.6';
+    const VERSION = '5.1.5';
 
     /**
      * 当前模块路径
@@ -126,7 +126,7 @@ class App implements \ArrayAccess
 
     public function __construct($appPath = '')
     {
-        $this->appPath   = $appPath ?: realpath(dirname(dirname($_SERVER['SCRIPT_FILENAME'])) . DIRECTORY_SEPARATOR . 'application') . DIRECTORY_SEPARATOR;
+        $this->appPath   = $appPath ?: realpath(dirname($_SERVER['SCRIPT_FILENAME']) . '/../application') . '/';
         $this->container = Container::getInstance();
     }
 
@@ -163,11 +163,11 @@ class App implements \ArrayAccess
     {
         $this->beginTime   = microtime(true);
         $this->beginMem    = memory_get_usage();
-        $this->thinkPath   = dirname(dirname(__DIR__)) . DIRECTORY_SEPARATOR;
-        $this->rootPath    = dirname(realpath($this->appPath)) . DIRECTORY_SEPARATOR;
-        $this->runtimePath = $this->rootPath . 'runtime' . DIRECTORY_SEPARATOR;
-        $this->routePath   = $this->rootPath . 'route' . DIRECTORY_SEPARATOR;
-        $this->configPath  = $this->rootPath . 'config' . DIRECTORY_SEPARATOR;
+        $this->thinkPath   = dirname(dirname(__DIR__)) . '/';
+        $this->rootPath    = dirname(realpath($this->appPath)) . '/';
+        $this->runtimePath = $this->rootPath . 'runtime/';
+        $this->routePath   = $this->rootPath . 'route/';
+        $this->configPath  = $this->rootPath . 'config/';
 
         // 设置路径环境变量
         $this->env->set([
@@ -177,8 +177,8 @@ class App implements \ArrayAccess
             'config_path'  => $this->configPath,
             'route_path'   => $this->routePath,
             'runtime_path' => $this->runtimePath,
-            'extend_path'  => $this->rootPath . 'extend' . DIRECTORY_SEPARATOR,
-            'vendor_path'  => $this->rootPath . 'vendor' . DIRECTORY_SEPARATOR,
+            'extend_path'  => $this->rootPath . 'extend/',
+            'vendor_path'  => $this->rootPath . 'vendor/',
         ]);
 
         // 加载环境变量配置文件
@@ -228,9 +228,6 @@ class App implements \ArrayAccess
         // 设置系统时区
         date_default_timezone_set($this->config('app.default_timezone'));
 
-        // 读取语言包
-        $this->loadLangPack();
-
         // 监听app_init
         $this->hook->listen('app_init');
     }
@@ -255,10 +252,7 @@ class App implements \ArrayAccess
         } else {
             // 加载行为扩展文件
             if (is_file($path . 'tags.php')) {
-                $tags = include $path . 'tags.php';
-                if (is_array($tags)) {
-                    $this->hook->import($tags);
-                }
+                $this->hook->import(include $path . 'tags.php');
             }
 
             // 加载公共文件
@@ -269,21 +263,11 @@ class App implements \ArrayAccess
             if ('' == $module) {
                 // 加载系统助手函数
                 include $this->thinkPath . 'helper.php';
-                // 加载全局中间件
-                if (is_file($path . 'middleware.php')) {
-                    $middleware = include $path . 'middleware.php';
-                    if (is_array($middleware)) {
-                        $this->middleware->import($middleware);
-                    }
-                }
             }
 
             // 注册服务的容器对象实例
             if (is_file($path . 'provider.php')) {
-                $provider = include $path . 'provider.php';
-                if (is_array($provider)) {
-                    $this->container->bind($provider);
-                }
+                $this->container->bind(include $path . 'provider.php');
             }
 
             // 自动读取配置文件
@@ -314,10 +298,10 @@ class App implements \ArrayAccess
      */
     public function run()
     {
-        try {
-            // 初始化应用
-            $this->initialize();
+        // 初始化应用
+        $this->initialize();
 
+        try {
             if ($this->bind) {
                 // 模块/控制器绑定
                 $this->route->bind($this->bind);
@@ -329,18 +313,28 @@ class App implements \ArrayAccess
                 }
             }
 
+            // 读取默认语言
+            $this->lang->range($this->config('app.default_lang'));
+            if ($this->config('app.lang_switch_on')) {
+                // 开启多语言机制 检测当前语言
+                $this->lang->detect();
+            }
+
+            $this->request->langset($this->lang->range());
+
+            // 加载系统语言包
+            $this->lang->load([
+                $this->thinkPath . 'lang/' . $this->request->langset() . '.php',
+                $this->appPath . 'lang/' . $this->request->langset() . '.php',
+            ]);
+
             // 监听app_dispatch
             $this->hook->listen('app_dispatch');
 
             // 获取应用调度信息
             $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'));
-
+                // 进行URL路由检测
                 $dispatch = $this->routeCheck();
             }
 
@@ -364,22 +358,14 @@ class App implements \ArrayAccess
                 $this->config('app.request_cache_except')
             );
 
-            $data = null;
+            // 执行调度
+            $data = $dispatch->run();
+
         } catch (HttpResponseException $exception) {
-            $dispatch = null;
-            $data     = $exception->getResponse();
+            $data = $exception->getResponse();
         }
 
-        $this->middleware->add(function (Request $request, $next) use ($dispatch, $data) {
-            if (is_null($data)) {
-                try {
-                    // 执行调度
-                    $data = $dispatch->run();
-                } catch (HttpResponseException $exception) {
-                    $data = $exception->getResponse();
-                }
-            }
-
+        $this->middlewareDispatcher->add(function (Request $request, $next) use ($data) {
             // 输出数据到客户端
             if ($data instanceof Response) {
                 $response = $data;
@@ -395,7 +381,7 @@ class App implements \ArrayAccess
             return $response;
         });
 
-        $response = $this->middleware->dispatch($this->request);
+        $response = $this->middlewareDispatcher->dispatch($this->request);
 
         // 监听app_end
         $this->hook->listen('app_end', $response);
@@ -403,24 +389,6 @@ class App implements \ArrayAccess
         return $response;
     }
 
-    protected function loadLangPack()
-    {
-        // 读取默认语言
-        $this->lang->range($this->config('app.default_lang'));
-        if ($this->config('app.lang_switch_on')) {
-            // 开启多语言机制 检测当前语言
-            $this->lang->detect();
-        }
-
-        $this->request->langset($this->lang->range());
-
-        // 加载系统语言包
-        $this->lang->load([
-            $this->thinkPath . 'lang' . DIRECTORY_SEPARATOR . $this->request->langset() . '.php',
-            $this->appPath . 'lang' . DIRECTORY_SEPARATOR . $this->request->langset() . '.php',
-        ]);
-    }
-
     /**
      * 设置当前请求的调度信息
      * @access public
@@ -440,9 +408,9 @@ class App implements \ArrayAccess
      * @param  string $type 信息类型
      * @return void
      */
-    public function log($msg, $type = 'info')
+    public function log($log, $type = 'info')
     {
-        $this->debug && $this->log->record($msg, $type);
+        $this->debug && $this->log->record($log, $type);
     }
 
     /**
@@ -606,9 +574,9 @@ class App implements \ArrayAccess
             return $this->__get($class);
         } elseif ($empty && class_exists($emptyClass = $this->parseClass($module, $layer, $empty, $appendSuffix))) {
             return $this->__get($emptyClass);
+        } else {
+            throw new ClassNotFoundException('class not exists:' . $class, $class);
         }
-
-        throw new ClassNotFoundException('class not exists:' . $class, $class);
     }
 
     /**

+ 15 - 48
thinkphp/library/think/Build.php

@@ -135,7 +135,7 @@ class Build
 
         // 创建子目录和文件
         foreach ($list as $path => $file) {
-            $modulePath = $this->basePath . $module . DIRECTORY_SEPARATOR;
+            $modulePath = $this->basePath . $module . '/';
             if ('__dir__' == $path) {
                 // 生成子目录
                 foreach ($file as $dir) {
@@ -187,7 +187,7 @@ class Build
      * @param  string $layer  控制器层目录名
      * @return string
      */
-    public function buildRoute($suffix = false, $layer = '')
+    public function buildRoute($alias = false, $layer = '')
     {
         $namespace = $this->app->getNameSpace();
         $modules   = glob($this->basePath . '*', GLOB_ONLYDIR);
@@ -204,8 +204,11 @@ class Build
                 continue;
             }
 
-            $path = $this->basePath . $module . DIRECTORY_SEPARATOR . $layer . DIRECTORY_SEPARATOR;
-            $content .= $this->buildDirRoute($path, $namespace, $module, $suffix, $layer);
+            $controllers = glob($this->basePath . $module . '/' . $layer . '/*.php');
+
+            foreach ($controllers as $controller) {
+                $content .= $this->getControllerRoute($namespace, $module, basename($controller, '.php'), $alias, $layer);
+            }
         }
 
         $filename = $this->app->getRuntimePath() . 'build_route.php';
@@ -215,61 +218,25 @@ class Build
     }
 
     /**
-     * 生成子目录控制器类的路由规则
+     * 生成控制器类的路由规则
      * @access protected
-     * @param  string $path  控制器目录
      * @param  string $namespace 应用命名空间
      * @param  string $module 模块
+     * @param  string $controller 控制器名
      * @param  bool   $suffix 类库后缀
      * @param  string $layer 控制器层目录名
      * @return string
      */
-    protected function buildDirRoute($path, $namespace, $module, $suffix, $layer)
-    {
-        $content     = '';
-        $controllers = glob($path . '*.php');
-
-        foreach ($controllers as $controller) {
-            $controller = basename($controller, '.php');
-
-            if ($suffix) {
-                // 控制器后缀
-                $controller = substr($controller, 0, -10);
-            }
-
-            $class = new \ReflectionClass($namespace . '\\' . $module . '\\' . $layer . '\\' . $controller);
-
-            if (strpos($layer, DIRECTORY_SEPARATOR)) {
-                // 多级控制器
-                $level      = str_replace(DIRECTORY_SEPARATOR, '.', substr($layer, 11));
-                $controller = $level . '.' . $controller;
-            }
-
-            $content .= $this->getControllerRoute($class, $module, $controller);
-        }
-
-        $subDir = glob($path . '*', GLOB_ONLYDIR);
-
-        foreach ($subDir as $dir) {
-            $content .= $this->buildDirRoute($dir . DIRECTORY_SEPARATOR, $namespace, $module, $suffix, $layer . '\\' . basename($dir));
-        }
-
-        return $content;
-    }
-
-    /**
-     * 生成控制器类的路由规则
-     * @access protected
-     * @param  string $class        控制器完整类名
-     * @param  string $module       模块名
-     * @param  string $controller   控制器名
-     * @return string
-     */
-    protected function getControllerRoute($class, $module, $controller)
+    protected function getControllerRoute($namespace, $module, $controller, $alias = false, $layer = '')
     {
+        $class   = new \ReflectionClass($namespace . '\\' . $module . '\\' . $layer . '\\' . $controller);
         $content = '';
         $comment = $class->getDocComment();
 
+        if ($alias) {
+            $controller = substr($controller, 0, -10);
+        }
+
         if (false !== strpos($comment, '@route(')) {
             $comment = $this->parseRouteComment($comment);
             $route   = $module . '/' . $controller;

+ 7 - 6
thinkphp/library/think/Config.php

@@ -72,11 +72,12 @@ class Config implements \ArrayAccess
                 return $this->set(include $file, $name);
             } elseif ('yaml' == $type && function_exists('yaml_parse_file')) {
                 return $this->set(yaml_parse_file($file), $name);
+            } else {
+                return $this->parse($file, $type, $name);
             }
-            return $this->parse($file, $type, $name);
+        } else {
+            return $this->config;
         }
-
-        return $this->config;
     }
 
     /**
@@ -89,12 +90,12 @@ class Config implements \ArrayAccess
     {
         // 如果尚未载入 则动态加载配置文件
         $module = Container::get('request')->module();
-        $module = $module ? $module . DIRECTORY_SEPARATOR : '';
+        $module = $module ? $module . '/' : '';
         $app    = Container::get('app');
         $path   = $app->getAppPath() . $module;
 
         if (is_dir($path . 'config')) {
-            $file = $path . 'config' . DIRECTORY_SEPARATOR . $name . $app->getConfigExt();
+            $file = $path . 'config/' . $name . $app->getConfigExt();
         } elseif (is_dir($app->getConfigPath() . $module)) {
             $file = $app->getConfigPath() . $module . $name . $app->getConfigExt();
         }
@@ -116,7 +117,7 @@ class Config implements \ArrayAccess
             $name = $this->prefix . '.' . $name;
         }
 
-        return !is_null($this->get($name)) ? true : false;
+        return $this->get($name) ? true : false;
     }
 
     /**

+ 3 - 35
thinkphp/library/think/Console.php

@@ -41,7 +41,6 @@ class Console
         "think\\console\\command\\Clear",
         "think\\console\\command\\make\\Controller",
         "think\\console\\command\\make\\Model",
-        "think\\console\\command\\make\\Middleware",
         "think\\console\\command\\optimize\\Autoload",
         "think\\console\\command\\optimize\\Config",
         "think\\console\\command\\optimize\\Schema",
@@ -49,22 +48,11 @@ class Console
         "think\\console\\command\\RunServer",
     ];
 
-    /**
-     * Console constructor.
-     * @access public
-     * @param  string     $name    名称
-     * @param  string     $version 版本
-     * @param null|string $user    执行用户
-     */
-    public function __construct($name = 'UNKNOWN', $version = 'UNKNOWN', $user = null)
+    public function __construct($name = 'UNKNOWN', $version = 'UNKNOWN')
     {
         $this->name    = $name;
         $this->version = $version;
 
-        if ($user) {
-            $this->setUser($user);
-        }
-
         $this->defaultCommand = 'list';
         $this->definition     = $this->getDefaultInputDefinition();
 
@@ -73,33 +61,13 @@ class Console
         }
     }
 
-    /**
-     * 设置执行用户
-     * @param $user
-     */
-    public function setUser($user)
-    {
-        $user = posix_getpwnam($user);
-        if ($user) {
-            posix_setuid($user['uid']);
-            posix_setgid($user['gid']);
-        }
-    }
-
-    /**
-     * 初始化 Console
-     * @access public
-     * @param  bool $run 是否运行 Console
-     * @return int|Console
-     */
     public static function init($run = true)
     {
         static $console;
 
         if (!$console) {
-            $config = Container::get('config')->pull('console');
-            // 实例化 console
-            $console = new self($config['name'], $config['version'], $config['user']);
+            // 实例化console
+            $console = new self('Think Console', '0.1');
 
             // 读取指令集
             $file = Container::get('env')->get('app_path') . 'command.php';

+ 67 - 137
thinkphp/library/think/Container.php

@@ -14,10 +14,8 @@ namespace think;
 use Closure;
 use InvalidArgumentException;
 use ReflectionClass;
-use ReflectionException;
 use ReflectionFunction;
 use ReflectionMethod;
-use think\exception\ClassNotFoundException;
 
 class Container
 {
@@ -79,27 +77,6 @@ class Container
     }
 
     /**
-     * 移除容器中的对象实例
-     * @access public
-     * @param  string  $abstract    类标识、接口
-     * @return void
-     */
-    public static function remove($abstract)
-    {
-        return static::getInstance()->delete($abstract);
-    }
-
-    /**
-     * 清除容器中的对象实例
-     * @access public
-     * @return void
-     */
-    public static function clear()
-    {
-        return static::getInstance()->flush();
-    }
-
-    /**
      * 绑定一个类、闭包、实例、接口实现到容器
      * @access public
      * @param  string|array  $abstract    类标识、接口
@@ -178,184 +155,137 @@ class Container
         }
 
         if (isset($this->instances[$abstract]) && !$newInstance) {
-            return $this->instances[$abstract];
-        }
-
-        if (isset($this->bind[$abstract])) {
-            $concrete = $this->bind[$abstract];
-
-            if ($concrete instanceof Closure) {
-                $object = $this->invokeFunction($concrete, $vars);
+            $object = $this->instances[$abstract];
+        } else {
+            if (isset($this->bind[$abstract])) {
+                $concrete = $this->bind[$abstract];
+
+                if ($concrete instanceof Closure) {
+                    $object = $this->invokeFunction($concrete, $vars);
+                } else {
+                    $object = $this->make($concrete, $vars, $newInstance);
+                }
             } else {
-                $object = $this->make($concrete, $vars, $newInstance);
+                $object = $this->invokeClass($abstract, $vars);
             }
-        } else {
-            $object = $this->invokeClass($abstract, $vars);
-        }
 
-        if (!$newInstance) {
-            $this->instances[$abstract] = $object;
+            if (!$newInstance) {
+                $this->instances[$abstract] = $object;
+            }
         }
 
         return $object;
     }
 
     /**
-     * 删除容器中的对象实例
-     * @access public
-     * @param  string    $abstract    类名或者标识
-     * @return void
-     */
-    public function delete($abstract)
-    {
-        if (isset($this->instances[$abstract])) {
-            unset($this->instances[$abstract]);
-        }
-    }
-
-    /**
-     * 清除容器中的对象实例
-     * @access public
-     * @return void
-     */
-    public function flush()
-    {
-        $this->instances = [];
-        $this->bind      = [];
-    }
-
-    /**
      * 执行函数或者闭包方法 支持参数调用
      * @access public
-     * @param  mixed  $function 函数或者闭包
-     * @param  array  $vars     参数
+     * @param  string|array|\Closure $function 函数或者闭包
+     * @param  array                 $vars     变量
      * @return mixed
      */
     public function invokeFunction($function, $vars = [])
     {
-        try {
-            $reflect = new ReflectionFunction($function);
-
-            $args = $this->bindParams($reflect, $vars);
+        $reflect = new ReflectionFunction($function);
+        $args    = $this->bindParams($reflect, $vars);
 
-            return $reflect->invokeArgs($args);
-        } catch (ReflectionException $e) {
-            throw new Exception('function not exists: ' . $function . '()');
-        }
+        return $reflect->invokeArgs($args);
     }
 
     /**
      * 调用反射执行类的方法 支持参数绑定
      * @access public
-     * @param  mixed   $method 方法
-     * @param  array   $vars   参数
+     * @param  string|array $method 方法
+     * @param  array        $vars   变量
      * @return mixed
      */
     public function invokeMethod($method, $vars = [])
     {
-        try {
-            if (is_array($method)) {
-                $class   = is_object($method[0]) ? $method[0] : $this->invokeClass($method[0]);
-                $reflect = new ReflectionMethod($class, $method[1]);
-            } else {
-                // 静态方法
-                $reflect = new ReflectionMethod($method);
-            }
-
-            $args = $this->bindParams($reflect, $vars);
-
-            return $reflect->invokeArgs(isset($class) ? $class : null, $args);
-        } catch (ReflectionException $e) {
-            throw new Exception('method not exists: ' . (is_array($method) ? $method[0] . '::' . $method[1] : $method) . '()');
+        if (is_array($method)) {
+            $class   = is_object($method[0]) ? $method[0] : $this->invokeClass($method[0]);
+            $reflect = new ReflectionMethod($class, $method[1]);
+        } else {
+            // 静态方法
+            $reflect = new ReflectionMethod($method);
         }
-    }
 
-    /**
-     * 调用反射执行类的方法 支持参数绑定
-     * @access public
-     * @param  object  $instance 对象实例
-     * @param  mixed   $reflect 反射类
-     * @param  array   $vars   参数
-     * @return mixed
-     */
-    public function invokeReflectMethod($instance, $reflect, $vars = [])
-    {
         $args = $this->bindParams($reflect, $vars);
 
-        return $reflect->invokeArgs($instance, $args);
+        return $reflect->invokeArgs(isset($class) ? $class : null, $args);
     }
 
     /**
      * 调用反射执行callable 支持参数绑定
      * @access public
      * @param  mixed $callable
-     * @param  array $vars   参数
+     * @param  array $vars   变量
      * @return mixed
      */
     public function invoke($callable, $vars = [])
     {
         if ($callable instanceof Closure) {
-            return $this->invokeFunction($callable, $vars);
+            $result = $this->invokeFunction($callable, $vars);
+        } else {
+            $result = $this->invokeMethod($callable, $vars);
         }
 
-        return $this->invokeMethod($callable, $vars);
+        return $result;
     }
 
     /**
      * 调用反射执行类的实例化 支持依赖注入
      * @access public
      * @param  string    $class 类名
-     * @param  array     $vars  参数
+     * @param  array     $vars  变量
      * @return mixed
      */
     public function invokeClass($class, $vars = [])
     {
-        try {
-            $reflect = new ReflectionClass($class);
+        $reflect     = new ReflectionClass($class);
+        $constructor = $reflect->getConstructor();
 
-            $constructor = $reflect->getConstructor();
-
-            $args = $constructor ? $this->bindParams($constructor, $vars) : [];
-
-            return $reflect->newInstanceArgs($args);
-        } catch (ReflectionException $e) {
-            throw new ClassNotFoundException('class not exists: ' . $class, $class);
+        if ($constructor) {
+            $args = $this->bindParams($constructor, $vars);
+        } else {
+            $args = [];
         }
+
+        return $reflect->newInstanceArgs($args);
     }
 
     /**
      * 绑定参数
      * @access protected
      * @param  \ReflectionMethod|\ReflectionFunction $reflect 反射类
-     * @param  array                                 $vars    参数
+     * @param  array                                 $vars    变量
      * @return array
      */
     protected function bindParams($reflect, $vars = [])
     {
-        if ($reflect->getNumberOfParameters() == 0) {
-            return [];
-        }
-
-        // 判断数组类型 数字数组时按顺序绑定参数
-        reset($vars);
-        $type   = key($vars) === 0 ? 1 : 0;
-        $params = $reflect->getParameters();
-
-        foreach ($params as $param) {
-            $name  = $param->getName();
-            $class = $param->getClass();
-
-            if ($class) {
-                $className = $class->getName();
-                $args[]    = $this->make($className);
-            } elseif (1 == $type && !empty($vars)) {
-                $args[] = array_shift($vars);
-            } elseif (0 == $type && isset($vars[$name])) {
-                $args[] = $vars[$name];
-            } elseif ($param->isDefaultValueAvailable()) {
-                $args[] = $param->getDefaultValue();
-            } else {
-                throw new InvalidArgumentException('method param miss:' . $name);
+        $args = [];
+
+        if ($reflect->getNumberOfParameters() > 0) {
+            // 判断数组类型 数字数组时按顺序绑定参数
+            reset($vars);
+            $type   = key($vars) === 0 ? 1 : 0;
+            $params = $reflect->getParameters();
+
+            foreach ($params as $param) {
+                $name  = $param->getName();
+                $class = $param->getClass();
+
+                if ($class) {
+                    $className = $class->getName();
+                    $args[]    = $this->make($className);
+                } elseif (1 == $type && !empty($vars)) {
+                    $args[] = array_shift($vars);
+                } elseif (0 == $type && isset($vars[$name])) {
+                    $args[] = $vars[$name];
+                } elseif ($param->isDefaultValueAvailable()) {
+                    $args[] = $param->getDefaultValue();
+                } else {
+                    throw new InvalidArgumentException('method param miss:' . $name);
+                }
             }
         }
 

+ 10 - 11
thinkphp/library/think/Controller.php

@@ -70,10 +70,12 @@ class Controller
         $this->initialize();
 
         // 前置操作方法
-        foreach ((array) $this->beforeActionList as $method => $options) {
-            is_numeric($method) ?
-            $this->beforeAction($options) :
-            $this->beforeAction($method, $options);
+        if ($this->beforeActionList) {
+            foreach ($this->beforeActionList as $method => $options) {
+                is_numeric($method) ?
+                $this->beforeAction($options) :
+                $this->beforeAction($method, $options);
+            }
         }
     }
 
@@ -118,10 +120,6 @@ class Controller
      */
     protected function fetch($template = '', $vars = [], $config = [])
     {
-        if ('' === $template) {
-            $template = Loader::parseName($this->request->action(true));
-        }
-
         return $this->view->fetch($template, $vars, $config);
     }
 
@@ -234,10 +232,11 @@ class Controller
         if (!$v->check($data)) {
             if ($this->failException) {
                 throw new ValidateException($v->getError());
+            } else {
+                return $v->getError();
             }
-            return $v->getError();
+        } else {
+            return true;
         }
-
-        return true;
     }
 }

+ 1 - 3
thinkphp/library/think/Db.php

@@ -14,7 +14,6 @@ namespace think;
 /**
  * Class Db
  * @package think
- * @method \think\db\Query connect(array $config =[], mixed $name = false) static 连接/切换数据库连接
  * @method \think\db\Query table(string $table) static 指定数据表(含前缀)
  * @method \think\db\Query name(string $name) static 指定数据表(不含前缀)
  * @method \think\db\Query where(mixed $field, string $op = null, mixed $condition = null) static 查询条件
@@ -43,8 +42,7 @@ namespace think;
  * @method void commit() static 用于非自动提交状态下面的查询提交
  * @method void rollback() static 事务回滚
  * @method boolean batchQuery(array $sqlArray) static 批处理执行SQL语句
- * @method string getLastInsID(string $sequence = null) static 获取最近插入的ID
- * @method mixed getConfig(string $name = '') static 获取数据库的配置参数
+ * @method string getLastInsID($sequence = null) static 获取最近插入的ID
  */
 class Db
 {

+ 2 - 1
thinkphp/library/think/Debug.php

@@ -223,8 +223,9 @@ class Debug
         if ($echo) {
             echo($output);
             return;
+        } else {
+            return $output;
         }
-        return $output;
     }
 
     public function inject(Response $response, &$content)

+ 12 - 12
thinkphp/library/think/Env.php

@@ -62,21 +62,21 @@ class Env
     {
         $result = getenv('PHP_' . $name);
 
-        if (false === $result) {
-            return $default;
-        }
+        if (false !== $result) {
+            if ('false' === $result) {
+                $result = false;
+            } elseif ('true' === $result) {
+                $result = true;
+            }
 
-        if ('false' === $result) {
-            $result = false;
-        } elseif ('true' === $result) {
-            $result = true;
-        }
+            if (!isset($this->data[$name])) {
+                $this->data[$name] = $result;
+            }
 
-        if (!isset($this->data[$name])) {
-            $this->data[$name] = $result;
+            return $result;
+        } else {
+            return $default;
         }
-
-        return $result;
     }
 
     /**

+ 2 - 2
thinkphp/library/think/Error.php

@@ -66,9 +66,9 @@ class Error
         if (error_reporting() & $errno) {
             // 将错误信息托管至 think\exception\ErrorException
             throw $exception;
+        } else {
+            self::getExceptionHandler()->report($exception);
         }
-
-        self::getExceptionHandler()->report($exception);
     }
 
     /**

+ 0 - 4
thinkphp/library/think/Facade.php

@@ -88,10 +88,6 @@ class Facade
      */
     public static function instance(...$args)
     {
-        if (__CLASS__ != static::class) {
-            return self::__callStatic('instance', $args);
-        }
-
         return self::createFacade('', $args);
     }
 

+ 52 - 52
thinkphp/library/think/File.php

@@ -147,7 +147,7 @@ class File extends SplFileObject
 
     /**
      * 检查目录是否可写
-     * @access protected
+     * @access public
      * @param  string   $path    目录
      * @return boolean
      */
@@ -159,10 +159,10 @@ class File extends SplFileObject
 
         if (mkdir($path, 0755, true)) {
             return true;
+        } else {
+            $this->error = ['directory {:path} creation failed', ['path' => $path]];
+            return false;
         }
-
-        $this->error = ['directory {:path} creation failed', ['path' => $path]];
-        return false;
     }
 
     /**
@@ -227,10 +227,27 @@ class File extends SplFileObject
     {
         $rule = $rule ?: $this->validate;
 
-        if ((isset($rule['size']) && !$this->checkSize($rule['size']))
-            || (isset($rule['type']) && !$this->checkMime($rule['type']))
-            || (isset($rule['ext']) && !$this->checkExt($rule['ext']))
-            || !$this->checkImg()) {
+        /* 检查文件大小 */
+        if (isset($rule['size']) && !$this->checkSize($rule['size'])) {
+            $this->error = 'filesize not match';
+            return false;
+        }
+
+        /* 检查文件Mime类型 */
+        if (isset($rule['type']) && !$this->checkMime($rule['type'])) {
+            $this->error = 'mimetype to upload is not allowed';
+            return false;
+        }
+
+        /* 检查文件后缀 */
+        if (isset($rule['ext']) && !$this->checkExt($rule['ext'])) {
+            $this->error = 'extensions to upload is not allowed';
+            return false;
+        }
+
+        /* 检查图像文件 */
+        if (!$this->checkImg()) {
+            $this->error = 'illegal image files';
             return false;
         }
 
@@ -252,7 +269,6 @@ class File extends SplFileObject
         $extension = strtolower(pathinfo($this->getInfo('name'), PATHINFO_EXTENSION));
 
         if (!in_array($extension, $ext)) {
-            $this->error = 'extensions to upload is not allowed';
             return false;
         }
 
@@ -270,7 +286,6 @@ class File extends SplFileObject
 
         /* 对图像文件进行严格检测 */
         if (in_array($extension, ['gif', 'jpg', 'jpeg', 'bmp', 'png', 'swf']) && !in_array($this->getImageType($this->filename), [1, 2, 3, 4, 6, 13])) {
-            $this->error = 'illegal image files';
             return false;
         }
 
@@ -282,13 +297,13 @@ class File extends SplFileObject
     {
         if (function_exists('exif_imagetype')) {
             return exif_imagetype($image);
-        }
-
-        try {
-            $info = getimagesize($image);
-            return $info ? $info[2] : false;
-        } catch (\Exception $e) {
-            return false;
+        } else {
+            try {
+                $info = getimagesize($image);
+                return $info ? $info[2] : false;
+            } catch (\Exception $e) {
+                return false;
+            }
         }
     }
 
@@ -301,7 +316,6 @@ class File extends SplFileObject
     public function checkSize($size)
     {
         if ($this->getSize() > $size) {
-            $this->error = 'filesize not match';
             return false;
         }
 
@@ -321,7 +335,6 @@ class File extends SplFileObject
         }
 
         if (!in_array(strtolower($this->getMime()), $mime)) {
-            $this->error = 'mimetype to upload is not allowed';
             return false;
         }
 
@@ -389,7 +402,7 @@ class File extends SplFileObject
 
     /**
      * 获取保存文件名
-     * @access protected
+     * @access public
      * @param  string|bool   $savename    保存的文件名 默认自动生成
      * @return string
      */
@@ -397,9 +410,25 @@ class File extends SplFileObject
     {
         if (true === $savename) {
             // 自动生成文件名
-            $savename = $this->autoBuildName();
+            if ($this->rule instanceof \Closure) {
+                $savename = call_user_func_array($this->rule, [$this]);
+            } else {
+                switch ($this->rule) {
+                    case 'date':
+                        $savename = date('Ymd') . '/' . md5(microtime(true));
+                        break;
+                    default:
+                        if (in_array($this->rule, hash_algos())) {
+                            $hash     = $this->hash($this->rule);
+                            $savename = substr($hash, 0, 2) . '/' . substr($hash, 2);
+                        } elseif (is_callable($this->rule)) {
+                            $savename = call_user_func($this->rule);
+                        } else {
+                            $savename = date('Ymd') . '/' . md5(microtime(true));
+                        }
+                }
+            }
         } elseif ('' === $savename || false === $savename) {
-            // 保留原文件名
             $savename = $this->getInfo('name');
         }
 
@@ -411,37 +440,8 @@ class File extends SplFileObject
     }
 
     /**
-     * 自动生成文件名
-     * @access protected
-     * @return string
-     */
-    protected function autoBuildName()
-    {
-        if ($this->rule instanceof \Closure) {
-            $savename = call_user_func_array($this->rule, [$this]);
-        } else {
-            switch ($this->rule) {
-                case 'date':
-                    $savename = date('Ymd') . DIRECTORY_SEPARATOR . md5(microtime(true));
-                    break;
-                default:
-                    if (in_array($this->rule, hash_algos())) {
-                        $hash     = $this->hash($this->rule);
-                        $savename = substr($hash, 0, 2) . DIRECTORY_SEPARATOR . substr($hash, 2);
-                    } elseif (is_callable($this->rule)) {
-                        $savename = call_user_func($this->rule);
-                    } else {
-                        $savename = date('Ymd') . DIRECTORY_SEPARATOR . md5(microtime(true));
-                    }
-            }
-        }
-
-        return $savename;
-    }
-
-    /**
      * 获取错误代码信息
-     * @access private
+     * @access public
      * @param  int $errorNo  错误号
      */
     private function error($errorNo)

+ 6 - 3
thinkphp/library/think/Hook.php

@@ -116,9 +116,9 @@ class Hook
         if (empty($tag)) {
             //获取全部的插件信息
             return $this->tags;
+        } else {
+            return array_key_exists($tag, $this->tags) ? $this->tags[$tag] : [];
         }
-
-        return array_key_exists($tag, $this->tags) ? $this->tags[$tag] : [];
     }
 
     /**
@@ -137,7 +137,10 @@ class Hook
         foreach ($tags as $key => $name) {
             $results[$key] = $this->execTag($name, $tag, $params);
 
-            if (false === $results[$key] || (!is_null($results[$key]) && $once)) {
+            if (false === $results[$key]) {
+                // 如果返回false 则中断行为执行
+                break;
+            } elseif (!is_null($results[$key]) && $once) {
                 break;
             }
         }

+ 2 - 2
thinkphp/library/think/Lang.php

@@ -79,9 +79,9 @@ class Lang
 
         if (is_array($name)) {
             return $this->lang[$range] = array_change_key_case($name) + $this->lang[$range];
+        } else {
+            return $this->lang[$range][strtolower($name)] = $value;
         }
-
-        return $this->lang[$range][strtolower($name)] = $value;
     }
 
     /**

+ 18 - 33
thinkphp/library/think/Loader.php

@@ -58,44 +58,29 @@ class Loader
         // 注册系统自动加载
         spl_autoload_register($autoload ?: 'think\\Loader::autoload', true, true);
 
-        $path = realpath(dirname($_SERVER['SCRIPT_FILENAME']));
+        // 注册命名空间定义
+        self::addNamespace([
+            'think'  => __DIR__ . '/',
+            'traits' => __DIR__ . '/../traits/',
+        ]);
 
-        if ('cli-server' == PHP_SAPI || !is_file('./think')) {
-            $rootPath = dirname($path) . DIRECTORY_SEPARATOR;
+        $path = dirname($_SERVER['SCRIPT_FILENAME']);
+        if (is_file('./think')) {
+            $rootPath = realpath($path) . '/';
         } else {
-            $rootPath = $path . DIRECTORY_SEPARATOR;
+            $rootPath = realpath($path . '/../') . '/';
         }
 
-        self::$composerPath = $rootPath . 'vendor' . DIRECTORY_SEPARATOR . 'composer' . DIRECTORY_SEPARATOR;
-
-        // Composer自动加载支持
-        if (is_dir(self::$composerPath)) {
-            if (is_file(self::$composerPath . 'autoload_static.php')) {
-                require self::$composerPath . 'autoload_static.php';
-
-                $declaredClass = get_declared_classes();
-                $composerClass = array_pop($declaredClass);
-
-                self::$prefixLengthsPsr4 = $composerClass::$prefixLengthsPsr4;
-
-                self::$prefixDirsPsr4 = property_exists($composerClass, 'prefixDirsPsr4') ? $composerClass::$prefixDirsPsr4 : [];
-
-                self::$prefixesPsr0 = property_exists($composerClass, 'prefixesPsr0') ? $composerClass::$prefixesPsr0 : [];
-                self::$map          = property_exists($composerClass, 'classMap') ? $composerClass::$classMap : [];
-            } else {
-                self::registerComposerLoader(self::$composerPath);
-            }
+        // 加载类库映射文件
+        if (is_file($rootPath . 'runtime/classmap.php')) {
+            self::addClassMap(__include_file($rootPath . 'runtime/classmap.php'));
         }
 
-        // 注册命名空间定义
-        self::addNamespace([
-            'think'  => __DIR__,
-            'traits' => dirname(__DIR__) . DIRECTORY_SEPARATOR . 'traits',
-        ]);
+        self::$composerPath = $rootPath . 'vendor/composer/';
 
-        // 加载类库映射文件
-        if (is_file($rootPath . 'runtime' . DIRECTORY_SEPARATOR . 'classmap.php')) {
-            self::addClassMap(__include_file($rootPath . 'runtime' . DIRECTORY_SEPARATOR . 'classmap.php'));
+        // Composer自动加载支持
+        if (is_dir(self::$composerPath)) {
+            self::registerComposerLoader(self::$composerPath);
         }
 
         // 自动加载extend目录
@@ -361,9 +346,9 @@ class Loader
                 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), "_"));
     }
 }
 

+ 28 - 51
thinkphp/library/think/Log.php

@@ -50,12 +50,6 @@ class Log implements LoggerInterface
     protected $key;
 
     /**
-     * 是否允许日志写入
-     * @var bool
-     */
-    protected $allowWrite = true;
-
-    /**
      * 应用对象
      * @var App
      */
@@ -114,10 +108,6 @@ class Log implements LoggerInterface
      */
     public function record($msg, $type = 'info', array $context = [])
     {
-        if (!$this->allowWrite) {
-            return;
-        }
-
         if (is_string($msg)) {
             $replace = [];
             foreach ($context as $key => $val) {
@@ -178,60 +168,47 @@ class Log implements LoggerInterface
     }
 
     /**
-     * 关闭本次请求日志写入
-     * @access public
-     * @return $this
-     */
-    public function close()
-    {
-        $this->allowWrite = false;
-        $this->log        = [];
-
-        return $this;
-    }
-
-    /**
      * 保存调试信息
      * @access public
      * @return bool
      */
     public function save()
     {
-        if (empty($this->log) || !$this->allowWrite) {
-            return true;
-        }
-
-        if (is_null($this->driver)) {
-            $this->init($this->app['config']->pull('log'));
-        }
-
-        if (!$this->check($this->config)) {
-            // 检测日志写入权限
-            return false;
-        }
+        if (!empty($this->log)) {
+            if (is_null($this->driver)) {
+                $this->init($this->app['config']->pull('log'));
+            }
 
-        if (empty($this->config['level'])) {
-            // 获取全部日志
-            $log = $this->log;
-            if (!$this->app->isDebug() && isset($log['debug'])) {
-                unset($log['debug']);
+            if (!$this->check($this->config)) {
+                // 检测日志写入权限
+                return false;
             }
-        } else {
-            // 记录允许级别
-            $log = [];
-            foreach ($this->config['level'] as $level) {
-                if (isset($this->log[$level])) {
-                    $log[$level] = $this->log[$level];
+
+            if (empty($this->config['level'])) {
+                // 获取全部日志
+                $log = $this->log;
+                if (!$this->app->isDebug() && isset($log['debug'])) {
+                    unset($log['debug']);
+                }
+            } else {
+                // 记录允许级别
+                $log = [];
+                foreach ($this->config['level'] as $level) {
+                    if (isset($this->log[$level])) {
+                        $log[$level] = $this->log[$level];
+                    }
                 }
             }
-        }
 
-        $result = $this->driver->save($log);
-        if ($result) {
-            $this->log = [];
+            $result = $this->driver->save($log);
+            if ($result) {
+                $this->log = [];
+            }
+
+            return $result;
         }
 
-        return $result;
+        return true;
     }
 
     /**

+ 13 - 13
thinkphp/library/think/Model.php

@@ -389,7 +389,7 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
     /**
      * 检查数据是否允许写入
      * @access protected
-     * @param  array   $append 自动完成的字段列表
+     * @param  array   $autoFields 自动完成的字段列表
      * @return array
      */
     protected function checkAllowFields(array $append = [])
@@ -478,11 +478,13 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
             $where = $array;
         }
 
-        foreach ((array) $this->relationWrite as $name => $val) {
-            if (is_array($val)) {
-                foreach ($val as $key) {
-                    if (isset($data[$key])) {
-                        unset($data[$key]);
+        if (!empty($this->relationWrite)) {
+            foreach ($this->relationWrite as $name => $val) {
+                if (is_array($val)) {
+                    foreach ($val as $key) {
+                        if (isset($data[$key])) {
+                            unset($data[$key]);
+                        }
                     }
                 }
             }
@@ -859,15 +861,13 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
      */
     public static function destroy($data)
     {
-        if (empty($data) && 0 !== $data) {
-            return 0;
-        }
-
         $model = new static();
 
         $query = $model->db();
 
-        if (is_array($data) && key($data) !== 0) {
+        if (empty($data) && 0 !== $data) {
+            return 0;
+        } elseif (is_array($data) && key($data) !== 0) {
             $query->where($data);
             $data = null;
         } elseif ($data instanceof \Closure) {
@@ -947,9 +947,9 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
     {
         if (array_key_exists($name, $this->data) || array_key_exists($name, $this->relation)) {
             return true;
+        } else {
+            return false;
         }
-
-        return false;
     }
 
     /**

+ 2 - 2
thinkphp/library/think/Paginator.php

@@ -104,8 +104,8 @@ abstract class Paginator implements ArrayAccess, Countable, IteratorAggregate, J
      * @param       $items
      * @param       $listRows
      * @param null  $currentPage
-     * @param null  $total
      * @param bool  $simple
+     * @param null  $total
      * @param array $options
      * @return Paginator
      */
@@ -150,7 +150,7 @@ abstract class Paginator implements ArrayAccess, Countable, IteratorAggregate, J
 
         $url = $path;
         if (!empty($parameters)) {
-            $url .= '?' . http_build_query($parameters, null, '&');
+            $url .= '?' . urldecode(http_build_query($parameters, null, '&'));
         }
 
         return $url . $this->buildFragment();

+ 104 - 172
thinkphp/library/think/Request.php

@@ -252,12 +252,6 @@ class Request
     protected $isCheckCache;
 
     /**
-     * 请求安全Key
-     * @var string
-     */
-    protected $secureKey;
-
-    /**
      * 架构函数
      * @access public
      * @param  array  $options 参数
@@ -285,9 +279,9 @@ class Request
         if (array_key_exists($method, $this->hook)) {
             array_unshift($args, $this);
             return call_user_func_array($this->hook[$method], $args);
+        } else {
+            throw new Exception('method not exists:' . static::class . '->' . $method);
         }
-
-        throw new Exception('method not exists:' . static::class . '->' . $method);
     }
 
     /**
@@ -410,27 +404,9 @@ class Request
     }
 
     /**
-     * 获取当前根域名
-     * @access public
-     * @return string
-     */
-    public function rootDomain()
-    {
-        $root = $this->config->get('app.url_domain_root');
-
-        if (!$root) {
-            $item  = explode('.', $this->host());
-            $count = count($item);
-            $root  = $count > 1 ? $item[$count - 2] . '.' . $item[$count - 1] : $item[0];
-        }
-
-        return $root;
-    }
-
-    /**
      * 获取当前子域名
      * @access public
-     * @return string
+     * @return string|$this
      */
     public function subDomain()
     {
@@ -461,10 +437,10 @@ class Request
     {
         if (is_null($domain)) {
             return $this->panDomain;
+        } else {
+            $this->panDomain = $domain;
+            return $this;
         }
-
-        $this->panDomain = $domain;
-        return $this;
     }
 
     /**
@@ -616,7 +592,7 @@ class Request
                 }
             }
 
-            $this->pathinfo = empty($_SERVER['PATH_INFO']) || '/' == $_SERVER['PATH_INFO'] ? '' : ltrim($_SERVER['PATH_INFO'], '/');
+            $this->pathinfo = empty($_SERVER['PATH_INFO']) ? '/' : ltrim($_SERVER['PATH_INFO'], '/');
         }
 
         return $this->pathinfo;
@@ -1105,12 +1081,37 @@ class Request
         $files = $this->file;
         if (!empty($files)) {
             // 处理上传文件
-            $array = $this->dealUploadFile($files);
-
+            $array = [];
+            foreach ($files as $key => $file) {
+                if (is_array($file['name'])) {
+                    $item  = [];
+                    $keys  = array_keys($file);
+                    $count = count($file['name']);
+                    for ($i = 0; $i < $count; $i++) {
+                        if (empty($file['tmp_name'][$i]) || !is_file($file['tmp_name'][$i])) {
+                            continue;
+                        }
+                        $temp['key'] = $key;
+                        foreach ($keys as $_key) {
+                            $temp[$_key] = $file[$_key][$i];
+                        }
+                        $item[] = (new File($temp['tmp_name']))->setUploadInfo($temp);
+                    }
+                    $array[$key] = $item;
+                } else {
+                    if ($file instanceof File) {
+                        $array[$key] = $file;
+                    } else {
+                        if (empty($file['tmp_name']) || !is_file($file['tmp_name'])) {
+                            continue;
+                        }
+                        $array[$key] = (new File($file['tmp_name']))->setUploadInfo($file);
+                    }
+                }
+            }
             if (strpos($name, '.')) {
                 list($name, $sub) = explode('.', $name);
             }
-
             if ('' === $name) {
                 // 获取全部文件
                 return $array;
@@ -1124,46 +1125,6 @@ class Request
         return;
     }
 
-    protected function dealUploadFile($files)
-    {
-        $array = [];
-        foreach ($files as $key => $file) {
-            if (is_array($file['name'])) {
-                $item  = [];
-                $keys  = array_keys($file);
-                $count = count($file['name']);
-
-                for ($i = 0; $i < $count; $i++) {
-                    if (empty($file['tmp_name'][$i]) || !is_file($file['tmp_name'][$i])) {
-                        continue;
-                    }
-
-                    $temp['key'] = $key;
-
-                    foreach ($keys as $_key) {
-                        $temp[$_key] = $file[$_key][$i];
-                    }
-
-                    $item[] = (new File($temp['tmp_name']))->setUploadInfo($temp);
-                }
-
-                $array[$key] = $item;
-            } else {
-                if ($file instanceof File) {
-                    $array[$key] = $file;
-                } else {
-                    if (empty($file['tmp_name']) || !is_file($file['tmp_name'])) {
-                        continue;
-                    }
-
-                    $array[$key] = (new File($file['tmp_name']))->setUploadInfo($file);
-                }
-            }
-        }
-
-        return $array;
-    }
-
     /**
      * 获取环境变量
      * @access public
@@ -1253,7 +1214,6 @@ class Request
             } else {
                 $type = 's';
             }
-
             // 按.拆分成多维数组进行判断
             foreach (explode('.', $name) as $val) {
                 if (isset($data[$val])) {
@@ -1263,7 +1223,6 @@ class Request
                     return $default;
                 }
             }
-
             if (is_object($data)) {
                 return $data;
             }
@@ -1297,9 +1256,9 @@ class Request
     {
         if (is_null($filter)) {
             return $this->filter;
+        } else {
+            $this->filter = $filter;
         }
-
-        $this->filter = $filter;
     }
 
     protected function getFilter($filter, $default)
@@ -1519,9 +1478,9 @@ class Request
 
         if (true === $ajax) {
             return $result;
+        } else {
+            return $this->param($this->config->get('var_ajax')) ? true : $result;
         }
-
-        return $this->param($this->config->get('var_ajax')) ? true : $result;
     }
 
     /**
@@ -1536,9 +1495,9 @@ class Request
 
         if (true === $pjax) {
             return $result;
+        } else {
+            return $this->param($this->config->get('var_pjax')) ? true : $result;
         }
-
-        return $this->param($this->config->get('var_pjax')) ? true : $result;
     }
 
     /**
@@ -1596,9 +1555,9 @@ class Request
             return true;
         } elseif (isset($_SERVER['HTTP_USER_AGENT']) && preg_match('/(blackberry|configuration\/cldc|hp |hp-|htc |htc_|htc-|iemobile|kindle|midp|mmp|motorola|mobile|nokia|opera mini|opera |Googlebot-Mobile|YahooSeeker\/M1A1-R2D2|android|iphone|ipod|mobi|palm|palmos|pocket|portalmmm|ppc;|smartphone|sonyericsson|sqh|spv|symbian|treo|up.browser|up.link|vodafone|windows ce|xda |xda_)/i', $_SERVER['HTTP_USER_AGENT'])) {
             return true;
+        } else {
+            return false;
         }
-
-        return false;
     }
 
     /**
@@ -1696,9 +1655,9 @@ class Request
     {
         if (!empty($route)) {
             $this->routeInfo = $route;
+        } else {
+            return $this->routeInfo;
         }
-
-        return $this->routeInfo;
     }
 
     /**
@@ -1717,20 +1676,6 @@ class Request
     }
 
     /**
-     * 获取当前请求的安全Key
-     * @access public
-     * @return string
-     */
-    public function secureKey()
-    {
-        if (is_null($this->secureKey)) {
-            $this->secureKey = uniqid('', true);
-        }
-
-        return $this->secureKey;
-    }
-
-    /**
      * 设置或者获取当前的模块名
      * @access public
      * @param  string $module 模块名
@@ -1741,9 +1686,9 @@ class Request
         if (!is_null($module)) {
             $this->module = $module;
             return $this;
+        } else {
+            return $this->module ?: '';
         }
-
-        return $this->module ?: '';
     }
 
     /**
@@ -1757,9 +1702,9 @@ class Request
         if (!is_null($controller)) {
             $this->controller = $controller;
             return $this;
+        } else {
+            return $this->controller ?: '';
         }
-
-        return $this->controller ?: '';
     }
 
     /**
@@ -1770,13 +1715,12 @@ class Request
      */
     public function action($action = null)
     {
-        if (!is_null($action) && !is_bool($action)) {
+        if (!is_null($action)) {
             $this->action = $action;
             return $this;
+        } else {
+            return $this->action ?: '';
         }
-
-        $name = $this->action ?: '';
-        return true === $action ? $name : strtolower($name);
     }
 
     /**
@@ -1790,9 +1734,9 @@ class Request
         if (!is_null($lang)) {
             $this->langset = $lang;
             return $this;
+        } else {
+            return $this->langset ?: '';
         }
-
-        return $this->langset ?: '';
     }
 
     /**
@@ -1856,67 +1800,66 @@ class Request
             $except = [];
         }
 
-        if (false === $key || !$this->isGet() || $this->isCheckCache || false === $expire) {
-            // 关闭当前缓存
-            return;
-        }
-
-        // 标记请求缓存检查
-        $this->isCheckCache = true;
-
-        foreach ($except as $rule) {
-            if (0 === stripos($this->url(), $rule)) {
+        if (false !== $key && $this->isGet() && !$this->isCheckCache) {
+            // 标记请求缓存检查
+            $this->isCheckCache = true;
+            if (false === $expire) {
+                // 关闭当前缓存
                 return;
             }
-        }
-
-        if ($key instanceof \Closure) {
-            $key = call_user_func_array($key, [$this]);
-        } elseif (true === $key) {
-            // 自动缓存功能
-            $key = '__URL__';
-        } elseif (strpos($key, '|')) {
-            list($key, $fun) = explode('|', $key);
-        }
 
-        // 特殊规则替换
-        if (false !== strpos($key, '__')) {
-            $key = str_replace(['__MODULE__', '__CONTROLLER__', '__ACTION__', '__URL__'], [$this->module, $this->controller, $this->action, md5($this->url(true))], $key);
-        }
-
-        if (false !== strpos($key, ':')) {
-            $param = $this->param();
-            foreach ($param as $item => $val) {
-                if (is_string($val) && false !== strpos($key, ':' . $item)) {
-                    $key = str_replace(':' . $item, $val, $key);
+            foreach ($except as $rule) {
+                if (0 === stripos($this->url(), $rule)) {
+                    return;
                 }
             }
-        } elseif (strpos($key, ']')) {
-            if ('[' . $this->ext() . ']' == $key) {
-                // 缓存某个后缀的请求
-                $key = md5($this->url());
-            } else {
-                return;
+
+            if ($key instanceof \Closure) {
+                $key = call_user_func_array($key, [$this]);
+            } elseif (true === $key) {
+                // 自动缓存功能
+                $key = '__URL__';
+            } elseif (strpos($key, '|')) {
+                list($key, $fun) = explode('|', $key);
             }
-        }
 
-        if (isset($fun)) {
-            $key = $fun($key);
-        }
-        $cache = Container::get('cache');
+            // 特殊规则替换
+            if (false !== strpos($key, '__')) {
+                $key = str_replace(['__MODULE__', '__CONTROLLER__', '__ACTION__', '__URL__'], [$this->module, $this->controller, $this->action, md5($this->url(true))], $key);
+            }
 
-        if (strtotime($this->server('HTTP_IF_MODIFIED_SINCE')) + $expire > $_SERVER['REQUEST_TIME']) {
-            // 读取缓存
-            $response = Response::create()->code(304);
-            throw new HttpResponseException($response);
-        } elseif ($cache->has($key)) {
-            list($content, $header) = $cache->get($key);
+            if (false !== strpos($key, ':')) {
+                $param = $this->param();
+                foreach ($param as $item => $val) {
+                    if (is_string($val) && false !== strpos($key, ':' . $item)) {
+                        $key = str_replace(':' . $item, $val, $key);
+                    }
+                }
+            } elseif (strpos($key, ']')) {
+                if ('[' . $this->ext() . ']' == $key) {
+                    // 缓存某个后缀的请求
+                    $key = md5($this->url());
+                } else {
+                    return;
+                }
+            }
 
-            $response = Response::create($content)->header($header);
-            throw new HttpResponseException($response);
+            if (isset($fun)) {
+                $key = $fun($key);
+            }
+            $cache = Container::get('cache');
+            if (strtotime($this->server('HTTP_IF_MODIFIED_SINCE')) + $expire > $_SERVER['REQUEST_TIME']) {
+                // 读取缓存
+                $response = Response::create()->code(304);
+                throw new HttpResponseException($response);
+            } elseif ($cache->has($key)) {
+                list($content, $header) = $cache->get($key);
+                $response               = Response::create($content)->header($header);
+                throw new HttpResponseException($response);
+            } else {
+                $this->cache = [$key, $expire, $tag];
+            }
         }
-
-        $this->cache = [$key, $expire, $tag];
     }
 
     /**
@@ -1929,15 +1872,4 @@ class Request
         return $this->cache;
     }
 
-    /**
-     * 获取请求数据的值
-     * @access public
-     * @param  string $name 名称
-     * @return mixed
-     */
-    public function __get($name)
-    {
-        return $this->param($name);
-    }
-
 }

+ 4 - 4
thinkphp/library/think/Response.php

@@ -103,9 +103,9 @@ class Response
 
         if (class_exists($class)) {
             return new $class($data, $code, $header, $options);
+        } else {
+            return new static($data, $code, $header, $options);
         }
-
-        return new static($data, $code, $header, $options);
     }
 
     /**
@@ -352,9 +352,9 @@ class Response
     {
         if (!empty($name)) {
             return isset($this->header[$name]) ? $this->header[$name] : null;
+        } else {
+            return $this->header;
         }
-
-        return $this->header;
     }
 
     /**

+ 314 - 130
thinkphp/library/think/Route.php

@@ -12,7 +12,6 @@
 namespace think;
 
 use think\exception\RouteNotFoundException;
-use think\route\AliasRule;
 use think\route\dispatch\Url as UrlDispatch;
 use think\route\Domain;
 use think\route\Resource;
@@ -72,12 +71,18 @@ class Route
     protected $domain;
 
     /**
-     * 当前分组对象
-     * @var RuleGroup
+     * 当前分组
+     * @var string
      */
     protected $group;
 
     /**
+     * 路由标识
+     * @var array
+     */
+    protected $name = [];
+
+    /**
      * 路由绑定
      * @var array
      */
@@ -96,31 +101,20 @@ class Route
     protected $cross;
 
     /**
-     * 路由别名
-     * @var array
-     */
-    protected $alias = [];
-
-    /**
-     * 路由是否延迟解析
-     * @var bool
-     */
-    protected $lazy = true;
-
-    /**
-     * (分组)路由规则是否合并解析
-     * @var bool
+     * 当前路由标识
+     * @var string
      */
-    protected $mergeRuleRegex = true;
+    protected $ruleName;
 
     /**
-     * 路由解析自动搜索多级控制器
-     * @var bool
+     * 路由别名
+     * @var array
      */
-    protected $autoSearchController = true;
+    protected $alias = [];
 
-    public function __construct(Request $request)
+    public function __construct(Request $request, Config $config)
     {
+        $this->config  = $config;
         $this->request = $request;
         $this->host    = $this->request->host();
 
@@ -128,44 +122,6 @@ class Route
     }
 
     /**
-     * 设置路由域名及分组(包括资源路由)是否延迟解析
-     * @access public
-     * @param  bool     $lazy   路由是否延迟解析
-     * @return $this
-     */
-    public function lazy($lazy = true)
-    {
-        $this->lazy = $lazy;
-        return $this;
-    }
-
-    /**
-     * 设置路由域名及分组(包括资源路由)是否合并解析
-     * @access public
-     * @param  bool     $merge   路由是否合并解析
-     * @return $this
-     */
-    public function mergeRuleRegex($merge = true)
-    {
-        $this->mergeRuleRegex = $merge;
-        $this->group->mergeRuleRegex($merge);
-
-        return $this;
-    }
-
-    /**
-     * 设置路由自动解析是否搜索多级控制器
-     * @access public
-     * @param  bool     $auto   是否自动搜索多级控制器
-     * @return $this
-     */
-    public function autoSearchController($auto = true)
-    {
-        $this->autoSearchController = $auto;
-        return $this;
-    }
-
-    /**
      * 初始化默认域名
      * @access protected
      * @return void
@@ -181,7 +137,22 @@ class Route
         $this->domains[$this->host] = $domain;
 
         // 默认分组
-        $this->group = $domain;
+        $this->group = $this->createTopGroup($domain);
+    }
+
+    /**
+     * 创建一个域名下的顶级路由分组
+     * @access protected
+     * @param  Domain    $domain 域名
+     * @return RuleGroup
+     */
+    protected function createTopGroup(Domain $domain)
+    {
+        $group = new RuleGroup($this);
+        // 注册分组到当前域名
+        $domain->addRule($group);
+
+        return $group;
     }
 
     /**
@@ -234,6 +205,22 @@ class Route
     }
 
     /**
+     * 获取当前根域名
+     * @access protected
+     * @return string
+     */
+    protected function getRootDomain()
+    {
+        $root = $this->config->get('app.url_domain_root');
+        if (!$root) {
+            $item  = explode('.', $this->host);
+            $count = count($item);
+            $root  = $count > 1 ? $item[$count - 2] . '.' . $item[$count - 1] : $item[0];
+        }
+        return $root;
+    }
+
+    /**
      * 注册域名路由
      * @access public
      * @param  string|array  $name 子域名
@@ -248,22 +235,33 @@ class Route
         $domainName = is_array($name) ? array_shift($name) : $name;
 
         if ('*' != $domainName && !strpos($domainName, '.')) {
-            $domainName .= '.' . $this->request->rootDomain();
+            $domainName .= '.' . $this->getRootDomain();
         }
 
-        if (!isset($this->domains[$domainName])) {
-            $domain = (new Domain($this, $domainName, $rule, $option, $pattern))
-                ->lazy($this->lazy)
-                ->mergeRuleRegex($this->mergeRuleRegex);
+        $route = $this->config->get('url_lazy_route') ? $rule : null;
 
-            $this->domains[$domainName] = $domain;
-        } else {
-            $domain = $this->domains[$domainName];
-            $domain->parseGroupRule($rule);
+        $domain = new Domain($this, $domainName, $route, $option, $pattern);
+
+        if (is_null($route)) {
+            // 获取原始分组
+            $originGroup = $this->group;
+            // 设置当前域名
+            $this->domain = $domainName;
+            $this->group  = $this->createTopGroup($domain);
+
+            // 解析域名路由规则
+            $this->parseGroupRule($domain, $rule);
+
+            // 还原默认域名
+            $this->domain = $this->host;
+            // 还原默认分组
+            $this->group = $originGroup;
         }
 
+        $this->domains[$domainName] = $domain;
+
         if (is_array($name) && !empty($name)) {
-            $root = $this->request->rootDomain();
+            $root = $this->getRootDomain();
             foreach ($name as $item) {
                 if (!strpos($item, '.')) {
                     $item .= '.' . $root;
@@ -278,6 +276,32 @@ class Route
     }
 
     /**
+     * 解析分组和域名的路由规则及绑定
+     * @access public
+     * @param  RuleGroup    $group 分组路由对象
+     * @param  mixed        $rule 路由规则
+     * @return void
+     */
+    public function parseGroupRule($group, $rule)
+    {
+        if ($rule instanceof \Closure) {
+            Container::getInstance()->invokeFunction($rule);
+        } elseif ($rule instanceof Response) {
+            $group->setRule($rule);
+        } elseif (is_array($rule)) {
+            $this->rules($rule);
+        } elseif ($rule) {
+            if (false !== strpos($rule, '?')) {
+                list($rule, $query) = explode('?', $rule);
+                parse_str($query, $vars);
+                $group->append($vars);
+            }
+
+            $this->bind($rule);
+        }
+    }
+
+    /**
      * 获取域名
      * @access public
      * @return array
@@ -291,14 +315,11 @@ class Route
      * 设置路由绑定
      * @access public
      * @param  string     $bind 绑定信息
-     * @param  string     $domain 域名
      * @return $this
      */
-    public function bind($bind, $domain = null)
+    public function bind($bind)
     {
-        $domain = is_null($domain) ? $this->domain : $domain;
-
-        $this->bind[$domain] = $bind;
+        $this->bind[$this->domain] = $bind;
 
         return $this;
     }
@@ -335,6 +356,19 @@ class Route
     }
 
     /**
+     * 设置当前路由标识
+     * @access public
+     * @param  string     $name 路由命名标识
+     * @return $this
+     */
+    public function name($name)
+    {
+        $this->ruleName = $name;
+
+        return $this;
+    }
+
+    /**
      * 读取路由标识
      * @access public
      * @param  string    $name 路由标识
@@ -342,7 +376,13 @@ class Route
      */
     public function getName($name = null)
     {
-        return Container::get('rule_name')->get($name);
+        if (is_null($name)) {
+            return $this->name;
+        }
+
+        $name = strtolower($name);
+
+        return isset($this->name[$name]) ? $this->name[$name] : null;
     }
 
     /**
@@ -353,7 +393,7 @@ class Route
      */
     public function setName($name)
     {
-        Container::get('rule_name')->import($name);
+        $this->name = $name;
         return $this;
     }
 
@@ -425,9 +465,68 @@ class Route
      * @param  array     $pattern    变量规则
      * @return RuleItem
      */
-    public function rule($rule, $route, $method = '*', array $option = [], array $pattern = [])
+    public function rule($rule, $route, $method = '*', $option = [], $pattern = [])
+    {
+        // 读取路由标识
+        if (is_array($rule)) {
+            $name = $rule[0];
+            $rule = $rule[1];
+        } elseif ($this->ruleName) {
+            $name = $this->ruleName;
+
+            $this->ruleName = null;
+        } elseif (is_string($route)) {
+            $name = $route;
+        }
+
+        $method = strtolower($method);
+
+        // 创建路由规则实例
+        $ruleItem = new RuleItem($this, $this->group, $rule, $route, $method, $option, $pattern);
+
+        if (isset($name)) {
+            // 上级完整分组名
+            $group = $this->group->getFullName();
+
+            if ($group) {
+                $rule = $group . '/' . $rule;
+            }
+
+            // 设置路由标识 用于URL快速生成
+            $this->setRuleName($rule, $name, $option);
+        }
+
+        // 添加到当前分组
+        $this->group->addRule($ruleItem, $method);
+
+        if (!empty($option['cross_domain'])) {
+            $this->setCrossDomainRule($ruleItem, $method);
+        }
+
+        return $ruleItem;
+    }
+
+    /**
+     * 设置路由标识 用于URL反解生成
+     * @access public
+     * @param  string    $rule      路由规则
+     * @param  string    $name      路由标识
+     * @param  array     $option    路由参数
+     * @return void
+     */
+    public function setRuleName($rule, $name, $option = [])
     {
-        return $this->group->addRule($rule, $route, $method, $option, $pattern);
+        $vars = $this->parseVar($rule);
+
+        if (isset($option['ext'])) {
+            $suffix = $option['ext'];
+        } elseif ($this->group->getOption('ext')) {
+            $suffix = $this->group->getOption('ext');
+        } else {
+            $suffix = null;
+        }
+
+        $this->name[strtolower($name)][] = [$rule, $vars, $this->domain, $suffix];
     }
 
     /**
@@ -440,10 +539,10 @@ class Route
     public function setCrossDomainRule($rule, $method = '*')
     {
         if (!isset($this->cross)) {
-            $this->cross = (new RuleGroup($this))->mergeRuleRegex($this->mergeRuleRegex);
+            $this->cross = new RuleGroup($this);
         }
 
-        $this->cross->addRuleItem($rule, $method);
+        $this->cross->addRule($rule, $method);
 
         return $this;
     }
@@ -457,9 +556,23 @@ class Route
      * @param  array     $pattern    变量规则
      * @return void
      */
-    public function rules($rules, $method = '*', array $option = [], array $pattern = [])
+    public function rules($rules, $method = '*', $option = [], $pattern = [])
     {
-        $this->group->addRules($rules, $method, $option, $pattern);
+        foreach ($rules as $key => $val) {
+            if (is_numeric($key)) {
+                $key = array_shift($val);
+            }
+
+            if (is_array($val)) {
+                $route   = array_shift($val);
+                $option  = $val ? array_shift($val) : [];
+                $pattern = $val ? array_shift($val) : [];
+            } else {
+                $route = $val;
+            }
+
+            $this->rule($key, $route, $method, $option, $pattern);
+        }
     }
 
     /**
@@ -471,28 +584,49 @@ class Route
      * @param  array             $pattern    变量规则
      * @return RuleGroup
      */
-    public function group($name, $route, array $option = [], array $pattern = [])
+    public function group($name, $route, $option = [], $pattern = [])
     {
         if (is_array($name)) {
             $option = $name;
             $name   = isset($option['name']) ? $option['name'] : '';
         }
 
-        return (new RuleGroup($this, $this->group, $name, $route, $option, $pattern))
-            ->lazy($this->lazy)
-            ->mergeRuleRegex($this->mergeRuleRegex);
+        // 创建分组实例
+        $rule  = $this->config->get('url_lazy_route') ? $route : null;
+        $group = new RuleGroup($this, $this->group, $name, $rule, $option, $pattern);
+
+        if (is_null($rule)) {
+            // 解析分组路由
+            $parent = $this->getGroup();
+
+            $this->group = $group;
+
+            // 解析分组路由规则
+            $this->parseGroupRule($group, $route);
+
+            $this->group = $parent;
+        }
+
+        // 注册子分组
+        $this->group->addRule($group);
+
+        if (!empty($option['cross_domain'])) {
+            $this->setCrossDomainRule($group);
+        }
+
+        return $group;
     }
 
     /**
      * 注册路由
      * @access public
      * @param  string    $rule 路由规则
-     * @param  mixed     $route 路由地址
+     * @param  string    $route 路由地址
      * @param  array     $option 路由参数
      * @param  array     $pattern 变量规则
      * @return RuleItem
      */
-    public function any($rule, $route = '', array $option = [], array $pattern = [])
+    public function any($rule, $route = '', $option = [], $pattern = [])
     {
         return $this->rule($rule, $route, '*', $option, $pattern);
     }
@@ -501,12 +635,12 @@ class Route
      * 注册GET路由
      * @access public
      * @param  string    $rule 路由规则
-     * @param  mixed     $route 路由地址
+     * @param  string    $route 路由地址
      * @param  array     $option 路由参数
      * @param  array     $pattern 变量规则
      * @return RuleItem
      */
-    public function get($rule, $route = '', array $option = [], array $pattern = [])
+    public function get($rule, $route = '', $option = [], $pattern = [])
     {
         return $this->rule($rule, $route, 'GET', $option, $pattern);
     }
@@ -515,12 +649,12 @@ class Route
      * 注册POST路由
      * @access public
      * @param  string    $rule 路由规则
-     * @param  mixed     $route 路由地址
+     * @param  string    $route 路由地址
      * @param  array     $option 路由参数
      * @param  array     $pattern 变量规则
      * @return RuleItem
      */
-    public function post($rule, $route = '', array $option = [], array $pattern = [])
+    public function post($rule, $route = '', $option = [], $pattern = [])
     {
         return $this->rule($rule, $route, 'POST', $option, $pattern);
     }
@@ -529,12 +663,12 @@ class Route
      * 注册PUT路由
      * @access public
      * @param  string    $rule 路由规则
-     * @param  mixed     $route 路由地址
+     * @param  string    $route 路由地址
      * @param  array     $option 路由参数
      * @param  array     $pattern 变量规则
      * @return RuleItem
      */
-    public function put($rule, $route = '', array $option = [], array $pattern = [])
+    public function put($rule, $route = '', $option = [], $pattern = [])
     {
         return $this->rule($rule, $route, 'PUT', $option, $pattern);
     }
@@ -543,12 +677,12 @@ class Route
      * 注册DELETE路由
      * @access public
      * @param  string    $rule 路由规则
-     * @param  mixed     $route 路由地址
+     * @param  string    $route 路由地址
      * @param  array     $option 路由参数
      * @param  array     $pattern 变量规则
      * @return RuleItem
      */
-    public function delete($rule, $route = '', array $option = [], array $pattern = [])
+    public function delete($rule, $route = '', $option = [], $pattern = [])
     {
         return $this->rule($rule, $route, 'DELETE', $option, $pattern);
     }
@@ -557,12 +691,12 @@ class Route
      * 注册PATCH路由
      * @access public
      * @param  string    $rule 路由规则
-     * @param  mixed     $route 路由地址
+     * @param  string    $route 路由地址
      * @param  array     $option 路由参数
      * @param  array     $pattern 变量规则
      * @return RuleItem
      */
-    public function patch($rule, $route = '', array $option = [], array $pattern = [])
+    public function patch($rule, $route = '', $option = [], $pattern = [])
     {
         return $this->rule($rule, $route, 'PATCH', $option, $pattern);
     }
@@ -576,31 +710,32 @@ class Route
      * @param  array     $pattern 变量规则
      * @return Resource
      */
-    public function resource($rule, $route = '', array $option = [], array $pattern = [])
+    public function resource($rule, $route = '', $option = [], $pattern = [])
     {
-        return (new Resource($this, $this->group, $rule, $route, $option, $pattern, $this->rest))
-            ->lazy($this->lazy);
+        $resource = new Resource($this, $this->group, $rule, $route, $option, $pattern, $this->rest);
+
+        // 添加到当前分组
+        $this->group->addRule($resource);
+
+        return $resource;
     }
 
     /**
-     * 注册控制器路由 操作方法对应不同的请求前缀
+     * 注册控制器路由 操作方法对应不同的请求
      * @access public
      * @param  string    $rule 路由规则
      * @param  string    $route 路由地址
      * @param  array     $option 路由参数
      * @param  array     $pattern 变量规则
-     * @return RuleGroup
+     * @return $this
      */
-    public function controller($rule, $route = '', array $option = [], array $pattern = [])
+    public function controller($rule, $route = '', $option = [], $pattern = [])
     {
-        $group = new RuleGroup($this, $this->group, $rule, null, $option, $pattern);
-
         foreach ($this->methodPrefix as $type => $val) {
-            $item = $this->$type(':action', $val . ':action');
-            $group->addRuleItem($item, $type);
+            $this->$type($rule . '/:action', $route . '/' . $val . ':action', $option, $pattern);
         }
 
-        return $group->prefix($route . '/');
+        return $this;
     }
 
     /**
@@ -613,7 +748,7 @@ class Route
      * @param  array        $pattern 变量规则
      * @return RuleItem
      */
-    public function view($rule, $template = '', array $vars = [], array $option = [], array $pattern = [])
+    public function view($rule, $template = '', $vars = [], $option = [], $pattern = [])
     {
         return $this->rule($rule, $template, 'GET', $option, $pattern)->view($vars);
     }
@@ -622,13 +757,13 @@ class Route
      * 注册重定向路由
      * @access public
      * @param  string|array $rule 路由规则
-     * @param  string       $route 路由地址
+     * @param  string       $template 路由模板地址
      * @param  array        $status 状态码
      * @param  array        $option 路由参数
      * @param  array        $pattern 变量规则
      * @return RuleItem
      */
-    public function redirect($rule, $route = '', $status = 301, array $option = [], array $pattern = [])
+    public function redirect($rule, $route = '', $status = 301, $option = [], $pattern = [])
     {
         return $this->rule($rule, $route, '*', $option, $pattern)->redirect()->status($status);
     }
@@ -636,18 +771,20 @@ class Route
     /**
      * 注册别名路由
      * @access public
-     * @param  string  $rule 路由别名
-     * @param  string  $route 路由地址
-     * @param  array   $option 路由参数
-     * @return AliasRule
+     * @param  string|array  $rule 路由别名
+     * @param  string        $route 路由地址
+     * @param  array         $option 路由参数
+     * @return $this
      */
-    public function alias($rule, $route, array $option = [])
+    public function alias($rule = null, $route = '', $option = [])
     {
-        $aliasRule = new AliasRule($this, $this->group, $rule, $route, $option);
-
-        $this->alias[$rule] = $aliasRule;
+        if (is_array($rule)) {
+            $this->alias = array_merge($this->alias, $rule);
+        } else {
+            $this->alias[$rule] = $option ? [$route, $option] : $route;
+        }
 
-        return $aliasRule;
+        return $this;
     }
 
     /**
@@ -738,9 +875,9 @@ class Route
      * @param  array     $option 路由参数
      * @return RuleItem
      */
-    public function miss($route, $method = '*', array $option = [])
+    public function miss($route, $method = '*', $option = [])
     {
-        return $this->group->addMissRule($route, $method, $option);
+        return $this->rule('', $route, $method, $option)->isMiss();
     }
 
     /**
@@ -751,7 +888,7 @@ class Route
      */
     public function auto($route)
     {
-        return $this->group->addAutoRule($route);
+        return $this->rule('', $route)->isAuto();
     }
 
     /**
@@ -773,7 +910,7 @@ class Route
         $result = $domain->check($this->request, $url, $depr, $completeMatch);
 
         if (false === $result && !empty($this->cross)) {
-            // 检测跨路由
+            // 检测跨路由
             $result = $this->cross->check($this->request, $url, $depr, $completeMatch);
         }
 
@@ -783,15 +920,16 @@ class Route
         } elseif ($must) {
             // 强制路由不匹配则抛出异常
             throw new RouteNotFoundException();
+        } else {
+            // 默认路由解析
+            return new UrlDispatch($url, ['depr' => $depr, 'auto_search' => $this->config->get('app.controller_auto_search')]);
         }
-
-        // 默认路由解析
-        return new UrlDispatch($url, ['depr' => $depr, 'auto_search' => $this->autoSearchController]);
     }
 
     /**
      * 检测域名的路由规则
      * @access protected
+     * @param  string    $host 当前主机地址
      * @return Domain
      */
     protected function checkDomain()
@@ -844,6 +982,52 @@ class Route
     }
 
     /**
+     * 分析路由规则中的变量
+     * @access public
+     * @param  string    $rule 路由规则
+     * @return array
+     */
+    public function parseVar($rule)
+    {
+        // 提取路由规则中的变量
+        $var = [];
+
+        foreach (explode('/', $rule) as $val) {
+            $optional = false;
+
+            if (false !== strpos($val, '<') && preg_match_all('/<(\w+(\??))>/', $val, $matches)) {
+                foreach ($matches[1] as $name) {
+                    if (strpos($name, '?')) {
+                        $name     = substr($name, 0, -1);
+                        $optional = true;
+                    } else {
+                        $optional = false;
+                    }
+                    $var[$name] = $optional ? 2 : 1;
+                }
+            }
+
+            if (0 === strpos($val, '[:')) {
+                // 可选参数
+                $optional = true;
+                $val      = substr($val, 1, -1);
+            }
+
+            if (0 === strpos($val, ':')) {
+                // URL变量
+                $name = substr($val, 1);
+                if ('$' == substr($name, -1)) {
+                    $name = substr($name, 0, -1);
+                }
+
+                $var[$name] = $optional ? 2 : 1;
+            }
+        }
+
+        return $var;
+    }
+
+    /**
      * 设置全局的路由分组参数
      * @access public
      * @param  string    $method     方法名

+ 65 - 29
thinkphp/library/think/Template.php

@@ -85,25 +85,36 @@ class Template
      */
     public function __construct(array $config = [])
     {
-        $this->config['cache_path'] = Container::get('app')->getRuntimePath() . 'temp/';
-        $this->config               = array_merge($this->config, $config);
-
+        $this->config['cache_path']          = Container::get('app')->getRuntimePath() . 'temp/';
+        $this->config                        = array_merge($this->config, $config);
         $this->config['taglib_begin_origin'] = $this->config['taglib_begin'];
         $this->config['taglib_end_origin']   = $this->config['taglib_end'];
-
-        $this->config['taglib_begin'] = preg_quote($this->config['taglib_begin'], '/');
-        $this->config['taglib_end']   = preg_quote($this->config['taglib_end'], '/');
-        $this->config['tpl_begin']    = preg_quote($this->config['tpl_begin'], '/');
-        $this->config['tpl_end']      = preg_quote($this->config['tpl_end'], '/');
+        $this->config['taglib_begin']        = $this->stripPreg($this->config['taglib_begin']);
+        $this->config['taglib_end']          = $this->stripPreg($this->config['taglib_end']);
+        $this->config['tpl_begin']           = $this->stripPreg($this->config['tpl_begin']);
+        $this->config['tpl_end']             = $this->stripPreg($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';
+        $class         = false !== strpos($type, '\\') ? $type : '\\think\\template\\driver\\' . ucwords($type);
         $this->storage = new $class();
     }
 
     /**
+     * 字符串替换 避免正则混淆
+     * @access private
+     * @param  string $str
+     * @return string
+     */
+    private function stripPreg($str)
+    {
+        return str_replace(
+            ['{', '}', '(', ')', '|', '[', ']', '-', '+', '*', '.', '^', '?'],
+            ['\{', '\}', '\(', '\)', '\|', '\[', '\]', '\-', '\+', '\*', '\.', '\^', '\?'],
+            $str);
+    }
+
+    /**
      * 模板变量赋值
      * @access public
      * @param  mixed $name
@@ -142,6 +153,8 @@ class Template
             $this->config = array_merge($this->config, $config);
         } elseif (isset($this->config[$config])) {
             return $this->config[$config];
+        } else {
+            return;
         }
     }
 
@@ -155,20 +168,20 @@ class Template
     {
         if ('' == $name) {
             return $this->data;
-        }
-
-        $data = $this->data;
+        } else {
+            $data = $this->data;
 
-        foreach (explode('.', $name) as $key => $val) {
-            if (isset($data[$val])) {
-                $data = $data[$val];
-            } else {
-                $data = null;
-                break;
+            foreach (explode('.', $name) as $key => $val) {
+                if (isset($data[$val])) {
+                    $data = $data[$val];
+                } else {
+                    $data = null;
+                    break;
+                }
             }
-        }
 
-        return $data;
+            return $data;
+        }
     }
 
     /**
@@ -204,7 +217,7 @@ class Template
         $template = $this->parseTemplateFile($template);
 
         if ($template) {
-            $cacheFile = $this->config['cache_path'] . $this->config['cache_prefix'] . md5($this->config['layout_on'] . $this->config['layout_name'] . $template) . '.' . ltrim($this->config['cache_suffix'], '.');
+            $cacheFile = $this->config['cache_path'] . $this->config['cache_prefix'] . md5($this->config['layout_name'] . $template) . '.' . ltrim($this->config['cache_suffix'], '.');
 
             if (!$this->checkCache($cacheFile)) {
                 // 缓存无效 重新模板编译
@@ -298,7 +311,18 @@ class Template
      */
     private function checkCache($cacheFile)
     {
-        if (!$this->config['tpl_cache'] || !is_file($cacheFile) || !$handle = @fopen($cacheFile, "r")) {
+        // 未开启缓存功能
+        if (!$this->config['tpl_cache']) {
+            return false;
+        }
+
+        // 缓存文件不存在
+        if (!is_file($cacheFile)) {
+            return false;
+        }
+
+        // 读取缓存文件失败
+        if (!$handle = @fopen($cacheFile, "r")) {
             return false;
         }
 
@@ -393,6 +417,8 @@ class Template
         $this->storage->write($cacheFile, $content);
 
         $this->includeFile = [];
+
+        return;
     }
 
     /**
@@ -464,6 +490,8 @@ class Template
 
         // 还原被替换的Literal标签
         $this->parseLiteral($content, true);
+
+        return;
     }
 
     /**
@@ -480,8 +508,10 @@ class Template
 
         // PHP语法检查
         if ($this->config['tpl_deny_php'] && false !== strpos($content, '<?php')) {
-            throw new Exception('not allow php tag');
+            throw new Exception('not allow php tag', 11600);
         }
+
+        return;
     }
 
     /**
@@ -512,6 +542,8 @@ class Template
         } else {
             $content = str_replace('{__NOLAYOUT__}', '', $content);
         }
+
+        return;
     }
 
     /**
@@ -745,6 +777,8 @@ class Template
 
             return explode(',', $matches['name']);
         }
+
+        return;
     }
 
     /**
@@ -768,6 +802,8 @@ class Template
         $tLib = new $className($this);
 
         $tLib->parseTag($content, $hide ? '' : $tagLib);
+
+        return;
     }
 
     /**
@@ -791,9 +827,9 @@ class Template
 
         if (!empty($name) && isset($array[$name])) {
             return $array[$name];
+        } else {
+            return $array;
         }
-
-        return $array;
     }
 
     /**
@@ -1232,9 +1268,9 @@ class Template
             $this->includeFile[$template] = filemtime($template);
 
             return $template;
+        } else {
+            throw new TemplateNotFoundException('template not exists:' . $template, $template);
         }
-
-        throw new TemplateNotFoundException('template not exists:' . $template, $template);
     }
 
     /**

+ 10 - 9
thinkphp/library/think/Url.php

@@ -123,8 +123,10 @@ class Url
 
             if ($alias) {
                 // 别名路由解析
-                foreach ($alias as $key => $item) {
-                    $val = $item->gerRoute();
+                foreach ($alias as $key => $val) {
+                    if (is_array($val)) {
+                        $val = $val[0];
+                    }
 
                     if (0 === strpos($url, $val)) {
                         $url        = $key . substr($url, strlen($val));
@@ -318,21 +320,20 @@ class Url
         foreach ($rule as $item) {
             list($url, $pattern, $domain, $suffix) = $item;
             if (empty($pattern)) {
-                return [rtrim($url, '?/-'), $domain, $suffix];
+                return [rtrim($url, '$'), $domain, $suffix];
             }
 
             $type = $this->app['config']->get('url_common_param');
 
             foreach ($pattern as $key => $val) {
                 if (isset($vars[$key])) {
-                    $url = str_replace(['[:' . $key . ']', '<' . $key . '?>', ':' . $key, '<' . $key . '>'], $type ? $vars[$key] : urlencode($vars[$key]), $url);
+                    $url = str_replace(['[:' . $key . ']', '[:' . $key . '$]', '<' . $key . '?>$', '<' . $key . '?>', ':' . $key . '$', ':' . $key . '', '<' . $key . '>$', '<' . $key . '>'], $type ? $vars[$key] : urlencode($vars[$key]), $url);
                     unset($vars[$key]);
-                    $url    = str_replace(['/?', '-?'], ['/', '-'], $url);
-                    $result = [rtrim($url, '?/-'), $domain, $suffix];
+
+                    $result = [$url, $domain, $suffix];
                 } elseif (2 == $val) {
-                    $url    = str_replace(['/[:' . $key . ']', '[:' . $key . ']', '<' . $key . '?>'], '', $url);
-                    $url    = str_replace(['/?', '-?'], ['/', '-'], $url);
-                    $result = [rtrim($url, '?/-'), $domain, $suffix];
+                    $url    = str_replace(['/[:' . $key . ']', '/[:' . $key . '$]', '[:' . $key . ']', '[:' . $key . '$]', '<' . $key . '?>$', '<' . $key . '?>'], '', $url);
+                    $result = [$url, $domain, $suffix];
                 } else {
                     break;
                 }

+ 27 - 28
thinkphp/library/think/Validate.php

@@ -187,7 +187,7 @@ class Validate
      */
     public function __construct(array $rules = [], array $message = [], array $field = [])
     {
-        $this->rule    = $rules + $this->rule;
+        $this->rule    = array_merge($this->rule, $rules);
         $this->message = array_merge($this->message, $message);
         $this->field   = array_merge($this->field, $field);
     }
@@ -214,7 +214,7 @@ class Validate
     public function rule($name, $rule = '')
     {
         if (is_array($name)) {
-            $this->rule = $name + $this->rule;
+            $this->rule = array_merge($this->rule, $name);
             if (is_array($rule)) {
                 $this->field = array_merge($this->field, $rule);
             }
@@ -784,13 +784,13 @@ class Validate
     {
         if (function_exists('exif_imagetype')) {
             return exif_imagetype($image);
-        }
-
-        try {
-            $info = getimagesize($image);
-            return $info ? $info[2] : false;
-        } catch (\Exception $e) {
-            return false;
+        } else {
+            try {
+                $info = getimagesize($image);
+                return $info ? $info[2] : false;
+            } catch (\Exception $e) {
+                return false;
+            }
         }
     }
 
@@ -844,9 +844,9 @@ class Validate
             return true;
         } elseif ($file instanceof File) {
             return $file->checkExt($rule);
+        } else {
+            return false;
         }
-
-        return false;
     }
 
     /**
@@ -867,9 +867,9 @@ class Validate
             return true;
         } elseif ($file instanceof File) {
             return $file->checkMime($rule);
+        } else {
+            return false;
         }
-
-        return false;
     }
 
     /**
@@ -890,9 +890,9 @@ class Validate
             return true;
         } elseif ($file instanceof File) {
             return $file->checkSize($rule);
+        } else {
+            return false;
         }
-
-        return false;
     }
 
     /**
@@ -928,9 +928,9 @@ class Validate
             list($w, $h) = $rule;
 
             return $w == $width && $h == $height;
+        } else {
+            return in_array($this->getImageType($file->getRealPath()), [1, 2, 3, 6]);
         }
-
-        return in_array($this->getImageType($file->getRealPath()), [1, 2, 3, 6]);
     }
 
     /**
@@ -1010,7 +1010,6 @@ class Validate
         if ($db->where($map)->field($pk)->find()) {
             return false;
         }
-
         return true;
     }
 
@@ -1062,9 +1061,9 @@ class Validate
 
         if ($this->getDataValue($data, $field) == $val) {
             return !empty($value) || '0' == $value;
+        } else {
+            return true;
         }
-
-        return true;
     }
 
     /**
@@ -1081,9 +1080,9 @@ class Validate
 
         if ($result) {
             return !empty($value) || '0' == $value;
+        } else {
+            return true;
         }
-
-        return true;
     }
 
     /**
@@ -1100,9 +1099,9 @@ class Validate
 
         if (!empty($val)) {
             return !empty($value) || '0' == $value;
+        } else {
+            return true;
         }
-
-        return true;
     }
 
     /**
@@ -1184,10 +1183,10 @@ class Validate
             // 长度区间
             list($min, $max) = explode(',', $rule);
             return $length >= $min && $length <= $max;
+        } else {
+            // 指定长度
+            return $length == $rule;
         }
-
-        // 指定长度
-        return $length == $rule;
     }
 
     /**
@@ -1322,7 +1321,7 @@ class Validate
             $rule = '/^' . $rule . '$/';
         }
 
-        return is_scalar($value) && 1 === preg_match($rule, (string) $value);
+        return 1 === preg_match($rule, (string) $value);
     }
 
     /**

+ 3 - 6
thinkphp/library/think/cache/driver/File.php

@@ -43,7 +43,7 @@ class File extends Driver
         }
 
         if (empty($this->options['path'])) {
-            $this->options['path'] = Container::get('app')->getRuntimePath() . 'cache' . DIRECTORY_SEPARATOR;
+            $this->options['path'] = Container::get('app')->getRuntimePath() . 'cache/';
         } elseif (substr($this->options['path'], -1) != DIRECTORY_SEPARATOR) {
             $this->options['path'] .= DIRECTORY_SEPARATOR;
         }
@@ -242,10 +242,7 @@ class File extends Driver
     {
         $this->writeTimes++;
 
-        try {
-            return $this->unlink($this->getCacheKey($name));
-        } catch (\Exception $e) {
-        }
+        return $this->unlink($this->getCacheKey($name));
     }
 
     /**
@@ -272,7 +269,7 @@ class File extends Driver
 
         foreach ($files as $path) {
             if (is_dir($path)) {
-                $matches = glob($path . DIRECTORY_SEPARATOR . '*.php');
+                $matches = glob($path . '/*.php');
                 if (is_array($matches)) {
                     array_map('unlink', $matches);
                 }

+ 1 - 36
thinkphp/library/think/cache/driver/Redis.php

@@ -74,7 +74,7 @@ class Redis extends Driver
      */
     public function has($name)
     {
-        return $this->handler->exists($this->getCacheKey($name));
+        return $this->handler->get($this->getCacheKey($name)) ? true : false;
     }
 
     /**
@@ -203,39 +203,4 @@ class Redis extends Driver
         return $this->handler->flushDB();
     }
 
-    /**
-     * 如果不存在则写入缓存
-     * @access public
-     * @param string $name 缓存变量名
-     * @param mixed $value 存储数据
-     * @param int $expire  有效时间 0为永久
-     * @return mixed
-     */
-    public function remember($name, $value, $expire = null)
-    {
-        if (is_null($expire)) {
-            $expire = $this->options['expire'];
-        }
-
-        // 没有过期参数时,使用setnx
-        if (!$expire) {
-            $key = $this->getCacheKey($name);
-            $val = $this->serialize($value);
-            $res = $this->handler->setnx($key, $val);
-            if ($res) {
-                $this->writeTimes++;
-                return $value;
-            } else {
-                return $this->get($name);
-            }
-        }
-
-        if ($this->has($name)) {
-            return $this->get($name);
-        } else {
-            $this->set($name, $value, $expire);
-        }
-
-        return $value;
-    }
 }

+ 1 - 1
thinkphp/library/think/console/command/Clear.php

@@ -34,7 +34,7 @@ class Clear extends Command
         if ($files) {
             foreach ($files as $file) {
                 if ('.' != $file && '..' != $file && is_dir($path . $file)) {
-                    array_map('unlink', glob($path . $file . DIRECTORY_SEPARATOR . '*.*'));
+                    array_map('unlink', glob($path . $file . '/*.*'));
                 } elseif ('.gitignore' != $file && is_file($path . $file)) {
                     unlink($path . $file);
                 }

+ 1 - 1
thinkphp/library/think/console/command/RunServer.php

@@ -42,7 +42,7 @@ class RunServer extends Command
             $host,
             $port,
             escapeshellarg($root),
-            escapeshellarg($root . DIRECTORY_SEPARATOR . 'router.php')
+            escapeshellarg($root . '/router.php')
         );
 
         $output->writeln(sprintf('ThinkPHP Development server is started On <http://%s:%s/>', $host, $port));

+ 2 - 9
thinkphp/library/think/console/command/make/Controller.php

@@ -24,24 +24,17 @@ class Controller extends Make
     {
         parent::configure();
         $this->setName('make:controller')
-            ->addOption('api', null, Option::VALUE_NONE, 'Generate an api controller class.')
             ->addOption('plain', null, Option::VALUE_NONE, 'Generate an empty controller class.')
             ->setDescription('Create a new resource controller class');
     }
 
     protected function getStub()
     {
-        $stubPath = __DIR__ . DIRECTORY_SEPARATOR . 'stubs' . DIRECTORY_SEPARATOR;
-
-        if ($this->input->getOption('api')) {
-            return $stubPath . 'controller.api.stub';
-        }
-
         if ($this->input->getOption('plain')) {
-            return $stubPath . 'controller.plain.stub';
+            return __DIR__ . '/stubs/controller.plain.stub';
         }
 
-        return $stubPath . 'controller.stub';
+        return __DIR__ . '/stubs/controller.stub';
     }
 
     protected function getClassName($name)

+ 0 - 36
thinkphp/library/think/console/command/make/Middleware.php

@@ -1,36 +0,0 @@
-<?php
-// +----------------------------------------------------------------------
-// | ThinkPHP [ WE CAN DO IT JUST THINK ]
-// +----------------------------------------------------------------------
-// | Copyright (c) 2016 http://thinkphp.cn All rights reserved.
-// +----------------------------------------------------------------------
-// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
-// +----------------------------------------------------------------------
-// | Author: 刘志淳 <chun@engineer.com>
-// +----------------------------------------------------------------------
-
-namespace think\console\command\make;
-
-use think\console\command\Make;
-
-class Middleware extends Make
-{
-    protected $type = "Middleware";
-
-    protected function configure()
-    {
-        parent::configure();
-        $this->setName('make:middleware')
-            ->setDescription('Create a new middleware class');
-    }
-
-    protected function getStub()
-    {
-        return __DIR__ . DIRECTORY_SEPARATOR . 'stubs' . DIRECTORY_SEPARATOR . 'middleware.stub';
-    }
-
-    protected function getNamespace($appNamespace, $module)
-    {
-        return parent::getNamespace($appNamespace, 'http') . '\middleware';
-    }
-}

+ 1 - 1
thinkphp/library/think/console/command/make/Model.php

@@ -26,7 +26,7 @@ class Model extends Make
 
     protected function getStub()
     {
-        return __DIR__ . DIRECTORY_SEPARATOR . 'stubs' . DIRECTORY_SEPARATOR . 'model.stub';
+        return __DIR__ . '/stubs/model.stub';
     }
 
     protected function getNamespace($appNamespace, $module)

+ 0 - 64
thinkphp/library/think/console/command/make/stubs/controller.api.stub

@@ -1,64 +0,0 @@
-<?php
-
-namespace {%namespace%};
-
-use think\Controller;
-use think\Request;
-
-class {%className%} extends Controller
-{
-    /**
-     * 显示资源列表
-     *
-     * @return \think\Response
-     */
-    public function index()
-    {
-        //
-    }
-
-    /**
-     * 保存新建的资源
-     *
-     * @param  \think\Request  $request
-     * @return \think\Response
-     */
-    public function save(Request $request)
-    {
-        //
-    }
-
-    /**
-     * 显示指定的资源
-     *
-     * @param  int  $id
-     * @return \think\Response
-     */
-    public function read($id)
-    {
-        //
-    }
-
-    /**
-     * 保存更新的资源
-     *
-     * @param  \think\Request  $request
-     * @param  int  $id
-     * @return \think\Response
-     */
-    public function update(Request $request, $id)
-    {
-        //
-    }
-
-    /**
-     * 删除指定资源
-     *
-     * @param  int  $id
-     * @return \think\Response
-     */
-    public function delete($id)
-    {
-        //
-    }
-}

+ 0 - 10
thinkphp/library/think/console/command/make/stubs/middleware.stub

@@ -1,10 +0,0 @@
-<?php
-
-namespace {%namespace%};
-
-class {%className%}
-{
-    public function handle($request, \Closure $next)
-    {
-    }
-}

+ 2 - 15
thinkphp/library/think/console/command/optimize/Config.php

@@ -71,10 +71,7 @@ class Config extends Command
 
         // 加载行为扩展文件
         if (is_file($path . 'tags.php')) {
-            $tags = include $path . 'tags.php';
-            if (is_array($tags)) {
-                $content .= PHP_EOL . '\think\facade\Hook::import(' . (var_export($tags, true)) . ');' . PHP_EOL;
-            }
+            $content .= PHP_EOL . '\think\facade\Hook::import(' . (var_export(include $path . 'tags.php' ?: [], true)) . ');' . PHP_EOL;
         }
 
         // 加载公共文件
@@ -87,20 +84,10 @@ class Config extends Command
 
         if ('' == $module) {
             $content .= PHP_EOL . substr(php_strip_whitespace(App::getThinkPath() . 'helper.php'), 6) . PHP_EOL;
-
-            if (is_file($path . 'middleware.php')) {
-                $middleware = include $path . 'middleware.php';
-                if (is_array($middleware)) {
-                    $content .= PHP_EOL . '\think\Container::get("middleware")->import(' . var_export($middleware, true) . ');' . PHP_EOL;
-                }
-            }
         }
 
         if (is_file($path . 'provider.php')) {
-            $provider = include $path . 'provider.php';
-            if (is_array($provider)) {
-                $content .= PHP_EOL . '\think\Container::getInstance()->bind(' . var_export($provider, true) . ');' . PHP_EOL;
-            }
+            $content .= PHP_EOL . '\think\Container::getInstance()->bind(' . var_export(include $path . 'provider.php' ?: [], true) . ');' . PHP_EOL;
         }
 
         $content .= PHP_EOL . '\think\facade\Config::set(' . var_export($config->get(), true) . ');' . PHP_EOL;

+ 2 - 4
thinkphp/library/think/console/command/optimize/Route.php

@@ -28,16 +28,14 @@ class Route extends Command
 
     protected function execute(Input $input, Output $output)
     {
-        $filename = Container::get('app')->getRuntimePath() . 'route.php';
-        unlink($filename);
-        file_put_contents($filename, $this->buildRouteCache());
+        file_put_contents(Container::get('app')->getRuntimePath() . 'route.php', $this->buildRouteCache());
         $output->writeln('<info>Succeed!</info>');
     }
 
     protected function buildRouteCache()
     {
         Container::get('route')->setName([]);
-        Container::get('route')->lazy(false);
+        Container::get('config')->set('url_lazy_route', false);
         // 路由检测
         $path = Container::get('app')->getRoutePath();
 

+ 1 - 1
thinkphp/library/think/console/command/optimize/Schema.php

@@ -99,7 +99,7 @@ class Schema extends Command
             $info    = $class::getConnection()->getFields($table);
             $content .= var_export($info, true) . ';';
 
-            file_put_contents(App::getRuntimePath() . 'schema' . DIRECTORY_SEPARATOR . $dbName . '.' . $table . '.php', $content);
+            file_put_contents(App::getRuntimePath() . 'schema/' . $dbName . '.' . $table . '.php', $content);
         }
     }
 

+ 10 - 28
thinkphp/library/think/db/Builder.php

@@ -135,19 +135,13 @@ abstract class Builder
             } elseif (is_array($val) && !empty($val)) {
                 switch ($val[0]) {
                     case 'exp':
-                        if (isset($val[2]) && $query->getSecureKey() == $val[2]) {
-                            $result[$item] = $val[1];
-                        }
+                        $result[$item] = $val[1];
                         break;
                     case 'inc':
-                        if ($key == $val[1]) {
-                            $result[$item] = $this->parseKey($query, $val[1]) . ' + ' . floatval($val[2]);
-                        }
+                        $result[$item] = $this->parseKey($query, $val[1]) . ' + ' . floatval($val[2]);
                         break;
                     case 'dec':
-                        if ($key == $val[1]) {
-                            $result[$item] = $this->parseKey($query, $val[1]) . ' - ' . floatval($val[2]);
-                        }
+                        $result[$item] = $this->parseKey($query, $val[1]) . ' - ' . floatval($val[2]);
                         break;
                 }
             } elseif (is_scalar($val)) {
@@ -174,11 +168,12 @@ abstract class Builder
         // 过滤非标量数据
         if (0 === strpos($data, ':') && $query->isBind(substr($data, 1))) {
             return $data;
+        } else {
+            $key  = str_replace(['.', '->'], '_', $key);
+            $name = 'data__' . $key . $suffix;
+            $query->bind($name, $data, isset($bind[$key]) ? $bind[$key] : PDO::PARAM_STR);
+            return ':' . $name;
         }
-        $key  = str_replace(['.', '->'], '_', $key);
-        $name = 'data__' . $key . $suffix;
-        $query->bind($name, $data, isset($bind[$key]) ? $bind[$key] : PDO::PARAM_STR);
-        return ':' . $name;
     }
 
     /**
@@ -233,7 +228,6 @@ abstract class Builder
     {
         $item    = [];
         $options = $query->getOptions();
-
         foreach ((array) $tables as $key => $table) {
             if (!is_numeric($key)) {
                 $key    = $this->connection->parseSqlTable($key);
@@ -393,7 +387,7 @@ abstract class Builder
             $exp = $this->exp[$exp];
         }
 
-        $bindName = $bindName ?: 'where_' . $rule . '_' . str_replace(['.', '-'], '_', $field);
+        $bindName = $bindName ?: 'where_' . str_replace(['.', '-'], '_', $field);
 
         if (preg_match('/\W/', $bindName)) {
             // 处理带非单词字符的字段名
@@ -851,19 +845,7 @@ abstract class Builder
      */
     protected function parseGroup(Query $query, $group)
     {
-        if (empty($group)) {
-            return '';
-        }
-
-        if (is_string($group)) {
-            $group = explode(',', $group);
-        }
-
-        foreach ($group as $key) {
-            $val[] = $this->parseKey($query, $key);
-        }
-
-        return ' GROUP BY ' . implode(',', $val);
+        return !empty($group) ? ' GROUP BY ' . $this->parseKey($query, $group) : '';
     }
 
     /**

+ 250 - 270
thinkphp/library/think/db/Connection.php

@@ -106,8 +106,6 @@ abstract class Connection
         'query'           => '\\think\\db\\Query',
         // 是否需要断线重连
         'break_reconnect' => false,
-        // 断线标识字符串
-        'break_match_str' => [],
     ];
 
     // PDO连接参数
@@ -119,21 +117,6 @@ abstract class Connection
         PDO::ATTR_EMULATE_PREPARES  => false,
     ];
 
-    // 服务器断线标识字符
-    protected $breakMatchStr = [
-        'server has gone away',
-        'no connection to the server',
-        'Lost connection',
-        'is dead or not enabled',
-        'Error while sending',
-        'decryption failed or bad record mac',
-        'server closed the connection unexpectedly',
-        'SSL connection has been closed unexpectedly',
-        'Error writing data to the connection',
-        'Resource deadlock avoided',
-        'failed with errno',
-    ];
-
     // 绑定参数
     protected $bind = [];
 
@@ -210,9 +193,9 @@ abstract class Connection
     {
         if (!empty($this->builderClassName)) {
             return $this->builderClassName;
+        } else {
+            return $this->getConfig('builder') ?: '\\think\\db\\builder\\' . ucfirst($this->getConfig('type'));
         }
-
-        return $this->getConfig('builder') ?: '\\think\\db\\builder\\' . ucfirst($this->getConfig('type'));
     }
 
     /**
@@ -368,8 +351,7 @@ abstract class Connection
 
         if (!isset(self::$info[$schema])) {
             // 读取缓存
-            $cacheFile = Container::get('app')->getRuntimePath() . 'schema' . DIRECTORY_SEPARATOR . $schema . '.php';
-
+            $cacheFile = Container::get('app')->getRuntimePath() . 'schema/' . $schema . '.php';
             if (!$this->config['debug'] && is_file($cacheFile)) {
                 $info = include $cacheFile;
             } else {
@@ -383,7 +365,6 @@ abstract class Connection
                 // 记录字段类型
                 $type[$key] = $val['type'];
                 $bind[$key] = $this->getFieldBindType($val['type']);
-
                 if (!empty($val['primary'])) {
                     $pk[] = $key;
                 }
@@ -491,55 +472,49 @@ abstract class Connection
      */
     public function connect(array $config = [], $linkNum = 0, $autoConnection = false)
     {
-        if (isset($this->links[$linkNum])) {
-            return $this->links[$linkNum];
-        }
-
-        if (!$config) {
-            $config = $this->config;
-        } else {
-            $config = array_merge($this->config, $config);
-        }
-
-        // 连接参数
-        if (isset($config['params']) && is_array($config['params'])) {
-            $params = $config['params'] + $this->params;
-        } else {
-            $params = $this->params;
-        }
-
-        // 记录当前字段属性大小写设置
-        $this->attrCase = $params[PDO::ATTR_CASE];
-
-        if (!empty($config['break_match_str'])) {
-            $this->breakMatchStr = array_merge($this->breakMatchStr, (array) $config['break_match_str']);
-        }
-
-        try {
-            if (empty($config['dsn'])) {
-                $config['dsn'] = $this->parseDsn($config);
+        if (!isset($this->links[$linkNum])) {
+            if (!$config) {
+                $config = $this->config;
+            } else {
+                $config = array_merge($this->config, $config);
             }
 
-            if ($config['debug']) {
-                $startTime = microtime(true);
+            // 连接参数
+            if (isset($config['params']) && is_array($config['params'])) {
+                $params = $config['params'] + $this->params;
+            } else {
+                $params = $this->params;
             }
 
-            $this->links[$linkNum] = new PDO($config['dsn'], $config['username'], $config['password'], $params);
+            // 记录当前字段属性大小写设置
+            $this->attrCase = $params[PDO::ATTR_CASE];
 
-            if ($config['debug']) {
-                // 记录数据库连接信息
-                $this->log('[ DB ] CONNECT:[ UseTime:' . number_format(microtime(true) - $startTime, 6) . 's ] ' . $config['dsn']);
-            }
+            try {
+                if (empty($config['dsn'])) {
+                    $config['dsn'] = $this->parseDsn($config);
+                }
 
-            return $this->links[$linkNum];
-        } catch (\PDOException $e) {
-            if ($autoConnection) {
-                $this->log($e->getMessage(), 'error');
-                return $this->connect($autoConnection, $linkNum);
-            } else {
-                throw $e;
+                if ($config['debug']) {
+                    $startTime = microtime(true);
+                }
+
+                $this->links[$linkNum] = new PDO($config['dsn'], $config['username'], $config['password'], $params);
+
+                if ($config['debug']) {
+                    // 记录数据库连接信息
+                    $this->log('[ DB ] CONNECT:[ UseTime:' . number_format(microtime(true) - $startTime, 6) . 's ] ' . $config['dsn']);
+                }
+            } catch (\PDOException $e) {
+                if ($autoConnection) {
+                    $this->log($e->getMessage(), 'error');
+                    return $this->connect($autoConnection, $linkNum);
+                } else {
+                    throw $e;
+                }
             }
         }
+
+        return $this->links[$linkNum];
     }
 
     /**
@@ -560,9 +535,9 @@ abstract class Connection
     {
         if (!$this->linkID) {
             return false;
+        } else {
+            return $this->linkID;
         }
-
-        return $this->linkID;
     }
 
     /**
@@ -808,10 +783,11 @@ abstract class Connection
         $pk      = $query->getPk($options);
 
         if (!empty($options['cache']) && true === $options['cache']['key'] && is_string($pk) && isset($options['where']['AND'][$pk])) {
-            $key = $this->getCacheKey($query, $options['where']['AND'][$pk]);
+            $key = $this->getCacheKey($options['where']['AND'][$pk], $options);
         }
 
-        $data = $options['data'];
+        $data   = $options['data'];
+        $result = false;
 
         if (empty($options['fetch_sql']) && !empty($options['cache'])) {
             // 判断查询缓存
@@ -820,57 +796,55 @@ abstract class Connection
             if (is_string($cache['key'])) {
                 $key = $cache['key'];
             } elseif (!isset($key)) {
-                $key = $this->getCacheKey($query, $data);
+                $key = $this->getCacheKey($data, $options, $query->getBind(false));
             }
 
             $result = Container::get('cache')->get($key);
-
-            if (false !== $result) {
-                return $result;
-            }
         }
 
-        if (is_string($pk) && !is_array($data)) {
-            if (isset($key) && strpos($key, '|')) {
-                list($a, $val) = explode('|', $key);
-                $item[$pk]     = $val;
-            } else {
-                $item[$pk] = $data;
+        if (false === $result) {
+            if (is_string($pk)) {
+                if (!is_array($data)) {
+                    if (isset($key) && strpos($key, '|')) {
+                        list($a, $val) = explode('|', $key);
+                        $item[$pk]     = $val;
+                    } else {
+                        $item[$pk] = $data;
+                    }
+                    $data = $item;
+                }
             }
-            $data = $item;
-        }
-
-        $query->setOption('data', $data);
-        $query->setOption('limit', 1);
+            $query->setOption('data', $data);
+            $query->setOption('limit', 1);
 
-        // 生成查询SQL
-        $sql = $this->builder->select($query);
+            // 生成查询SQL
+            $sql = $this->builder->select($query);
 
-        $bind = $query->getBind();
+            $bind = $query->getBind();
 
-        if (!empty($options['fetch_sql'])) {
-            // 获取实际执行的SQL语句
-            return $this->getRealSql($sql, $bind);
-        }
+            if (!empty($options['fetch_sql'])) {
+                // 获取实际执行的SQL语句
+                return $this->getRealSql($sql, $bind);
+            }
 
-        // 事件回调
-        $result = $query->trigger('before_find');
+            // 事件回调
+            if ($result = $query->trigger('before_find')) {
+            } else {
+                // 执行查询
+                $resultSet = $this->query($sql, $bind, $options['master'], $options['fetch_pdo']);
 
-        if (!$result) {
-            // 执行查询
-            $resultSet = $this->query($sql, $bind, $options['master'], $options['fetch_pdo']);
+                if ($resultSet instanceof \PDOStatement) {
+                    // 返回PDOStatement对象
+                    return $resultSet;
+                }
 
-            if ($resultSet instanceof \PDOStatement) {
-                // 返回PDOStatement对象
-                return $resultSet;
+                $result = isset($resultSet[0]) ? $resultSet[0] : null;
             }
 
-            $result = isset($resultSet[0]) ? $resultSet[0] : null;
-        }
-
-        if (isset($cache) && $result) {
-            // 缓存数据
-            $this->cacheData($key, $result, $cache);
+            if (isset($cache) && $result) {
+                // 缓存数据
+                $this->cacheData($key, $result, $cache);
+            }
         }
 
         return $result;
@@ -911,41 +885,42 @@ abstract class Connection
     public function select(Query $query)
     {
         // 分析查询表达式
-        $options = $query->getOptions();
+        $options   = $query->getOptions();
+        $resultSet = false;
 
         if (empty($options['fetch_sql']) && !empty($options['cache'])) {
-            $resultSet = $this->getCacheData($query, $options['cache'], null, $key);
-
-            if (false !== $resultSet) {
-                return $resultSet;
-            }
+            // 判断查询缓存
+            $cache     = $options['cache'];
+            $key       = is_string($cache['key']) ? $cache['key'] : md5(serialize($options) . serialize($query->getBind(false)));
+            $resultSet = Container::get('cache')->get($key);
         }
 
-        // 生成查询SQL
-        $sql = $this->builder->select($query);
-
-        $bind = $query->getBind();
+        if (false === $resultSet) {
+            // 生成查询SQL
+            $sql = $this->builder->select($query);
 
-        if (!empty($options['fetch_sql'])) {
-            // 获取实际执行的SQL语句
-            return $this->getRealSql($sql, $bind);
-        }
+            $bind = $query->getBind();
 
-        $resultSet = $query->trigger('before_select');
+            if (!empty($options['fetch_sql'])) {
+                // 获取实际执行的SQL语句
+                return $this->getRealSql($sql, $bind);
+            }
 
-        if (!$resultSet) {
-            // 执行查询操作
-            $resultSet = $this->query($sql, $bind, $options['master'], $options['fetch_pdo']);
+            if ($resultSet = $query->trigger('before_select')) {
+            } else {
+                // 执行查询操作
+                $resultSet = $this->query($sql, $bind, $options['master'], $options['fetch_pdo']);
 
-            if ($resultSet instanceof \PDOStatement) {
-                // 返回PDOStatement对象
-                return $resultSet;
+                if ($resultSet instanceof \PDOStatement) {
+                    // 返回PDOStatement对象
+                    return $resultSet;
+                }
             }
-        }
 
-        if (!empty($options['cache']) && false !== $resultSet) {
-            // 缓存数据集
-            $this->cacheData($key, $resultSet, $options['cache']);
+            if (isset($cache) && false !== $resultSet) {
+                // 缓存数据集
+                $this->cacheData($key, $resultSet, $cache);
+            }
         }
 
         return $resultSet;
@@ -1033,7 +1008,6 @@ abstract class Connection
                 foreach ($array as $item) {
                     $sql  = $this->builder->insertAll($query, $item, $replace);
                     $bind = $query->getBind();
-
                     if (!empty($options['fetch_sql'])) {
                         $fetchSql[] = $this->getRealSql($sql, $bind);
                     } else {
@@ -1058,10 +1032,12 @@ abstract class Connection
         $bind = $query->getBind();
 
         if (!empty($options['fetch_sql'])) {
+            // 获取实际执行的SQL语句
             return $this->getRealSql($sql, $bind);
+        } else {
+            // 执行操作
+            return $this->execute($sql, $bind);
         }
-
-        return $this->execute($sql, $bind);
     }
 
     /**
@@ -1078,6 +1054,7 @@ abstract class Connection
         // 分析查询表达式
         $options = $query->getOptions();
 
+        // 生成SQL语句
         $table = $this->parseSqlTable($table);
 
         $sql = $this->builder->selectInsert($query, $fields, $table);
@@ -1085,10 +1062,12 @@ abstract class Connection
         $bind = $query->getBind();
 
         if (!empty($options['fetch_sql'])) {
+            // 获取实际执行的SQL语句
             return $this->getRealSql($sql, $bind);
+        } else {
+            // 执行操作
+            return $this->execute($sql, $bind);
         }
-
-        return $this->execute($sql, $bind);
     }
 
     /**
@@ -1115,7 +1094,7 @@ abstract class Connection
             if (is_string($pk) && isset($data[$pk])) {
                 $where[$pk] = [$pk, '=', $data[$pk]];
                 if (!isset($key)) {
-                    $key = $this->getCacheKey($query, $data[$pk]);
+                    $key = $this->getCacheKey($data[$pk], $options);
                 }
                 unset($data[$pk]);
             } elseif (is_array($pk)) {
@@ -1139,7 +1118,7 @@ abstract class Connection
                 $query->setOption('where', ['AND' => $where]);
             }
         } elseif (!isset($key) && is_string($pk) && isset($options['where']['AND'][$pk])) {
-            $key = $this->getCacheKey($query, $options['where']['AND'][$pk]);
+            $key = $this->getCacheKey($options['where']['AND'][$pk], $options);
         }
 
         // 更新数据
@@ -1152,34 +1131,34 @@ abstract class Connection
         if (!empty($options['fetch_sql'])) {
             // 获取实际执行的SQL语句
             return $this->getRealSql($sql, $bind);
-        }
-
-        // 检测缓存
-        $cache = Container::get('cache');
+        } else {
+            // 检测缓存
+            $cache = Container::get('cache');
+
+            if (isset($key) && $cache->get($key)) {
+                // 删除缓存
+                $cache->rm($key);
+            } elseif (!empty($options['cache']['tag'])) {
+                $cache->clear($options['cache']['tag']);
+            }
 
-        if (isset($key) && $cache->get($key)) {
-            // 删除缓存
-            $cache->rm($key);
-        } elseif (!empty($options['cache']['tag'])) {
-            $cache->clear($options['cache']['tag']);
-        }
+            // 执行操作
+            $result = '' == $sql ? 0 : $this->execute($sql, $bind);
 
-        // 执行操作
-        $result = '' == $sql ? 0 : $this->execute($sql, $bind);
+            if ($result) {
+                if (is_string($pk) && isset($where[$pk])) {
+                    $data[$pk] = $where[$pk];
+                } elseif (is_string($pk) && isset($key) && strpos($key, '|')) {
+                    list($a, $val) = explode('|', $key);
+                    $data[$pk]     = $val;
+                }
 
-        if ($result) {
-            if (is_string($pk) && isset($where[$pk])) {
-                $data[$pk] = $where[$pk];
-            } elseif (is_string($pk) && isset($key) && strpos($key, '|')) {
-                list($a, $val) = explode('|', $key);
-                $data[$pk]     = $val;
+                $query->setOption('data', $data);
+                $query->trigger('after_update');
             }
 
-            $query->setOption('data', $data);
-            $query->trigger('after_update');
+            return $result;
         }
-
-        return $result;
     }
 
     /**
@@ -1200,9 +1179,9 @@ abstract class Connection
         if (isset($options['cache']) && is_string($options['cache']['key'])) {
             $key = $options['cache']['key'];
         } elseif (!is_null($data) && true !== $data && !is_array($data)) {
-            $key = $this->getCacheKey($query, $data);
+            $key = $this->getCacheKey($data, $options);
         } elseif (is_string($pk) && isset($options['where']['AND'][$pk])) {
-            $key = $this->getCacheKey($query, $options['where']['AND'][$pk]);
+            $key = $this->getCacheKey($options['where']['AND'][$pk], $options);
         }
 
         if (true !== $data && empty($options['where'])) {
@@ -1260,44 +1239,50 @@ abstract class Connection
     {
         $options = $query->getOptions();
 
+        $result = false;
         if (empty($options['fetch_sql']) && !empty($options['cache'])) {
+            // 判断查询缓存
+            $cache = $options['cache'];
 
-            $result = $this->getCacheData($query, $options['cache'], $field, $key);
-
-            if (false !== $result) {
-                return $result;
-            }
+            $key    = is_string($cache['key']) ? $cache['key'] : md5($field . serialize($options) . serialize($query->getBind(false)));
+            $result = Container::get('cache')->get($key);
         }
 
-        if (isset($options['field'])) {
-            $query->removeOption('field');
-        }
+        if (false === $result) {
+            if (isset($options['field'])) {
+                $query->removeOption('field');
+            }
 
-        if (is_string($field)) {
-            $field = array_map('trim', explode(',', $field));
-        }
+            if (is_string($field)) {
+                $field = array_map('trim', explode(',', $field));
+            }
 
-        $query->setOption('field', $field);
-        $query->setOption('limit', 1);
+            $query->setOption('field', $field);
+            $query->setOption('limit', 1);
+            // 生成查询SQL
+            $sql = $this->builder->select($query);
 
-        // 生成查询SQL
-        $sql = $this->builder->select($query);
+            $bind = $query->getBind();
 
-        $bind = $query->getBind();
+            if (!empty($options['fetch_sql'])) {
+                // 获取实际执行的SQL语句
+                return $this->getRealSql($sql, $bind);
+            }
 
-        if (!empty($options['fetch_sql'])) {
-            // 获取实际执行的SQL语句
-            return $this->getRealSql($sql, $bind);
-        }
+            // 执行查询操作
+            $pdo = $this->query($sql, $bind, $options['master'], true);
 
-        // 执行查询操作
-        $pdo = $this->query($sql, $bind, $options['master'], true);
+            if (is_string($pdo)) {
+                // 返回SQL语句
+                return $pdo;
+            }
 
-        $result = $pdo->fetchColumn();
+            $result = $pdo->fetchColumn();
 
-        if (isset($cache) && false !== $result) {
-            // 缓存数据
-            $this->cacheData($key, $result, $cache);
+            if (isset($cache) && false !== $result) {
+                // 缓存数据
+                $this->cacheData($key, $result, $cache);
+            }
         }
 
         return false !== $result ? $result : $default;
@@ -1330,83 +1315,82 @@ abstract class Connection
     {
         $options = $query->getOptions();
 
+        $result = false;
+
         if (empty($options['fetch_sql']) && !empty($options['cache'])) {
             // 判断查询缓存
             $cache = $options['cache'];
 
-            $guid = is_string($cache['key']) ? $cache['key'] : $this->getCacheKey($query, $field);
-
+            $guid   = is_string($cache['key']) ? $cache['key'] : md5($field . serialize($options) . serialize($query->getBind(false)));
             $result = Container::get('cache')->get($guid);
+        }
 
-            if (false !== $result) {
-                return $result;
+        if (false === $result) {
+            if (isset($options['field'])) {
+                $query->removeOption('field');
             }
-        }
 
-        if (isset($options['field'])) {
-            $query->removeOption('field');
-        }
+            if (is_null($field)) {
+                $field = '*';
+            } elseif ($key && '*' != $field) {
+                $field = $key . ',' . $field;
+            }
 
-        if (is_null($field)) {
-            $field = '*';
-        } elseif ($key && '*' != $field) {
-            $field = $key . ',' . $field;
-        }
+            if (is_string($field)) {
+                $field = array_map('trim', explode(',', $field));
+            }
 
-        if (is_string($field)) {
-            $field = array_map('trim', explode(',', $field));
-        }
+            $query->setOption('field', $field);
 
-        $query->setOption('field', $field);
+            // 生成查询SQL
+            $sql = $this->builder->select($query);
 
-        // 生成查询SQL
-        $sql = $this->builder->select($query);
+            $bind = $query->getBind();
 
-        $bind = $query->getBind();
+            if (!empty($options['fetch_sql'])) {
+                // 获取实际执行的SQL语句
+                return $this->getRealSql($sql, $bind);
+            }
 
-        if (!empty($options['fetch_sql'])) {
-            // 获取实际执行的SQL语句
-            return $this->getRealSql($sql, $bind);
-        }
+            // 执行查询操作
+            $pdo = $this->query($sql, $bind, $options['master'], true);
 
-        // 执行查询操作
-        $pdo = $this->query($sql, $bind, $options['master'], true);
+            if (1 == $pdo->columnCount()) {
+                $result = $pdo->fetchAll(PDO::FETCH_COLUMN);
+            } else {
+                $resultSet = $pdo->fetchAll(PDO::FETCH_ASSOC);
+
+                if ('*' == $field && $key) {
+                    $result = array_column($resultSet, null, $key);
+                } elseif ($resultSet) {
+                    $fields = array_keys($resultSet[0]);
+                    $count  = count($fields);
+                    $key1   = array_shift($fields);
+                    $key2   = $fields ? array_shift($fields) : '';
+                    $key    = $key ?: $key1;
+
+                    if (strpos($key, '.')) {
+                        list($alias, $key) = explode('.', $key);
+                    }
 
-        if (1 == $pdo->columnCount()) {
-            $result = $pdo->fetchAll(PDO::FETCH_COLUMN);
-        } else {
-            $resultSet = $pdo->fetchAll(PDO::FETCH_ASSOC);
-
-            if ('*' == $field && $key) {
-                $result = array_column($resultSet, null, $key);
-            } elseif ($resultSet) {
-                $fields = array_keys($resultSet[0]);
-                $count  = count($fields);
-                $key1   = array_shift($fields);
-                $key2   = $fields ? array_shift($fields) : '';
-                $key    = $key ?: $key1;
-
-                if (strpos($key, '.')) {
-                    list($alias, $key) = explode('.', $key);
-                }
+                    if (2 == $count) {
+                        $column = $key2;
+                    } elseif (1 == $count) {
+                        $column = $key1;
+                    } else {
+                        $column = null;
+                    }
 
-                if (2 == $count) {
-                    $column = $key2;
-                } elseif (1 == $count) {
-                    $column = $key1;
+                    $result = array_column($resultSet, $column, $key);
                 } else {
-                    $column = null;
+                    $result = [];
                 }
-
-                $result = array_column($resultSet, $column, $key);
-            } else {
-                $result = [];
             }
-        }
 
-        if (isset($cache) && isset($guid)) {
-            // 缓存数据
-            $this->cacheData($guid, $result, $cache);
+            if (isset($cache) && isset($guid)) {
+                // 缓存数据
+                $this->cacheData($guid, $result, $cache);
+            }
         }
 
         return $result;
@@ -1800,9 +1784,22 @@ abstract class Connection
             return false;
         }
 
+        $info = [
+            'server has gone away',
+            'no connection to the server',
+            'Lost connection',
+            'is dead or not enabled',
+            'Error while sending',
+            'decryption failed or bad record mac',
+            'server closed the connection unexpectedly',
+            'SSL connection has been closed unexpectedly',
+            'Error writing data to the connection',
+            'Resource deadlock avoided',
+        ];
+
         $error = $e->getMessage();
 
-        foreach ($this->breakMatchStr as $msg) {
+        foreach ($info as $msg) {
             if (false !== stripos($error, $msg)) {
                 return true;
             }
@@ -2050,29 +2047,14 @@ abstract class Connection
     }
 
     /**
-     * 获取缓存数据
-     * @access protected
-     * @param  Query     $query   查询对象
-     * @param  mixed     $cache   缓存设置
-     * @param  array     $options 缓存
-     * @return mixed
-     */
-    protected function getCacheData(Query $query, $cache, $data, &$key = null)
-    {
-        // 判断查询缓存
-        $key = is_string($cache['key']) ? $cache['key'] : $this->getCacheKey($query, $data);
-
-        return Container::get('cache')->get($key);
-    }
-
-    /**
      * 生成缓存标识
      * @access protected
-     * @param  Query     $query   查询对象
      * @param  mixed     $value   缓存数据
+     * @param  array     $options 缓存参数
+     * @param  array     $bind    绑定参数
      * @return string
      */
-    protected function getCacheKey(Query $query, $value)
+    protected function getCacheKey($value, $options, $bind = [])
     {
         if (is_scalar($value)) {
             $data = $value;
@@ -2080,16 +2062,14 @@ abstract class Connection
             $data = $value[2];
         }
 
-        $prefix = 'think:' . $this->getConfig('database') . '.';
-
         if (isset($data)) {
-            return $prefix . $query->getTable() . '|' . $data;
-        }
-
-        try {
-            return md5($prefix . serialize($query->getOptions()) . serialize($query->getBind(false)));
-        } catch (\Exception $e) {
-            return;
+            return 'think:' . (is_array($options['table']) ? key($options['table']) : $options['table']) . '|' . $data;
+        } else {
+            try {
+                return md5(serialize($options) . serialize($bind));
+            } catch (\Exception $e) {
+                return;
+            }
         }
     }
 

+ 108 - 190
thinkphp/library/think/db/Query.php

@@ -59,12 +59,6 @@ class Query
     protected $pk;
 
     /**
-     * 查询安全Key
-     * @var string
-     */
-    protected $secureKey;
-
-    /**
      * 当前数据表前缀
      * @var string
      */
@@ -127,8 +121,7 @@ class Query
             $this->connection = $connection;
         }
 
-        $this->prefix    = $this->connection->getConfig('prefix');
-        $this->secureKey = Container::get('request')->secureKey();
+        $this->prefix = $this->connection->getConfig('prefix');
     }
 
     /**
@@ -272,16 +265,6 @@ class Query
     }
 
     /**
-     * 获取查询安全Key
-     * @access public
-     * @return string
-     */
-    public function getSecureKey()
-    {
-        return $this->secureKey;
-    }
-
-    /**
      * 得到当前或者指定名称的数据表
      * @access public
      * @param  string $name
@@ -309,8 +292,7 @@ class Query
     public function connect($config = [], $name = false)
     {
         $this->connection = Connection::instance($config, $name);
-
-        $query = $this->connection->getConfig('query');
+        $query            = $this->connection->getConfig('query');
 
         if (__CLASS__ != trim($query, '\\')) {
             return new $query($this->connection);
@@ -374,16 +356,6 @@ class Query
     }
 
     /**
-     * 获取返回或者影响的记录数
-     * @access public
-     * @return integer
-     */
-    public function getNumRows()
-    {
-        return $this->connection->getNumRows();
-    }
-
-    /**
      * 获取最近一次查询的sql语句
      * @access public
      * @return string
@@ -452,7 +424,7 @@ class Query
      * 获取数据库的配置参数
      * @access public
      * @param  string $name 参数名称
-     * @return mixed
+     * @return boolean
      */
     public function getConfig($name = '')
     {
@@ -535,17 +507,18 @@ class Query
                     }
             }
             return $this->getTable() . '_' . $seq;
-        }
-        // 当设置的分表字段不在查询条件或者数据中
-        // 进行联合查询,必须设定 partition['num']
-        $tableName = [];
-        for ($i = 0; $i < $rule['num']; $i++) {
-            $tableName[] = 'SELECT * FROM ' . $this->getTable() . '_' . ($i + 1);
-        }
+        } else {
+            // 当设置的分表字段不在查询条件或者数据中
+            // 进行联合查询,必须设定 partition['num']
+            $tableName = [];
+            for ($i = 0; $i < $rule['num']; $i++) {
+                $tableName[] = 'SELECT * FROM ' . $this->getTable() . '_' . ($i + 1);
+            }
 
-        $tableName = '( ' . implode(" UNION ", $tableName) . ') AS ' . $this->name;
+            $tableName = '( ' . implode(" UNION ", $tableName) . ') AS ' . $this->name;
 
-        return $tableName;
+            return $tableName;
+        }
     }
 
     /**
@@ -871,7 +844,6 @@ class Query
     {
         if (is_array($join)) {
             $table = $join;
-            $alias = array_shift($join);
         } else {
             $join = trim($join);
 
@@ -1058,7 +1030,7 @@ class Query
      */
     public function exp($field, $value)
     {
-        $this->data($field, ['exp', $value, $this->secureKey]);
+        $this->data($field, ['exp', $value]);
         return $this;
     }
 
@@ -1075,9 +1047,9 @@ class Query
     {
         $this->options['view'] = true;
 
-        if (is_array($join) && key($join) === 0) {
+        if (is_array($join) && key($join) !== 0) {
             foreach ($join as $key => $val) {
-                $this->view($val[0], $val[1], isset($val[2]) ? $val[2] : null, isset($val[3]) ? $val[3] : 'INNER');
+                $this->view($key, $val[0], isset($val[1]) ? $val[1] : null, isset($val[2]) ? $val[2] : 'INNER');
             }
         } else {
             $fields = [];
@@ -1190,7 +1162,7 @@ class Query
      */
     public function whereNull($field, $logic = 'AND')
     {
-        return $this->parseWhereExp($logic, $field, 'null', null, [], true);
+        return $this->parseWhereExp($logic, $field, 'null', null);
     }
 
     /**
@@ -1202,7 +1174,7 @@ class Query
      */
     public function whereNotNull($field, $logic = 'AND')
     {
-        return $this->parseWhereExp($logic, $field, 'notnull', null, [], true);
+        return $this->parseWhereExp($logic, $field, 'notnull', null);
     }
 
     /**
@@ -1241,7 +1213,7 @@ class Query
      */
     public function whereIn($field, $condition, $logic = 'AND')
     {
-        return $this->parseWhereExp($logic, $field, 'in', $condition, [], true);
+        return $this->parseWhereExp($logic, $field, 'in', $condition);
     }
 
     /**
@@ -1254,7 +1226,7 @@ class Query
      */
     public function whereNotIn($field, $condition, $logic = 'AND')
     {
-        return $this->parseWhereExp($logic, $field, 'not in', $condition, [], true);
+        return $this->parseWhereExp($logic, $field, 'not in', $condition);
     }
 
     /**
@@ -1267,7 +1239,7 @@ class Query
      */
     public function whereLike($field, $condition, $logic = 'AND')
     {
-        return $this->parseWhereExp($logic, $field, 'like', $condition, [], true);
+        return $this->parseWhereExp($logic, $field, 'like', $condition);
     }
 
     /**
@@ -1280,7 +1252,7 @@ class Query
      */
     public function whereNotLike($field, $condition, $logic = 'AND')
     {
-        return $this->parseWhereExp($logic, $field, 'not like', $condition, [], true);
+        return $this->parseWhereExp($logic, $field, 'not like', $condition);
     }
 
     /**
@@ -1293,7 +1265,7 @@ class Query
      */
     public function whereBetween($field, $condition, $logic = 'AND')
     {
-        return $this->parseWhereExp($logic, $field, 'between', $condition, [], true);
+        return $this->parseWhereExp($logic, $field, 'between', $condition);
     }
 
     /**
@@ -1306,7 +1278,7 @@ class Query
      */
     public function whereNotBetween($field, $condition, $logic = 'AND')
     {
-        return $this->parseWhereExp($logic, $field, 'not between', $condition, [], true);
+        return $this->parseWhereExp($logic, $field, 'not between', $condition);
     }
 
     /**
@@ -1349,27 +1321,25 @@ class Query
      * @access public
      * @param  mixed  $field     查询字段
      * @param  mixed  $condition 查询条件
-     * @param  array  $bind      参数绑定
      * @param  string $logic     查询逻辑 and or xor
      * @return $this
      */
-    public function whereExp($field, $condition, $bind = [], $logic = 'AND')
+    public function whereExp($field, $condition, $logic = 'AND')
     {
-        return $this->parseWhereExp($logic, $field, 'exp', $condition, $bind, true);
+        return $this->parseWhereExp($logic, $field, 'exp', $condition);
     }
 
     /**
      * 分析查询表达式
-     * @access protected
+     * @access public
      * @param  string   $logic     查询逻辑 and or xor
      * @param  mixed    $field     查询字段
      * @param  mixed    $op        查询表达式
      * @param  mixed    $condition 查询条件
      * @param  array    $param     查询参数
-     * @param  bool     $strict    严格模式
      * @return $this
      */
-    protected function parseWhereExp($logic, $field, $op, $condition, array $param = [], $strict = false)
+    protected function parseWhereExp($logic, $field, $op, $condition, $param = [])
     {
         if ($field instanceof $this) {
             $this->options['where'] = $field->getOptions('where');
@@ -1382,104 +1352,64 @@ class Query
             $field = $this->options['via'] . '.' . $field;
         }
 
-        if ($strict) {
-            // 使用严格模式查询
-            $where = [$field, $op, $condition];
-            if ('exp' == strtolower($op) && !empty($param)) {
-                // 参数绑定
-                $this->bind($param);
-            }
-        } elseif (is_array($field)) {
-            // 解析数组批量查询
-            return $this->parseArrayWhereItems($field, $logic);
-        } elseif ($field instanceof \Closure) {
-            $where = $field;
+        if ($field instanceof \Closure) {
+            $where = is_string($op) ? [$op, $field] : $field;
             $field = '';
-        } elseif (is_string($field)) {
-            // 解析条件单元
-            $where = $this->parseWhereItem($logic, $field, $op, $condition, $param);
-        }
-
-        if (!empty($where)) {
-            if (isset($this->options['where'][$logic][$field])) {
-                $this->options['where'][$logic][] = $where;
-            } else {
-                $this->options['where'][$logic][$field] = $where;
-            }
-        }
-
-        return $this;
-    }
-
-    /**
-     * 分析查询表达式
-     * @access protected
-     * @param  string   $logic     查询逻辑 and or xor
-     * @param  mixed    $field     查询字段
-     * @param  mixed    $op        查询表达式
-     * @param  mixed    $condition 查询条件
-     * @param  array    $param     查询参数
-     * @return mixed
-     */
-    protected function parseWhereItem($logic, $field, $op, $condition, $param = [])
-    {
-        if (preg_match('/[,=\<\'\"\(\s]/', $field)) {
+        } elseif (is_string($field) && preg_match('/[,=\<\'\"\(\s]/', $field)) {
             $where = ['', 'exp', $field];
             if (is_array($op)) {
                 // 参数绑定
                 $this->bind($op);
             }
+        } elseif (is_null($op) && is_null($condition)) {
+            if (is_array($field)) {
+                if (key($field) !== 0) {
+                    $where = [];
+                    foreach ($field as $key => $val) {
+                        if (is_null($val)) {
+                            $where[$key] = [$key, 'null', ''];
+                        } else {
+                            $where[$key] = !is_scalar($val) ? $val : [$key, '=', $val];
+                        }
+                    }
+                } else {
+                    // 数组批量查询
+                    $where = $field;
+                }
+
+                if (!empty($where)) {
+                    $this->options['where'][$logic] = isset($this->options['where'][$logic]) ? array_merge($this->options['where'][$logic], $where) : $where;
+                }
+
+                return $this;
+            } elseif ($field && is_string($field)) {
+                // 字符串查询
+                $where = [$field, 'null', ''];
+            }
         } elseif (is_array($op)) {
-            // 同一字段多条件查询
             array_unshift($param, $field);
             $where = $param;
-        } elseif ($field && is_null($condition)) {
-            if (in_array(strtolower($op), ['null', 'notnull', 'not null'])) {
-                // null查询
-                $where = [$field, $op, ''];
-            } else {
-                // 字段相等查询
-                $where = is_null($op) ? [$field, 'null', ''] : [$field, '=', $op];
-            }
-        } elseif (strtolower($op) == 'exp') {
-            $bind  = isset($param[2]) && is_array($param[2]) ? $param[2] : null;
-            $where = [$field, 'exp', $condition, $bind];
-            if ($bind) {
-                // 参数绑定
-                $this->bind($bind);
-            }
+        } elseif (in_array(strtolower($op), ['null', 'notnull', 'not null'])) {
+            // null查询
+            $where = [$field, $op, ''];
+        } elseif (is_null($condition)) {
+            // 字段相等查询
+            $where = [$field, '=', $op];
         } else {
-            $where = $field ? [$field, $op, $condition] : null;
-        }
-
-        return $where;
-    }
+            $where = [$field, $op, $condition, isset($param[2]) ? $param[2] : null];
 
-    /**
-     * 数组批量查询
-     * @access protected
-     * @param  array    $field     批量查询
-     * @param  string   $logic     查询逻辑 and or xor
-     * @return $this
-     */
-    protected function parseArrayWhereItems($field, $logic)
-    {
-        if (key($field) !== 0) {
-            $where = [];
-            foreach ($field as $key => $val) {
-                if (is_null($val)) {
-                    $where[$key] = [$key, 'null', ''];
-                } else {
-                    $where[$key] = !is_scalar($val) ? $val : [$key, '=', $val];
-                }
+            if ('exp' == strtolower($op) && isset($param[2]) && is_array($param[2])) {
+                // 参数绑定
+                $this->bind($param[2]);
             }
-        } else {
-            // 数组批量查询
-            $where = $field;
         }
 
         if (!empty($where)) {
-            $this->options['where'][$logic] = isset($this->options['where'][$logic]) ? array_merge($this->options['where'][$logic], $where) : $where;
+            if (isset($this->options['where'][$logic][$field])) {
+                $this->options['where'][$logic][] = $where;
+            } else {
+                $this->options['where'][$logic][$field] = $where;
+            }
         }
 
         return $this;
@@ -1692,7 +1622,6 @@ class Query
                 }
             }
         }
-
         $this->options['table'] = $table;
 
         return $this;
@@ -1719,35 +1648,33 @@ class Query
      */
     public function order($field, $order = null)
     {
-        if (empty($field)) {
-            return $this;
-        }
-
-        if (is_string($field)) {
-            if (!empty($this->options['via'])) {
-                $field = $this->options['via'] . '.' . $field;
-            }
+        if (!empty($field)) {
+            if (is_string($field)) {
+                if (!empty($this->options['via'])) {
+                    $field = $this->options['via'] . '.' . $field;
+                }
 
-            $field = empty($order) ? $field : [$field => $order];
-        } elseif (!empty($this->options['via'])) {
-            foreach ($field as $key => $val) {
-                if (is_numeric($key)) {
-                    $field[$key] = $this->options['via'] . '.' . $val;
-                } else {
-                    $field[$this->options['via'] . '.' . $key] = $val;
-                    unset($field[$key]);
+                $field = empty($order) ? $field : [$field => $order];
+            } elseif (!empty($this->options['via'])) {
+                foreach ($field as $key => $val) {
+                    if (is_numeric($key)) {
+                        $field[$key] = $this->options['via'] . '.' . $val;
+                    } else {
+                        $field[$this->options['via'] . '.' . $key] = $val;
+                        unset($field[$key]);
+                    }
                 }
             }
-        }
 
-        if (!isset($this->options['order'])) {
-            $this->options['order'] = [];
-        }
+            if (!isset($this->options['order'])) {
+                $this->options['order'] = [];
+            }
 
-        if (is_array($field)) {
-            $this->options['order'] = array_merge($this->options['order'], $field);
-        } else {
-            $this->options['order'][] = $field;
+            if (is_array($field)) {
+                $this->options['order'] = array_merge($this->options['order'], $field);
+            } else {
+                $this->options['order'][] = $field;
+            }
         }
 
         return $this;
@@ -1806,7 +1733,7 @@ class Query
     /**
      * 指定group查询
      * @access public
-     * @param  string|array $group GROUP
+     * @param  string $group GROUP
      * @return $this
      */
     public function group($group)
@@ -2059,10 +1986,9 @@ class Query
      * @param  string       $field 日期字段名
      * @param  string|array $op    比较运算符或者表达式
      * @param  string|array $range 比较范围
-     * @param  string       $logic AND OR
      * @return $this
      */
-    public function whereTime($field, $op, $range = null, $logic = 'AND')
+    public function whereTime($field, $op, $range = null)
     {
         if (is_null($range)) {
             if (is_array($op)) {
@@ -2082,7 +2008,9 @@ class Query
             $op = is_array($range) ? 'between' : '>=';
         }
 
-        return $this->parseWhereExp($logic, $field, strtolower($op) . ' time', $range, [], true);
+        $this->where($field, strtolower($op) . ' time', $range);
+
+        return $this;
     }
 
     /**
@@ -2091,17 +2019,18 @@ class Query
      * @param  string    $field 日期字段名
      * @param  string    $startTime    开始时间
      * @param  string    $endTime 结束时间
-     * @param  string    $logic AND OR
      * @return $this
      */
-    public function whereBetweenTime($field, $startTime, $endTime = null, $logic = 'AND')
+    public function whereBetweenTime($field, $startTime, $endTime = null)
     {
         if (is_null($endTime)) {
             $time    = is_string($startTime) ? strtotime($startTime) : $startTime;
             $endTime = strtotime('+1 day', $time);
         }
 
-        return $this->parseWhereExp($logic, $field, 'between time', [$startTime, $endTime], [], true);
+        $this->where($field, 'between time', [$startTime, $endTime]);
+
+        return $this;
     }
 
     /**
@@ -2115,7 +2044,7 @@ class Query
         if (!empty($this->pk)) {
             $pk = $this->pk;
         } else {
-            $pk = $this->connection->getPk(is_array($options) && isset($options['table']) ? $options['table'] : $this->getTable());
+            $pk = $this->connection->getPk(is_array($options) ? $options['table'] : $this->getTable());
         }
 
         return $pk;
@@ -2153,19 +2082,6 @@ class Query
 
     /**
      * 查询参数赋值
-     * @access public
-     * @param  string $name     参数名
-     * @param  mixed  $value    值
-     * @return $this
-     */
-    public function option($name, $value)
-    {
-        $this->options[$name] = $value;
-        return $this;
-    }
-
-    /**
-     * 查询参数赋值
      * @access protected
      * @param  array $options 表达式参数
      * @return $this
@@ -2186,8 +2102,9 @@ class Query
     {
         if ('' === $name) {
             return $this->options;
+        } else {
+            return isset($this->options[$name]) ? $this->options[$name] : null;
         }
-        return isset($this->options[$name]) ? $this->options[$name] : null;
     }
 
     /**
@@ -2762,9 +2679,10 @@ class Query
         if (!empty($this->model)) {
             $class = get_class($this->model);
             throw new ModelNotFoundException('model data Not Found:' . $class, $class, $options);
+        } else {
+            $table = is_array($options['table']) ? key($options['table']) : $options['table'];
+            throw new DataNotFoundException('table data not Found:' . $table, $table, $options);
         }
-        $table = is_array($options['table']) ? key($options['table']) : $options['table'];
-        throw new DataNotFoundException('table data not Found:' . $table, $table, $options);
     }
 
     /**

+ 2 - 2
thinkphp/library/think/db/builder/Mysql.php

@@ -116,9 +116,9 @@ class Mysql extends Builder
 
         if (strpos($key, '->') && false === strpos($key, '(')) {
             // JSON字段支持
-            list($field, $name) = explode('->', $key, 2);
+            list($field, $name) = explode('->', $key);
 
-            $key = 'json_extract(' . $this->parseKey($query, $field) . ', \'$.' . str_replace('->', '.', $name) . '\')';
+            $key = 'json_extract(' . $this->parseKey($query, $field) . ', \'$.' . $name . '\')';
         } elseif (strpos($key, '.') && !preg_match('/[,\'\"\(\)`\s]/', $key)) {
             list($table, $key) = explode('.', $key, 2);
 

+ 1 - 1
thinkphp/library/think/debug/Html.php

@@ -49,7 +49,7 @@ class Html
             return false;
         }
         // 获取基本信息
-        $runtime = number_format(microtime(true) - Container::get('app')->getBeginTime(), 10, '.', '');
+        $runtime = number_format(microtime(true) - Container::get('app')->getBeginTime(), 10);
         $reqs    = $runtime > 0 ? number_format(1 / $runtime, 2) : '∞';
         $mem     = number_format((memory_get_usage() - Container::get('app')->getBeginMem()) / 1024, 2);
 

+ 21 - 48
thinkphp/library/think/Middleware.php → thinkphp/library/think/http/middleware/Dispatcher.php

@@ -9,17 +9,18 @@
 // | Author: Slince <taosikai@yeah.net>
 // +----------------------------------------------------------------------
 
-namespace think;
+namespace think\http\middleware;
 
-class Middleware
+use think\Request;
+use think\Response;
+
+class Dispatcher implements DispatcherInterface
 {
-    protected $queue = [];
+    protected $queue;
 
-    public function import(array $middlewares = [])
+    public function __construct($middlewares = [])
     {
-        foreach ($middlewares as $middleware) {
-            $this->add($middleware);
-        }
+        $this->queue = (array) $middlewares;
     }
 
     /**
@@ -27,26 +28,16 @@ class Middleware
      */
     public function add($middleware)
     {
-        if (is_null($middleware)) {
-            return;
-        }
-
-        $middleware = $this->buildMiddleware($middleware);
-
+        $this->assertValid($middleware);
         $this->queue[] = $middleware;
     }
 
     /**
      * {@inheritdoc}
      */
-    public function unshift($middleware)
+    public function insert($middleware)
     {
-        if (is_null($middleware)) {
-            return;
-        }
-
-        $middleware = $this->buildMiddleware($middleware);
-
+        $this->assertValid($middleware);
         array_unshift($this->queue, $middleware);
     }
 
@@ -63,30 +54,8 @@ class Middleware
      */
     public function dispatch(Request $request)
     {
-        return call_user_func($this->resolve(), $request);
-    }
-
-    protected function buildMiddleware($middleware)
-    {
-        if (is_array($middleware)) {
-            list($middleware, $param) = $middleware;
-        }
-
-        if ($middleware instanceof \Closure) {
-            return [$middleware, null];
-        }
-
-        if (!is_string($middleware)) {
-            throw new \InvalidArgumentException('The middleware is invalid');
-        }
-
-        $class = false === strpos($middleware, '\\') ? Container::get('app')->getNamespace() . '\\http\\middleware\\' . $middleware : $middleware;
-
-        if (strpos($class, ':')) {
-            list($class, $param) = explode(':', $class, 2);
-        }
-
-        return [[Container::get($class), 'handle'], isset($param) ? $param : null];
+        $requestHandler = $this->resolve();
+        return call_user_func($requestHandler, $request);
     }
 
     protected function resolve()
@@ -95,9 +64,7 @@ class Middleware
             $middleware = array_shift($this->queue);
 
             if (null !== $middleware) {
-                list($call, $param) = $middleware;
-
-                $response = call_user_func_array($call, [$request, $this->resolve(), $param]);
+                $response = call_user_func($middleware, $request, $this->resolve());
 
                 if (!$response instanceof Response) {
                     throw new \LogicException('The middleware must return Response instance');
@@ -105,9 +72,15 @@ class Middleware
 
                 return $response;
             } else {
-                throw new \InvalidArgumentException('The queue was exhausted, with no response returned');
+                throw new MissingResponseException('The queue was exhausted, with no response returned');
             }
         };
     }
 
+    protected function assertValid($middleware)
+    {
+        if (!is_callable($middleware)) {
+            throw new \InvalidArgumentException('The middleware is invalid');
+        }
+    }
 }

+ 45 - 0
thinkphp/library/think/http/middleware/DispatcherInterface.php

@@ -0,0 +1,45 @@
+<?php
+// +----------------------------------------------------------------------
+// | ThinkPHP [ WE CAN DO IT JUST THINK ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
+// +----------------------------------------------------------------------
+// | Author: Slince <taosikai@yeah.net>
+// +----------------------------------------------------------------------
+
+namespace think\http\middleware;
+
+use think\Request;
+use think\Response;
+
+interface DispatcherInterface
+{
+    /**
+     * 在队尾添加 middleware
+     * @param callable $middleware
+     * @return DispatcherInterface
+     */
+    public function add($middleware);
+
+    /**
+     * 在队前插入 middleware
+     * @param callable $middleware
+     * @return DispatcherInterface
+     */
+    public function insert($middleware);
+
+    /**
+     * 获取所有的middleware
+     * @return array
+     */
+    public function all();
+
+    /**
+     * 处理 request 并返回 response
+     * @param Request $request
+     * @return Response
+     */
+    public function dispatch(Request $request);
+}

+ 4 - 16
thinkphp/library/think/facade/Middleware.php → thinkphp/library/think/http/middleware/MissingResponseException.php

@@ -6,22 +6,10 @@
 // +----------------------------------------------------------------------
 // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
 // +----------------------------------------------------------------------
-// | Author: liu21st <liu21st@gmail.com>
+// | Author: Slince <taosikai@yeah.net>
 // +----------------------------------------------------------------------
 
-namespace think\facade;
+namespace think\http\middleware;
 
-use think\Facade;
-
-/**
- * @see \think\Middleware
- * @mixin \think\Middleware
- * @method void import(array $middlewares = []) static 批量设置中间件
- * @method void add(mixed $middleware) static 添加中间件到队列
- * @method void unshift(mixed $middleware) static 添加中间件到队列开头
- * @method array all() static 获取中间件队列
- * @method \think\Response dispatch(\think\Request $request) static 执行中间件调度
- */
-class Middleware extends Facade
-{
-}
+class MissingResponseException extends \InvalidArgumentException
+{}

+ 69 - 0
thinkphp/library/think/http/tests/middleware/DispatcherTest.php

@@ -0,0 +1,69 @@
+<?php
+
+namespace think\http\tests\middleware;
+
+use PHPUnit\Framework\TestCase;
+use think\http\middleware\Dispatcher;
+use think\http\middleware\MissingResponseException;
+use think\Request;
+use think\Response;
+
+class DispatcherTest extends TestCase
+{
+    public function testValidMiddleware()
+    {
+        $dispatcher = new Dispatcher();
+        $dispatcher->add(function () {
+        });
+        $this->assertCount(1, $dispatcher->all());
+        $this->expectException(\InvalidArgumentException::class);
+        $dispatcher->add('foo middleware');
+    }
+
+    public function testAddAndInsert()
+    {
+        $middleware1 = function () {};
+        $middleware2 = function () {};
+        $dispatcher = new Dispatcher();
+        $dispatcher->add($middleware1);
+        $dispatcher->insert($middleware2);
+        $this->assertSame([$middleware2, $middleware1], $dispatcher->all());
+    }
+
+    public function testDispatch()
+    {
+        $middleware1 = function ($request, $next) {
+            return $next($request);
+        };
+        $middleware2 = function ($request) {
+            return Response::create('hello world');
+        };
+        $dispatcher = new Dispatcher([$middleware1, $middleware2]);
+        $response   = $dispatcher->dispatch(new Request());
+        $this->assertInstanceOf(Response::class, $response);
+        $this->assertEquals('hello world', $response->getContent());
+    }
+
+    public function testDispatchWithoutResponse()
+    {
+        $middleware1 = function ($request, $next) {
+            return $next($request);
+        };
+        $middleware2 = function ($request, $next) {
+            return $next($request);
+        };
+        $dispatcher = new Dispatcher([$middleware1, $middleware2]);
+        $this->expectException(MissingResponseException::class);
+        $dispatcher->dispatch(new Request());
+    }
+
+    public function testDispatchWithBadResponse()
+    {
+        $middleware = function ($request, $next) {
+            return 'invalid response';
+        };
+        $dispatcher = new Dispatcher($middleware);
+        $this->expectException(\LogicException::class);
+        $dispatcher->dispatch(new Request());
+    }
+}

+ 7 - 24
thinkphp/library/think/log/driver/File.php

@@ -24,7 +24,6 @@ class File
         'file_size'   => 2097152,
         'path'        => '',
         'apart_level' => [],
-        'max_files'   => 0,
     ];
 
     protected $writed = [];
@@ -37,9 +36,7 @@ class File
         }
 
         if (empty($this->config['path'])) {
-            $this->config['path'] = Container::get('app')->getRuntimePath() . 'log' . DIRECTORY_SEPARATOR;
-        } elseif (substr($this->config['path'], -1) != DIRECTORY_SEPARATOR) {
-            $this->config['path'] .= DIRECTORY_SEPARATOR;
+            $this->config['path'] = Container::get('app')->getRuntimePath() . 'log/';
         }
     }
 
@@ -52,23 +49,11 @@ class File
     public function save(array $log = [])
     {
         if ($this->config['single']) {
-            $name        = is_string($this->config['single']) ? $this->config['single'] : 'single';
+            $name        = is_string($single) ? $single : 'single';
             $destination = $this->config['path'] . $name . '.log';
         } else {
-            $cli = PHP_SAPI == 'cli' ? '_cli' : '';
-
-            if ($this->config['max_files']) {
-                $filename = date('Ymd') . $cli . '.log';
-                $files    = glob($this->config['path'] . '*.log');
-
-                if (count($files) > $this->config['max_files']) {
-                    unlink($files[0]);
-                }
-            } else {
-                $filename = date('Ym') . DIRECTORY_SEPARATOR . date('d') . $cli . '.log';
-            }
-
-            $destination = $this->config['path'] . $filename;
+            $cli         = PHP_SAPI == 'cli' ? '_cli' : '';
+            $destination = $this->config['path'] . date('Ym') . '/' . date('d') . $cli . '.log';
         }
 
         $path = dirname($destination);
@@ -87,11 +72,9 @@ class File
             if (in_array($type, $this->config['apart_level'])) {
                 // 独立记录的日志级别
                 if ($this->config['single']) {
-                    $filename = $path . DIRECTORY_SEPARATOR . $name . '_' . $type . '.log';
-                } elseif ($this->config['max_files']) {
-                    $filename = $path . DIRECTORY_SEPARATOR . date('Ymd') . '_' . $type . $cli . '.log';
+                    $filename = $path . '/' . $name . '_' . $type . '.log';
                 } else {
-                    $filename = $path . DIRECTORY_SEPARATOR . date('d') . '_' . $type . $cli . '.log';
+                    $filename = $path . '/' . date('d') . '_' . $type . $cli . '.log';
                 }
 
                 $this->write($level, $filename, true);
@@ -120,7 +103,7 @@ class File
         // 检测日志文件大小,超过配置大小则备份日志文件重新生成
         if (is_file($destination) && floor($this->config['file_size']) <= filesize($destination)) {
             try {
-                rename($destination, dirname($destination) . DIRECTORY_SEPARATOR . time() . '-' . basename($destination));
+                rename($destination, dirname($destination) . '/' . time() . '-' . basename($destination));
             } catch (\Exception $e) {
             }
 

+ 12 - 0
thinkphp/library/think/model/Collection.php

@@ -17,6 +17,18 @@ use think\Model;
 class Collection extends BaseCollection
 {
     /**
+     * 返回数组中指定的一列
+     * @access public
+     * @param  string        $column_key
+     * @param  string|null   $index_key
+     * @return array
+     */
+    public function column($column_key, $index_key = null)
+    {
+        return array_column($this->toArray(), $column_key, $index_key);
+    }
+
+    /**
      * 延迟预载入关联查询
      * @access public
      * @param  mixed $relation 关联

+ 49 - 67
thinkphp/library/think/model/concern/Attribute.php

@@ -139,38 +139,37 @@ trait Attribute
     {
         if (is_string($data)) {
             $this->data[$data] = $value;
-            return $this;
-        }
-
-        // 清空数据
-        $this->data = [];
+        } else {
+            // 清空数据
+            $this->data = [];
 
-        if (is_object($data)) {
-            $data = get_object_vars($data);
-        }
+            if (is_object($data)) {
+                $data = get_object_vars($data);
+            }
 
-        if ($this->disuse) {
-            // 废弃字段
-            foreach ((array) $this->disuse as $key) {
-                if (array_key_exists($key, $data)) {
-                    unset($data[$key]);
+            if ($this->disuse) {
+                // 废弃字段
+                foreach ((array) $this->disuse as $key) {
+                    if (array_key_exists($key, $data)) {
+                        unset($data[$key]);
+                    }
                 }
             }
-        }
 
-        if (true === $value) {
-            // 数据对象赋值
-            foreach ($data as $key => $value) {
-                $this->setAttr($key, $value, $data);
-            }
-        } elseif (is_array($value)) {
-            foreach ($value as $name) {
-                if (isset($data[$name])) {
-                    $this->data[$name] = $data[$name];
+            if (true === $value) {
+                // 数据对象赋值
+                foreach ($data as $key => $value) {
+                    $this->setAttr($key, $value, $data);
+                }
+            } elseif (is_array($value)) {
+                foreach ($value as $name) {
+                    if (isset($data[$name])) {
+                        $this->data[$name] = $data[$name];
+                    }
                 }
+            } else {
+                $this->data = $data;
             }
-        } else {
-            $this->data = $data;
         }
 
         return $this;
@@ -211,8 +210,9 @@ trait Attribute
     {
         if (is_null($name)) {
             return $this->origin;
+        } else {
+            return array_key_exists($name, $this->origin) ? $this->origin[$name] : null;
         }
-        return array_key_exists($name, $this->origin) ? $this->origin[$name] : null;
     }
 
     /**
@@ -230,8 +230,9 @@ trait Attribute
             return $this->data[$name];
         } elseif (array_key_exists($name, $this->relation)) {
             return $this->relation[$name];
+        } else {
+            throw new InvalidArgumentException('property not exists:' . static::class . '->' . $name);
         }
-        throw new InvalidArgumentException('property not exists:' . static::class . '->' . $name);
     }
 
     /**
@@ -453,51 +454,36 @@ trait Attribute
                 $value = $this->formatDateTime($value, $this->dateFormat);
             }
         } elseif ($notFound) {
-            $value = $this->getRelationAttribute($name, $item);
-        }
+            $relation = $this->isRelationAttr($name);
 
-        return $value;
-    }
-
-    /**
-     * 获取关联属性值
-     * @access protected
-     * @param  string   $name  属性名
-     * @param  array    $item  数据
-     * @return mixed
-     */
-    protected function getRelationAttribute($name, &$item)
-    {
-        $relation = $this->isRelationAttr($name);
-
-        if ($relation) {
-            $modelRelation = $this->$relation();
-            if ($modelRelation instanceof Relation) {
-                $value = $this->getRelationData($modelRelation);
+            if ($relation) {
+                $modelRelation = $this->$relation();
+                if ($modelRelation instanceof Relation) {
+                    $value = $this->getRelationData($modelRelation);
 
-                if ($item && method_exists($modelRelation, 'getBindAttr') && $bindAttr = $modelRelation->getBindAttr()) {
+                    if ($item && method_exists($modelRelation, 'getBindAttr') && $bindAttr = $modelRelation->getBindAttr()) {
 
-                    foreach ($bindAttr as $key => $attr) {
-                        $key = is_numeric($key) ? $attr : $key;
+                        foreach ($bindAttr as $key => $attr) {
+                            $key = is_numeric($key) ? $attr : $key;
 
-                        if (isset($item[$key])) {
-                            throw new Exception('bind attr has exists:' . $key);
-                        } else {
-                            $item[$key] = $value ? $value->getAttr($attr) : null;
+                            if (isset($item[$key])) {
+                                throw new Exception('bind attr has exists:' . $key);
+                            } else {
+                                $item[$key] = $value ? $value->getAttr($attr) : null;
+                            }
                         }
+                        return false;
                     }
 
-                    return false;
-                }
-
-                // 保存关联对象值
-                $this->relation[$name] = $value;
+                    // 保存关联对象值
+                    $this->relation[$name] = $value;
 
-                return $value;
+                    return $value;
+                }
             }
+            throw new InvalidArgumentException('property not exists:' . static::class . '->' . $name);
         }
-
-        throw new InvalidArgumentException('property not exists:' . static::class . '->' . $name);
+        return $value;
     }
 
     /**
@@ -555,11 +541,7 @@ trait Attribute
                 $value = empty($value) ? new \stdClass() : json_decode($value);
                 break;
             case 'serialize':
-                try {
-                    $value = unserialize($value);
-                } catch (\Exception $e) {
-                    $value = null;
-                }
+                $value = unserialize($value);
                 break;
             default:
                 if (false !== strpos($type, '\\')) {

+ 4 - 4
thinkphp/library/think/model/concern/RelationShip.php

@@ -89,8 +89,9 @@ trait RelationShip
             return $this->relation;
         } elseif (array_key_exists($name, $this->relation)) {
             return $this->relation[$name];
+        } else {
+            return;
         }
-        return;
     }
 
     /**
@@ -141,10 +142,9 @@ trait RelationShip
      * @param  mixed   $operator 比较操作符
      * @param  integer $count    个数
      * @param  string  $id       关联表的统计字段
-     * @param  string  $joinType JOIN类型
      * @return Query
      */
-    public static function has($relation, $operator = '>=', $count = 1, $id = '*', $joinType = 'INNER')
+    public static function has($relation, $operator = '>=', $count = 1, $id = '*')
     {
         $relation = (new static())->$relation();
 
@@ -152,7 +152,7 @@ trait RelationShip
             return $relation->hasWhere($operator);
         }
 
-        return $relation->has($operator, $count, $id, $joinType);
+        return $relation->has($operator, $count, $id);
     }
 
     /**

+ 4 - 3
thinkphp/library/think/model/concern/SoftDelete.php

@@ -52,8 +52,9 @@ trait SoftDelete
             return $model
                 ->db(false)
                 ->useSoftDelete($field, ['not null', '']);
+        } else {
+            return $model->db(false);
         }
-        return $model->db(false);
     }
 
     /**
@@ -153,9 +154,9 @@ trait SoftDelete
                 ->where($where)
                 ->useSoftDelete($name, ['not null', ''])
                 ->update([$name => null]);
+        } else {
+            return 0;
         }
-
-        return 0;
     }
 
     /**

+ 1 - 24
thinkphp/library/think/model/relation/BelongsTo.php

@@ -52,7 +52,6 @@ class BelongsTo extends OneToOne
         $foreignKey = $this->foreignKey;
 
         $relationModel = $this->query
-            ->removeWhereField($this->localKey)
             ->where($this->localKey, $this->parent->$foreignKey)
             ->relation($subRelation)
             ->find();
@@ -70,10 +69,9 @@ class BelongsTo extends OneToOne
      * @param  string  $operator 比较操作符
      * @param  integer $count    个数
      * @param  string  $id       关联表的统计字段
-     * @param  string  $joinType JOIN类型
      * @return Query
      */
-    public function has($operator = '>=', $count = 1, $id = '*', $joinType = 'INNER')
+    public function has($operator = '>=', $count = 1, $id = '*')
     {
         return $this->parent;
     }
@@ -127,8 +125,6 @@ class BelongsTo extends OneToOne
         }
 
         if (!empty($range)) {
-            $this->query->removeWhereField($localKey);
-
             $data = $this->eagerlyWhere([
                 [$localKey, 'in', $range],
             ], $localKey, $relation, $subRelation, $closure);
@@ -172,8 +168,6 @@ class BelongsTo extends OneToOne
         $localKey   = $this->localKey;
         $foreignKey = $this->foreignKey;
 
-        $this->query->removeWhereField($localKey);
-
         $data = $this->eagerlyWhere([
             [$localKey, '=', $result->$foreignKey],
         ], $localKey, $relation, $subRelation, $closure);
@@ -227,21 +221,4 @@ class BelongsTo extends OneToOne
 
         return $this->parent->setRelation($this->relation, null);
     }
-
-    /**
-     * 执行基础查询(仅执行一次)
-     * @access protected
-     * @return void
-     */
-    protected function baseQuery()
-    {
-        if (empty($this->baseQuery)) {
-            if (isset($this->parent->{$this->foreignKey})) {
-                // 关联查询带入关联条件
-                $this->query->where($this->localKey, '=', $this->parent->{$this->foreignKey});
-            }
-
-            $this->baseQuery = true;
-        }
-    }
 }

+ 2 - 28
thinkphp/library/think/model/relation/HasOne.php

@@ -52,7 +52,6 @@ class HasOne extends OneToOne
 
         // 判断关联类型执行查询
         $relationModel = $this->query
-            ->removeWhereField($this->foreignKey)
             ->where($this->foreignKey, $this->parent->$localKey)
             ->relation($subRelation)
             ->find();
@@ -67,13 +66,9 @@ class HasOne extends OneToOne
     /**
      * 根据关联条件查询当前模型
      * @access public
-     * @param  string  $operator 比较操作符
-     * @param  integer $count    个数
-     * @param  string  $id       关联表的统计字段
-     * @param  string  $joinType JOIN类型
      * @return Query
      */
-    public function has($operator = '>=', $count = 1, $id = '*', $joinType = 'INNER')
+    public function has()
     {
         $table      = $this->query->getTable();
         $model      = basename(str_replace('\\', '/', get_class($this->parent)));
@@ -139,8 +134,6 @@ class HasOne extends OneToOne
         }
 
         if (!empty($range)) {
-            $this->query->removeWhereField($foreignKey);
-
             $data = $this->eagerlyWhere([
                 [$foreignKey, 'in', $range],
             ], $foreignKey, $relation, $subRelation, $closure);
@@ -183,10 +176,7 @@ class HasOne extends OneToOne
     {
         $localKey   = $this->localKey;
         $foreignKey = $this->foreignKey;
-
-        $this->query->removeWhereField($foreignKey);
-
-        $data = $this->eagerlyWhere([
+        $data       = $this->eagerlyWhere([
             [$foreignKey, '=', $result->$localKey],
         ], $foreignKey, $relation, $subRelation, $closure);
 
@@ -207,20 +197,4 @@ class HasOne extends OneToOne
         }
     }
 
-    /**
-     * 执行基础查询(仅执行一次)
-     * @access protected
-     * @return void
-     */
-    protected function baseQuery()
-    {
-        if (empty($this->baseQuery)) {
-            if (isset($this->parent->{$this->localKey})) {
-                // 关联查询带入关联条件
-                $this->query->where($this->foreignKey, '=', $this->parent->{$this->localKey});
-            }
-
-            $this->baseQuery = true;
-        }
-    }
 }

+ 1 - 1
thinkphp/library/think/model/relation/MorphMany.php

@@ -244,7 +244,7 @@ class MorphMany extends Relation
     protected function eagerlyMorphToMany($where, $relation, $subRelation = '', $closure = false)
     {
         // 预载入关联查询 支持嵌套预载入
-        $this->query->removeOption('where');
+        $this->query->removeOptions('where');
 
         if ($closure) {
             $closure($this->query);

+ 1 - 1
thinkphp/library/think/process/pipes/Windows.php

@@ -196,7 +196,7 @@ class Windows extends Pipes
             return;
         }
 
-        if (null !== $r && 0 < count($r)) {
+        if (null !== $w && 0 < count($r)) {
             $data = '';
             while ($dataread = fread($r['input'], self::CHUNK_SIZE)) {
                 $data .= $dataread;

+ 1 - 0
thinkphp/library/think/response/View.php

@@ -64,6 +64,7 @@ class View extends Response
     {
         if (is_array($name)) {
             $this->vars = array_merge($this->vars, $name);
+            return $this;
         } else {
             $this->vars[$name] = $value;
         }

+ 0 - 9
thinkphp/library/think/response/Xml.php

@@ -41,15 +41,6 @@ class Xml extends Response
      */
     protected function output($data)
     {
-        if (is_string($data)) {
-            if (0 !== strpos($data, '<?xml')) {
-                $encoding = $this->options['encoding'];
-                $xml      = "<?xml version=\"1.0\" encoding=\"{$encoding}\"?>";
-                $data     = $xml . $data;
-            }
-            return $data;
-        }
-
         // XML数据转换
         return $this->xmlEncode($data, $this->options['root_node'], $this->options['item_node'], $this->options['root_attr'], $this->options['item_key'], $this->options['encoding']);
     }

+ 0 - 126
thinkphp/library/think/route/AliasRule.php

@@ -1,126 +0,0 @@
-<?php
-// +----------------------------------------------------------------------
-// | ThinkPHP [ WE CAN DO IT JUST THINK ]
-// +----------------------------------------------------------------------
-// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
-// +----------------------------------------------------------------------
-// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
-// +----------------------------------------------------------------------
-// | Author: liu21st <liu21st@gmail.com>
-// +----------------------------------------------------------------------
-
-namespace think\route;
-
-use think\Route;
-
-class AliasRule extends Domain
-{
-    protected $route;
-
-    /**
-     * 架构函数
-     * @access public
-     * @param  Route             $router 路由实例
-     * @param  RuleGroup         $parent 上级对象
-     * @param  string            $name   路由别名
-     * @param  string            $route  路由绑定
-     * @param  array             $option 路由参数
-     */
-    public function __construct(Route $router, RuleGroup $parent, $name, $route, $option = [])
-    {
-        $this->router = $router;
-        $this->parent = $parent;
-        $this->name   = $name;
-        $this->route  = $route;
-        $this->option = $option;
-    }
-
-    /**
-     * 检测域名路由
-     * @access public
-     * @param  Request      $request  请求对象
-     * @param  string       $url      访问地址
-     * @param  string       $depr     路径分隔符
-     * @param  bool         $completeMatch   路由是否完全匹配
-     * @return Dispatch|false
-     */
-    public function check($request, $url, $depr = '/', $completeMatch = false)
-    {
-        if ($dispatch = $this->checkCrossDomain($request)) {
-            // 允许跨域
-            return $dispatch;
-        }
-
-        // 检查参数有效性
-        if (!$this->checkOption($this->option, $request)) {
-            return false;
-        }
-
-        list($action, $bind) = array_pad(explode('|', $url, 2), 2, '');
-
-        if (isset($this->option['allow']) && !in_array($action, $this->option['allow'])) {
-            // 允许操作
-            return false;
-        } elseif (isset($this->option['except']) && in_array($action, $this->option['except'])) {
-            // 排除操作
-            return false;
-        }
-
-        if (isset($this->option['method'][$action])) {
-            $this->option['method'] = $this->option['method'][$action];
-        }
-
-        // 匹配后执行的行为
-        $this->afterMatchGroup($request);
-
-        if ($this->parent) {
-            // 合并分组参数
-            $this->mergeGroupOptions();
-        }
-
-        $this->parseBindAppendParam($this->route);
-
-        if (0 === strpos($this->route, '\\')) {
-            // 路由到类
-            return $this->bindToClass($bind, substr($this->route, 1));
-        } elseif (0 === strpos($this->route, '@')) {
-            // 路由到控制器类
-            return $this->bindToController($bind, substr($this->route, 1));
-        } else {
-            // 路由到模块/控制器
-            return $this->bindToModule($bind, $this->route);
-        }
-    }
-
-    /**
-     * 设置允许的操作方法
-     * @access public
-     * @param  array      $action  操作方法
-     * @return $this
-     */
-    public function allow($action = [])
-    {
-        return $this->option('allow', $action);
-    }
-
-    /**
-     * 设置排除的操作方法
-     * @access public
-     * @param  array      $action  操作方法
-     * @return $this
-     */
-    public function except($action = [])
-    {
-        return $this->option('except', $action);
-    }
-
-    /**
-     * 获取当前的路由
-     * @access public
-     * @return string
-     */
-    public function getRoute()
-    {
-        return $this->route;
-    }
-}

+ 91 - 55
thinkphp/library/think/route/Domain.php

@@ -13,10 +13,12 @@ namespace think\route;
 
 use think\Container;
 use think\Loader;
+use think\Response;
 use think\Route;
 use think\route\dispatch\Callback as CallbackDispatch;
 use think\route\dispatch\Controller as ControllerDispatch;
 use think\route\dispatch\Module as ModuleDispatch;
+use think\route\dispatch\Response as ResponseDispatch;
 
 class Domain extends RuleGroup
 {
@@ -24,7 +26,7 @@ class Domain extends RuleGroup
      * 架构函数
      * @access public
      * @param  Route       $router   路由对象
-     * @param  string      $name     路由域名
+     * @param  string      $name     分组名称
      * @param  mixed       $rule     域名路由
      * @param  array       $option   路由参数
      * @param  array       $pattern  变量规则
@@ -32,7 +34,7 @@ class Domain extends RuleGroup
     public function __construct(Route $router, $name = '', $rule = null, $option = [], $pattern = [])
     {
         $this->router  = $router;
-        $this->domain  = $name;
+        $this->name    = trim($name, '/');
         $this->option  = $option;
         $this->rule    = $rule;
         $this->pattern = $pattern;
@@ -49,11 +51,30 @@ class Domain extends RuleGroup
      */
     public function check($request, $url, $depr = '/', $completeMatch = false)
     {
-        // 检测别名路由
-        $result = $this->checkRouteAlias($request, $url, $depr);
+        if ($this->rule) {
+            // 延迟解析域名路由
+            if ($this->rule instanceof Response) {
+                return new ResponseDispatch($this->rule);
+            }
 
-        if (false !== $result) {
-            return $result;
+            $group = new RuleGroup($this->router);
+
+            $this->addRule($group);
+
+            $this->router->setGroup($group);
+
+            $this->router->parseGroupRule($this, $this->rule);
+
+            $this->rule = null;
+        }
+
+        // 检测别名路由
+        if ($this->router->getAlias($url) || $this->router->getAlias(strstr($url, '|', true))) {
+            // 检测路由别名
+            $result = $this->checkRouteAlias($request, $url, $depr);
+            if (false !== $result) {
+                return $result;
+            }
         }
 
         // 检测URL绑定
@@ -67,19 +88,6 @@ class Domain extends RuleGroup
     }
 
     /**
-     * 设置路由绑定
-     * @access public
-     * @param  string     $bind 绑定信息
-     * @return $this
-     */
-    public function bind($bind)
-    {
-        $this->router->bind($bind, $this->domain);
-
-        return $this;
-    }
-
-    /**
      * 检测路由别名
      * @access private
      * @param  Request   $request
@@ -89,11 +97,45 @@ class Domain extends RuleGroup
      */
     private function checkRouteAlias($request, $url, $depr)
     {
-        $alias = strpos($url, '|') ? strstr($url, '|', true) : $url;
+        $array = explode('|', $url);
+        $alias = array_shift($array);
+        $item  = $this->router->getAlias($alias);
+
+        if (is_array($item)) {
+            list($rule, $option) = $item;
+            $action              = $array[0];
+
+            if (isset($option['allow']) && !in_array($action, explode(',', $option['allow']))) {
+                // 允许操作
+                return false;
+            } elseif (isset($option['except']) && in_array($action, explode(',', $option['except']))) {
+                // 排除操作
+                return false;
+            }
 
-        $item = $this->router->getAlias($alias);
+            if (isset($option['method'][$action])) {
+                $option['method'] = $option['method'][$action];
+            }
+        } else {
+            $rule = $item;
+        }
 
-        return $item ? $item->check($request, $url, $depr) : false;
+        $bind = implode('|', $array);
+
+        // 参数有效性检查
+        if (isset($option) && !$this->checkOption($option, $request)) {
+            // 路由不匹配
+            return false;
+        } elseif (0 === strpos($rule, '\\')) {
+            // 路由到类
+            return $this->bindToClass($bind, substr($rule, 1), $depr);
+        } elseif (0 === strpos($rule, '@')) {
+            // 路由到控制器类
+            return $this->bindToController($bind, substr($rule, 1), $depr);
+        } else {
+            // 路由到模块/控制器
+            return $this->bindToModule($bind, $rule, $depr);
+        }
     }
 
     /**
@@ -103,53 +145,41 @@ class Domain extends RuleGroup
      * @param  string    $depr URL分隔符
      * @return Dispatch|false
      */
-    private function checkUrlBind($url, $depr = '/')
+    private function checkUrlBind(&$url, $depr = '/')
     {
-        $bind = $this->router->getBind($this->domain);
+        $bind = $this->router->getBind($this->name);
 
         if (!empty($bind)) {
-
-            $this->parseBindAppendParam($bind);
-
             // 记录绑定信息
             Container::get('app')->log('[ BIND ] ' . var_export($bind, true));
 
             // 如果有URL绑定 则进行绑定检测
-            $type = substr($bind, 0, 1);
-            $bind = substr($bind, 1);
-
-            $bindTo = [
-                '\\' => 'bindToClass',
-                '@'  => 'bindToController',
-                ':'  => 'bindToNamespace',
-            ];
-
-            if (isset($bindTo[$type])) {
-                return $this->{$bindTo[$type]}($url, $bind, $depr);
+            if (0 === strpos($bind, '\\')) {
+                // 绑定到类
+                return $this->bindToClass($url, substr($bind, 1), $depr);
+            } elseif (0 === strpos($bind, '@')) {
+                // 绑定到控制器类
+                return $this->bindToController($url, substr($bind, 1), $depr);
+            } elseif (0 === strpos($bind, ':')) {
+                // 绑定到命名空间
+                return $this->bindToNamespace($url, substr($bind, 1), $depr);
             }
         }
 
         return false;
     }
 
-    protected function parseBindAppendParam(&$bind)
-    {
-        if (false !== strpos($bind, '?')) {
-            list($bind, $query) = explode('?', $bind);
-            parse_str($query, $vars);
-            $this->append($vars);
-        }
-    }
-
     /**
      * 绑定到类
-     * @access protected
+     * @access public
      * @param  string    $url URL地址
      * @param  string    $class 类名(带命名空间)
+     * @param  string    $depr URL分隔符
      * @return CallbackDispatch
      */
-    protected function bindToClass($url, $class)
+    public function bindToClass($url, $class, $depr = '/')
     {
+        $url    = str_replace($depr, '|', $url);
         $array  = explode('|', $url, 2);
         $action = !empty($array[0]) ? $array[0] : Container::get('config')->get('default_action');
 
@@ -162,13 +192,15 @@ class Domain extends RuleGroup
 
     /**
      * 绑定到命名空间
-     * @access protected
+     * @access public
      * @param  string    $url URL地址
      * @param  string    $namespace 命名空间
+     * @param  string    $depr URL分隔符
      * @return CallbackDispatch
      */
-    protected function bindToNamespace($url, $namespace)
+    public function bindToNamespace($url, $namespace, $depr = '/')
     {
+        $url    = str_replace($depr, '|', $url);
         $array  = explode('|', $url, 3);
         $class  = !empty($array[0]) ? $array[0] : Container::get('config')->get('default_controller');
         $method = !empty($array[1]) ? $array[1] : Container::get('config')->get('default_action');
@@ -182,13 +214,15 @@ class Domain extends RuleGroup
 
     /**
      * 绑定到控制器类
-     * @access protected
+     * @access public
      * @param  string    $url URL地址
      * @param  string    $controller 控制器名 (支持带模块名 index/user )
+     * @param  string    $depr URL分隔符
      * @return ControllerDispatch
      */
-    protected function bindToController($url, $controller)
+    public function bindToController($url, $controller, $depr = '/')
     {
+        $url    = str_replace($depr, '|', $url);
         $array  = explode('|', $url, 2);
         $action = !empty($array[0]) ? $array[0] : Container::get('config')->get('default_action');
 
@@ -201,13 +235,15 @@ class Domain extends RuleGroup
 
     /**
      * 绑定到模块/控制器
-     * @access protected
+     * @access public
      * @param  string    $url URL地址
      * @param  string    $controller 控制器类名(带命名空间)
+     * @param  string    $depr URL分隔符
      * @return ModuleDispatch
      */
-    protected function bindToModule($url, $controller)
+    public function bindToModule($url, $controller, $depr = '/')
     {
+        $url    = str_replace($depr, '|', $url);
         $array  = explode('|', $url, 2);
         $action = !empty($array[0]) ? $array[0] : Container::get('config')->get('default_action');
 

+ 24 - 22
thinkphp/library/think/route/Resource.php

@@ -26,17 +26,17 @@ class Resource extends RuleGroup
      * 架构函数
      * @access public
      * @param  Route         $router     路由对象
-     * @param  RuleGroup     $parent     上级对象
+     * @param  RuleGroup     $group      路由所属分组对象
      * @param  string        $name       资源名称
      * @param  string        $route      路由地址
      * @param  array         $option     路由参数
      * @param  array         $pattern    变量规则
      * @param  array         $rest       资源定义
      */
-    public function __construct(Route $router, RuleGroup $parent = null, $name = '', $route = '', $option = [], $pattern = [], $rest = [])
+    public function __construct(Route $router, RuleGroup $group = null, $name = '', $route = '', $option = [], $pattern = [], $rest = [])
     {
         $this->router   = $router;
-        $this->parent   = $parent;
+        $this->parent   = $group;
         $this->resource = $name;
         $this->route    = $route;
         $this->name     = strpos($name, '.') ? strstr($name, '.', true) : $name;
@@ -49,28 +49,23 @@ class Resource extends RuleGroup
         $this->pattern = $pattern;
         $this->option  = $option;
         $this->rest    = $rest;
-
-        if ($this->parent) {
-            $this->domain = $this->parent->getDomain();
-            $this->parent->addRuleItem($this);
-        }
     }
 
     /**
-     * 解析资源路由规则
+     * 检测分组路由
      * @access public
-     * @param  mixed        $rule    路由规则
-     * @return void
+     * @param  Request      $request  请求对象
+     * @param  string       $url      访问地址
+     * @param  string       $depr     路径分隔符
+     * @param  bool         $completeMatch   路由是否完全匹配
+     * @return Dispatch
      */
-    public function parseGroupRule($rule)
+    public function check($request, $url, $depr = '/', $completeMatch = false)
     {
-        $origin = $this->router->getGroup();
-        $this->router->setGroup($this);
-
         // 生成资源路由的路由规则
         $this->buildResourceRule($this->resource, $this->option);
 
-        $this->router->setGroup($origin);
+        return parent::check($request, $url, $depr, $completeMatch);
     }
 
     /**
@@ -89,12 +84,17 @@ class Resource extends RuleGroup
             $item  = [];
 
             foreach ($array as $val) {
-                $item[] = $val . '/<' . (isset($option['var'][$val]) ? $option['var'][$val] : $val . '_id') . '>';
+                $item[] = $val . '/:' . (isset($option['var'][$val]) ? $option['var'][$val] : $val . '_id');
             }
 
             $rule = implode('/', $item) . '/' . $last;
         }
 
+        // 注册分组
+        $group = $this->router->getGroup();
+
+        $this->router->setGroup($this);
+
         // 注册资源路由
         foreach ($this->rest as $key => $val) {
             if ((isset($option['only']) && !in_array($key, $option['only']))
@@ -102,16 +102,18 @@ class Resource extends RuleGroup
                 continue;
             }
 
-            if (isset($last) && strpos($val[1], '<id>') && isset($option['var'][$last])) {
-                $val[1] = str_replace('<id>', '<' . $option['var'][$last] . '>', $val[1]);
-            } elseif (strpos($val[1], '<id>') && isset($option['var'][$rule])) {
-                $val[1] = str_replace('<id>', '<' . $option['var'][$rule] . '>', $val[1]);
+            if (isset($last) && strpos($val[1], ':id') && isset($option['var'][$last])) {
+                $val[1] = str_replace(':id', ':' . $option['var'][$last], $val[1]);
+            } elseif (strpos($val[1], ':id') && isset($option['var'][$rule])) {
+                $val[1] = str_replace(':id', ':' . $option['var'][$rule], $val[1]);
             }
 
             $option['rest'] = $key;
 
-            $this->addRule(trim($val[1], '/'), $this->route . '/' . $val[2], $val[0], $option);
+            $this->router->rule(trim($val[1], '/'), $this->route . '/' . $val[2], $val[0], $option);
         }
+
+        $this->router->setGroup($group);
     }
 
     /**

+ 78 - 248
thinkphp/library/think/route/Rule.php

@@ -34,7 +34,7 @@ abstract class Rule
     // 路由变量规则
     protected $pattern = [];
     // 需要合并的路由参数
-    protected $mergeOptions = ['after', 'before', 'model', 'header', 'response', 'append', 'middleware'];
+    protected $mergeOptions = ['after', 'before', 'model'];
 
     abstract public function check($request, $url, $depr = '/');
 
@@ -75,14 +75,14 @@ abstract class Rule
     }
 
     /**
-     * 设置标识
+     * 设置Name
      * @access public
-     * @param  string  $name 标识
+     * @param  string|array  $name 变量
      * @return $this
      */
     public function name($name)
     {
-        $this->name = $name;
+        $this->name = '/' != $name ? ltrim($name, '/') : '/';
 
         return $this;
     }
@@ -128,6 +128,23 @@ abstract class Rule
     }
 
     /**
+     * 附加路由隐式参数
+     * @access public
+     * @param  array     $append
+     * @return $this
+     */
+    public function append(array $append = [])
+    {
+        if (isset($this->option['append'])) {
+            $this->option['append'] = array_merge($this->option['append'], $append);
+        } else {
+            $this->option['append'] = $append;
+        }
+
+        return $this;
+    }
+
+    /**
      * 设置路由请求类型
      * @access public
      * @param  string     $method
@@ -203,9 +220,7 @@ abstract class Rule
      */
     public function model($var, $model = null, $exception = true)
     {
-        if ($var instanceof \Closure) {
-            $this->option['model'][] = $var;
-        } elseif (is_array($var)) {
+        if (is_array($var)) {
             $this->option['model'] = $var;
         } elseif (is_null($model)) {
             $this->option['model']['id'] = [$var, true];
@@ -217,23 +232,6 @@ abstract class Rule
     }
 
     /**
-     * 附加路由隐式参数
-     * @access public
-     * @param  array     $append
-     * @return $this
-     */
-    public function append(array $append = [])
-    {
-        if (isset($this->option['append'])) {
-            $this->option['append'] = array_merge($this->option['append'], $append);
-        } else {
-            $this->option['append'] = $append;
-        }
-
-        return $this;
-    }
-
-    /**
      * 绑定验证
      * @access public
      * @param  mixed    $validate 验证器类
@@ -257,8 +255,7 @@ abstract class Rule
      */
     public function response($response)
     {
-        $this->option['response'][] = $response;
-        return $this;
+        return $this->option('response', $response);
     }
 
     /**
@@ -270,30 +267,14 @@ abstract class Rule
      */
     public function header($header, $value = null)
     {
-        if (is_array($header)) {
-            $this->option['header'] = $header;
-        } else {
-            $this->option['header'][$header] = $value;
+        if (empty($this->option['header'])) {
+            $this->option['header'] = [];
         }
 
-        return $this;
-    }
-
-    /**
-     * 指定路由中间件
-     * @access public
-     * @param  string|array|\Closure    $middleware
-     * @param  mixed                    $param
-     * @return $this
-     */
-    public function middleware($middleware, $param = null)
-    {
-        if (is_null($param) && is_array($middleware)) {
-            $this->option['middleware'] = $middleware;
+        if (is_array($header)) {
+            $this->option['header'] = array_merge($this->option['header'], $header);
         } else {
-            foreach ((array) $middleware as $item) {
-                $this->option['middleware'][] = [$item, $param];
-            }
+            $this->option['header'][$header] = $value;
         }
 
         return $this;
@@ -435,7 +416,7 @@ abstract class Rule
         }
 
         if ($allow && $this->parent) {
-            $this->parent->addRuleItem($this, 'options');
+            $this->parent->addRule($this, 'options');
         }
 
         return $this->option('cross_domain', $allow);
@@ -503,8 +484,6 @@ abstract class Rule
         }
 
         $this->option = array_merge($parentOption, $this->option);
-
-        return $this->option;
     }
 
     /**
@@ -595,15 +574,34 @@ abstract class Rule
         // 替换路由地址中的变量
         if (is_string($route) && !empty($matches)) {
             foreach ($matches as $key => $val) {
-                if (false !== strpos($route, '<' . $key . '>')) {
-                    $route = str_replace('<' . $key . '>', $val, $route);
-                } elseif (false !== strpos($route, ':' . $key)) {
+                if (false !== strpos($route, ':' . $key)) {
                     $route = str_replace(':' . $key, $val, $route);
                 }
             }
         }
 
-        $this->afterMatchRule($request, $option, $matches);
+        // 绑定模型数据
+        if (isset($option['model'])) {
+            $this->createBindModel($option['model'], $matches);
+        }
+
+        // 指定Header数据
+        if (!empty($option['header'])) {
+            $header = $option['header'];
+            Container::get('hook')->add('response_send', function ($response) use ($header) {
+                $response->header($header);
+            });
+        }
+
+        // 指定Response响应数据
+        if (!empty($option['response'])) {
+            Container::get('hook')->add('response_send', $option['response']);
+        }
+
+        // 开启请求缓存
+        if (isset($option['cache']) && $request->isGet()) {
+            $this->parseRequestCache($request, $option['cache']);
+        }
 
         // 解析额外参数
         $count = substr_count($rule, '/');
@@ -631,43 +629,6 @@ abstract class Rule
         return $this->dispatch($request, $route, $option);
     }
 
-    protected function afterMatchRule($request, $option = [], $matches = [])
-    {
-        // 添加中间件
-        if (!empty($option['middleware'])) {
-            foreach ($option['middleware'] as $middleware) {
-                Container::get('middleware')->add($middleware);
-            }
-        }
-
-        // 绑定模型数据
-        if (!empty($option['model'])) {
-            $this->createBindModel($option['model'], $matches);
-        }
-
-        // 指定Header数据
-        if (!empty($option['header'])) {
-            $header = $option['header'];
-            Container::get('hook')->add('response_send', function ($response) use ($header) {
-                $response->header($header);
-            });
-        }
-
-        // 指定Response响应数据
-        if (!empty($option['response'])) {
-            Container::get('hook')->add('response_send', $option['response']);
-        }
-
-        // 开启请求缓存
-        if (isset($option['cache']) && $request->isGet()) {
-            $this->parseRequestCache($request, $option['cache']);
-        }
-
-        if (!empty($option['append'])) {
-            $request->route($option['append']);
-        }
-    }
-
     /**
      * 验证数据
      * @access protected
@@ -733,8 +694,6 @@ abstract class Rule
      */
     protected function checkAfter($after)
     {
-        Container::get('log')->notice('路由后置行为建议使用中间件替代!');
-
         $hook = Container::get('hook');
 
         $result = null;
@@ -752,9 +711,9 @@ abstract class Rule
             return new ResponseDispatch($result);
         } elseif ($result instanceof Dispatch) {
             return $result;
+        } else {
+            return false;
         }
-
-        return false;
     }
 
     /**
@@ -779,13 +738,24 @@ abstract class Rule
             $result = new RedirectDispatch($route, [], isset($option['status']) ? $option['status'] : 301);
         } elseif (false !== strpos($route, '\\')) {
             // 路由到方法
-            $result = $this->dispatchMethod($route);
+            list($path, $var) = $this->parseUrlPath($route);
+            $route            = str_replace('/', '@', implode('/', $path));
+            $method           = strpos($route, '@') ? explode('@', $route) : $route;
+            $result           = new CallbackDispatch($method, $var);
         } elseif (0 === strpos($route, '@')) {
             // 路由到控制器
-            $result = $this->dispatchController($request, substr($route, 1));
+            $route             = substr($route, 1);
+            list($route, $var) = $this->parseUrlPath($route);
+            $result            = new ControllerDispatch(implode('/', $route), $var);
+
+            $request->action(array_pop($route));
+            $app = Container::get('app');
+            $request->controller($route ? array_pop($route) : $app->config('default_controller'));
+            $request->module($route ? array_pop($route) : $app->config('default_module'));
+            $app->setModulePath($app->getAppPath() . ($app->config('app_multi_module') ? $request->module() . DIRECTORY_SEPARATOR : ''));
         } else {
             // 路由到模块/控制器/操作
-            $result = $this->dispatchModule($request, $route);
+            $result = $this->parseModule($route);
         }
 
         return $result;
@@ -794,57 +764,18 @@ abstract class Rule
     /**
      * 解析URL地址为 模块/控制器/操作
      * @access protected
-     * @param  string    $route 路由地址
-     * @return CallbackDispatch
-     */
-    protected function dispatchMethod($route)
-    {
-        list($path, $var) = $this->parseUrlPath($route);
-
-        $route  = str_replace('/', '@', implode('/', $path));
-        $method = strpos($route, '@') ? explode('@', $route) : $route;
-
-        return new CallbackDispatch($method, $var);
-    }
-
-    /**
-     * 解析URL地址为 模块/控制器/操作
-     * @access protected
-     * @param  Request   $request Request对象
-     * @param  string    $route 路由地址
-     * @return ControllerDispatch
-     */
-    protected function dispatchController($request, $route)
-    {
-        list($route, $var) = $this->parseUrlPath($route);
-
-        $result = new ControllerDispatch(implode('/', $route), $var);
-
-        $request->action(array_pop($route));
-        $app = Container::get('app');
-        $request->controller($route ? array_pop($route) : $app->config('default_controller'));
-        $request->module($route ? array_pop($route) : $app->config('default_module'));
-        $app->setModulePath($app->getAppPath() . ($app->config('app_multi_module') ? $request->module() . DIRECTORY_SEPARATOR : ''));
-
-        return $result;
-    }
-
-    /**
-     * 解析URL地址为 模块/控制器/操作
-     * @access protected
-     * @param  Request   $request Request对象
-     * @param  string    $route 路由地址
-     * @return ModuleDispatch
+     * @param  string    $url URL地址
+     * @return array
      */
-    protected function dispatchModule($request, $route)
+    protected function parseModule($url)
     {
-        list($path, $var) = $this->parseUrlPath($route);
-
-        $config     = Container::get('config');
-        $action     = array_pop($path);
-        $controller = !empty($path) ? array_pop($path) : null;
-        $module     = $config->get('app_multi_module') && !empty($path) ? array_pop($path) : null;
-        $method     = $request->method();
+        list($path, $var) = $this->parseUrlPath($url);
+        $config           = Container::get('config');
+        $request          = Container::get('request');
+        $action           = array_pop($path);
+        $controller       = !empty($path) ? array_pop($path) : null;
+        $module           = $config->get('app_multi_module') && !empty($path) ? array_pop($path) : null;
+        $method           = $request->method();
 
         if ($config->get('use_action_prefix') && $this->router->getMethodPrefix($method)) {
             $prefix = $this->router->getMethodPrefix($method);
@@ -960,107 +891,6 @@ abstract class Rule
     }
 
     /**
-     * 生成路由的正则规则
-     * @access protected
-     * @param  string    $rule 路由规则
-     * @param  array     $match 匹配的变量
-     * @param  array     $pattern   路由变量规则
-     * @param  array     $option    路由参数
-     * @param  bool      $completeMatch   路由是否完全匹配
-     * @param  string    $suffix   路由正则变量后缀
-     * @return string
-     */
-    protected function buildRuleRegex($rule, $match, $pattern = [], $option = [], $completeMatch = false, $suffix = '')
-    {
-        foreach ($match as $name) {
-            $replace[] = $this->buildNameRegex($name, $pattern, $suffix);
-        }
-
-        // 是否区分 / 地址访问
-        if (!empty($option['remove_slash']) && '/' != $rule) {
-            $rule = rtrim($rule, '/');
-        }
-
-        $regex = str_replace($match, $replace, $rule);
-        $regex = str_replace([')?/', ')/', ')?-', ')-', '\\\\/'], [')\/', ')\/', ')\-', ')\-', '\/'], $regex);
-
-        return $regex . ($completeMatch ? '$' : '');
-    }
-
-    /**
-     * 生成路由变量的正则规则
-     * @access protected
-     * @param  string    $name      路由变量
-     * @param  string    $pattern   变量规则
-     * @param  string    $suffix    路由正则变量后缀
-     * @return string
-     */
-    protected function buildNameRegex($name, $pattern, $suffix)
-    {
-        $optional = '';
-        $slash    = substr($name, 0, 1);
-
-        if (in_array($slash, ['/', '-'])) {
-            $prefix = '\\' . $slash;
-            $name   = substr($name, 1);
-            $slash  = substr($name, 0, 1);
-        } else {
-            $prefix = '';
-        }
-
-        if ('<' != $slash) {
-            return $prefix . preg_quote($name, '/');
-        }
-
-        if (strpos($name, '?')) {
-            $name     = substr($name, 1, -2);
-            $optional = '?';
-        } elseif (strpos($name, '>')) {
-            $name = substr($name, 1, -1);
-        }
-
-        if (isset($pattern[$name])) {
-            $nameRule = $pattern[$name];
-            if (0 === strpos($nameRule, '/') && '/' == substr($nameRule, -1)) {
-                $nameRule = substr($nameRule, 1, -1);
-            }
-        } else {
-            $nameRule = '\w+';
-        }
-
-        return '(' . $prefix . '(?<' . $name . $suffix . '>' . $nameRule . '))' . $optional;
-    }
-
-    /**
-     * 分析路由规则中的变量
-     * @access protected
-     * @param  string    $rule 路由规则
-     * @return array
-     */
-    protected function parseVar($rule)
-    {
-        // 提取路由规则中的变量
-        $var = [];
-
-        if (preg_match_all('/<\w+\??>/', $rule, $matches)) {
-            foreach ($matches[0] as $name) {
-                $optional = false;
-
-                if (strpos($name, '?')) {
-                    $name     = substr($name, 1, -2);
-                    $optional = true;
-                } else {
-                    $name = substr($name, 1, -1);
-                }
-
-                $var[$name] = $optional ? 2 : 1;
-            }
-        }
-
-        return $var;
-    }
-
-    /**
      * 设置路由参数
      * @access public
      * @param  string    $method     方法名

+ 79 - 309
thinkphp/library/think/route/RuleGroup.php

@@ -12,7 +12,6 @@
 namespace think\route;
 
 use think\Container;
-use think\Exception;
 use think\Request;
 use think\Response;
 use think\Route;
@@ -44,51 +43,35 @@ class RuleGroup extends Rule
     // 完整名称
     protected $fullName;
 
-    // 所在域名
-    protected $domain;
-
     /**
      * 架构函数
      * @access public
      * @param  Route       $router   路由对象
-     * @param  RuleGroup   $parent   上级对象
+     * @param  RuleGroup   $group    路由所属分组对象
      * @param  string      $name     分组名称
      * @param  mixed       $rule     分组路由
      * @param  array       $option   路由参数
      * @param  array       $pattern  变量规则
      */
-    public function __construct(Route $router, RuleGroup $parent = null, $name = '', $rule = [], $option = [], $pattern = [])
+    public function __construct(Route $router, RuleGroup $group = null, $name = '', $rule = [], $option = [], $pattern = [])
     {
         $this->router  = $router;
-        $this->parent  = $parent;
+        $this->parent  = $group;
         $this->rule    = $rule;
         $this->name    = trim($name, '/');
         $this->option  = $option;
         $this->pattern = $pattern;
 
         $this->setFullName();
-
-        if ($this->parent) {
-            $this->domain = $this->parent->getDomain();
-            $this->parent->addRuleItem($this);
-        }
-
-        if (!empty($option['cross_domain'])) {
-            $this->router->setCrossDomainRule($this);
-        }
     }
 
     /**
      * 设置分组的路由规则
      * @access public
-     * @return void
+     * @return $this
      */
     protected function setFullName()
     {
-        if (false !== strpos($this->name, ':')) {
-            $this->name = preg_replace(['/\[\:(\w+)\]/', '/\:(\w+)/'], ['<\1?>', '<\1>'], $this->name);
-        }
-
         if ($this->parent && $this->parent->getFullName()) {
             $this->fullName = $this->parent->getFullName() . ($this->name ? '/' . $this->name : '');
         } else {
@@ -97,13 +80,15 @@ class RuleGroup extends Rule
     }
 
     /**
-     * 获取所属域名
+     * 设置分组的路由规则
      * @access public
-     * @return string
+     * @param  mixed      $rule     路由规则
+     * @return $this
      */
-    public function getDomain()
+    public function setRule($rule)
     {
-        return $this->domain;
+        $this->rule = $rule;
+        return $this;
     }
 
     /**
@@ -118,53 +103,87 @@ class RuleGroup extends Rule
     public function check($request, $url, $depr = '/', $completeMatch = false)
     {
         if ($dispatch = $this->checkCrossDomain($request)) {
-            // 跨域OPTIONS请求
+            // 允许跨域
             return $dispatch;
         }
 
-        // 检查分组有效性
-        if (!$this->checkOption($this->option, $request) || !$this->checkUrl($url)) {
+        // 检查参数有效性
+        if (!$this->checkOption($this->option, $request)) {
             return false;
         }
 
-        // 解析分组路由
+        if ($this->fullName) {
+            // 分组URL匹配检查
+            $pos = strpos(str_replace('<', ':', $this->fullName), ':');
+
+            if (false !== $pos) {
+                $str = substr($this->fullName, 0, $pos);
+            } else {
+                $str = $this->fullName;
+            }
+
+            if (0 !== stripos(str_replace('|', '/', $url), $str)) {
+                return false;
+            }
+        }
+
         if ($this->rule) {
+            // 延迟解析分组路由
             if ($this->rule instanceof Response) {
                 return new ResponseDispatch($this->rule);
             }
 
-            $this->parseGroupRule($this->rule);
+            $group = $this->router->getGroup();
+
+            $this->router->setGroup($this);
+
+            $this->router->parseGroupRule($this, $this->rule);
+
+            $this->router->setGroup($group);
+
+            $this->rule = null;
         }
 
-        // 获取当前路由规则
-        $method = strtolower($request->method());
-        $rules  = $this->getMethodRules($method);
+        // 分组匹配后执行的行为
 
-        if (count($rules) == 0) {
-            return false;
+        // 指定Response响应数据
+        if (!empty($this->option['response'])) {
+            Container::get('hook')->add('response_send', $this->option['response']);
         }
 
+        // 开启请求缓存
+        if (isset($this->option['cache']) && $request->isGet()) {
+            $this->parseRequestCache($request, $this->option['cache']);
+        }
+
+        // 获取当前路由规则
+        $method = strtolower($request->method());
+        $rules  = array_merge($this->rules['*'], $this->rules[$method]);
+
         if ($this->parent) {
             // 合并分组参数
             $this->mergeGroupOptions();
-            // 合并分组变量规则
-            $this->pattern = array_merge($this->parent->getPattern(), $this->pattern);
         }
 
         if (isset($this->option['complete_match'])) {
             $completeMatch = $this->option['complete_match'];
         }
 
-        if (!empty($this->option['merge_rule_regex'])) {
-            // 合并路由正则规则进行路由匹配检查
-            $result = $this->checkMergeRuleRegex($request, $rules, $url, $depr, $completeMatch);
+        if (!empty($this->option['append'])) {
+            $request->route($this->option['append']);
+        }
+
+        if (isset($rules[$url])) {
+            // 快速定位
+            $item   = $rules[$url];
+            $result = $item->check($request, $url, $depr, $completeMatch);
 
             if (false !== $result) {
                 return $result;
             }
         }
 
-        // 检查分组路由
+        // 遍历分组路由
         foreach ($rules as $key => $item) {
             $result = $item->check($request, $url, $depr, $completeMatch);
 
@@ -173,10 +192,10 @@ class RuleGroup extends Rule
             }
         }
 
-        if ($this->auto) {
+        if (isset($this->auto)) {
             // 自动解析URL地址
-            $result = new UrlDispatch($this->auto . '/' . $url, ['depr' => $depr, 'auto_search' => false]);
-        } elseif ($this->miss && in_array($this->miss->getMethod(), ['*', $method])) {
+            $result = new UrlDispatch($this->auto->getRoute() . '/' . $url, ['depr' => $depr, 'auto_search' => false]);
+        } elseif (isset($this->miss)) {
             // 未匹配所有路由的路由规则处理
             $result = $this->parseRule($request, '', $this->miss->getRoute(), $url, $this->miss->getOption());
         } else {
@@ -187,275 +206,37 @@ class RuleGroup extends Rule
     }
 
     /**
-     * 获取当前请求的路由规则(包括子分组、资源路由)
-     * @access protected
-     * @param  string      $method
-     * @return array
-     */
-    protected function getMethodRules($method)
-    {
-        return array_merge($this->rules['*'], $this->rules[$method]);
-    }
-
-    /**
-     * 分组URL匹配检查
-     * @access protected
-     * @param  string     $url
-     * @return bool
-     */
-    protected function checkUrl($url)
-    {
-        if ($this->fullName) {
-            $pos = strpos($this->fullName, '<');
-
-            if (false !== $pos) {
-                $str = substr($this->fullName, 0, $pos);
-            } else {
-                $str = $this->fullName;
-            }
-
-            if ($str && 0 !== stripos(str_replace('|', '/', $url), $str)) {
-                return false;
-            }
-        }
-
-        return true;
-    }
-
-    /**
-     * 延迟解析分组的路由规则
+     * 设置自动路由
      * @access public
-     * @param  bool     $lazy   路由是否延迟解析
+     * @param  RuleItem     $rule   路由规则
      * @return $this
      */
-    public function lazy($lazy = true)
+    public function setAutoRule(RuleItem $rule)
     {
-        if (!$lazy && !is_object($this->rule)) {
-            $this->parseGroupRule($this->rule);
-            $this->rule = null;
-        }
-
+        $this->auto = $rule;
         return $this;
     }
 
     /**
-     * 解析分组和域名的路由规则及绑定
-     * @access public
-     * @param  mixed        $rule    路由规则
-     * @return void
-     */
-    public function parseGroupRule($rule)
-    {
-        $origin = $this->router->getGroup();
-        $this->router->setGroup($this);
-
-        if ($rule instanceof \Closure) {
-            Container::getInstance()->invokeFunction($rule);
-        } elseif (is_array($rule)) {
-            $this->addRules($rule);
-        } elseif (is_string($rule) && $rule) {
-            $this->router->bind($rule, $this->domain);
-        }
-
-        $this->router->setGroup($origin);
-    }
-
-    /**
-     * 检测分组路由
+     * 设置为MISS路由
      * @access public
-     * @param  Request      $request  请求对象
-     * @param  array        $rules    路由规则
-     * @param  string       $url      访问地址
-     * @param  string       $depr     路径分隔符
-     * @param  bool         $completeMatch   路由是否完全匹配
-     * @return Dispatch|false
-     */
-    protected function checkMergeRuleRegex($request, &$rules, $url, $depr, $completeMatch)
-    {
-        $url = $depr . str_replace('|', $depr, $url);
-
-        foreach ($rules as $key => $item) {
-            if ($item instanceof RuleItem) {
-                $rule = $depr . str_replace('/', $depr, $item->getRule());
-                if ($depr == $rule && $depr != $url) {
-                    unset($rules[$key]);
-                    continue;
-                }
-
-                $complete = null !== $item->getOption('complete_match') ? $item->getOption('complete_match') : $completeMatch;
-
-                if (false === strpos($rule, '<')) {
-                    if (0 === strcasecmp($rule, $url) || (!$complete && 0 === strncasecmp($rule, $url, strlen($rule)))) {
-                        return $item->checkRule($request, $url, []);
-                    }
-
-                    unset($rules[$key]);
-                    continue;
-                }
-
-                $slash = preg_quote('/-' . $depr, '/');
-
-                if ($matchRule = preg_split('/[' . $slash . ']<\w+\??>/', $rule, 2)) {
-                    if ($matchRule[0] && 0 !== strncasecmp($rule, $url, strlen($matchRule[0]))) {
-                        unset($rules[$key]);
-                        continue;
-                    }
-                }
-
-                if (preg_match_all('/[' . $slash . ']?<?\w+\??>?/', $rule, $matches)) {
-                    unset($rules[$key]);
-                    $pattern = array_merge($this->getPattern(), $item->getPattern());
-                    $option  = array_merge($this->getOption(), $item->getOption());
-
-                    $regex[$key] = $this->buildRuleRegex($rule, $matches[0], $pattern, $option, $complete, '_THINK_' . $key);
-                    $items[$key] = $item;
-                }
-            }
-        }
-
-        try {
-            if (!empty($regex) && preg_match('/^(?:' . implode('|', $regex) . ')/', $url, $match)) {
-                $var = [];
-                foreach ($match as $key => $val) {
-                    if (is_string($key) && '' !== $val) {
-                        list($name, $pos) = explode('_THINK_', $key);
-
-                        $var[$name] = $val;
-                    }
-                }
-
-                if (!isset($pos)) {
-                    foreach ($regex as $key => $item) {
-                        if (0 === strpos(str_replace(['\/', '\-', '\\' . $depr], ['/', '-', $depr], $item), $match[0])) {
-                            $pos = $key;
-                            break;
-                        }
-                    }
-                }
-
-                return $items[$pos]->checkRule($request, $url, $var);
-            }
-
-            return false;
-        } catch (\Exception $e) {
-            throw new Exception('route pattern error');
-        }
-    }
-
-    /**
-     * 获取分组的MISS路由
-     * @access public
-     * @return RuleItem|null
-     */
-    public function getMissRule()
-    {
-        return $this->miss;
-    }
-
-    /**
-     * 获取分组的自动路由
-     * @access public
-     * @return string
-     */
-    public function getAutoRule()
-    {
-        return $this->auto;
-    }
-
-    /**
-     * 注册自动路由
-     * @access public
-     * @param  string     $route   路由规则
-     * @return void
-     */
-    public function addAutoRule($route)
-    {
-        $this->auto = $route;
-    }
-
-    /**
-     * 注册MISS路由
-     * @access public
-     * @param  string    $route      路由地址
-     * @param  string    $method     请求类型
-     * @param  array     $option     路由参数
-     * @return RuleItem
+     * @param  RuleItem     $rule   路由规则
+     * @return $this
      */
-    public function addMissRule($route, $method = '*', $option = [])
+    public function setMissRule(RuleItem $rule)
     {
-        // 创建路由规则实例
-        $ruleItem = new RuleItem($this->router, $this, null, '', $route, strtolower($method), $option);
-
-        $this->miss = $ruleItem;
-
-        return $ruleItem;
+        $this->miss = $rule;
+        return $this;
     }
 
     /**
      * 添加分组下的路由规则或者子分组
      * @access public
-     * @param  string    $rule       路由规则
-     * @param  string    $route      路由地址
-     * @param  string    $method     请求类型
-     * @param  array     $option     路由参数
-     * @param  array     $pattern    变量规则
+     * @param  Rule     $rule   路由规则
+     * @param  string   $method 请求类型
      * @return $this
      */
-    public function addRule($rule, $route, $method = '*', $option = [], $pattern = [])
-    {
-        // 读取路由标识
-        if (is_array($rule)) {
-            $name = $rule[0];
-            $rule = $rule[1];
-        } elseif (is_string($route)) {
-            $name = $route;
-        } else {
-            $name = null;
-        }
-
-        $method = strtolower($method);
-
-        // 创建路由规则实例
-        $ruleItem = new RuleItem($this->router, $this, $name, $rule, $route, $method, $option, $pattern);
-
-        if (!empty($option['cross_domain'])) {
-            $this->router->setCrossDomainRule($ruleItem, $method);
-        }
-
-        $this->addRuleItem($ruleItem, $method);
-
-        return $ruleItem;
-    }
-
-    /**
-     * 批量注册路由规则
-     * @access public
-     * @param  array     $rules      路由规则
-     * @param  string    $method     请求类型
-     * @param  array     $option     路由参数
-     * @param  array     $pattern    变量规则
-     * @return void
-     */
-    public function addRules($rules, $method = '*', $option = [], $pattern = [])
-    {
-        foreach ($rules as $key => $val) {
-            if (is_numeric($key)) {
-                $key = array_shift($val);
-            }
-
-            if (is_array($val)) {
-                $route   = array_shift($val);
-                $option  = $val ? array_shift($val) : [];
-                $pattern = $val ? array_shift($val) : [];
-            } else {
-                $route = $val;
-            }
-
-            $this->addRule($key, $route, $method, $option, $pattern);
-        }
-    }
-
-    public function addRuleItem($rule, $method = '*')
+    public function addRule($rule, $method = '*')
     {
         if (strpos($method, '|')) {
             $rule->method($method);
@@ -475,7 +256,7 @@ class RuleGroup extends Rule
      */
     public function prefix($prefix)
     {
-        if ($this->parent && $this->parent->getOption('prefix')) {
+        if ($this->parent->getOption('prefix')) {
             $prefix = $this->parent->getOption('prefix') . $prefix;
         }
 
@@ -483,17 +264,6 @@ class RuleGroup extends Rule
     }
 
     /**
-     * 合并分组的路由规则正则
-     * @access public
-     * @param  bool     $merge
-     * @return $this
-     */
-    public function mergeRuleRegex($merge = true)
-    {
-        return $this->option('merge_rule_regex', $merge);
-    }
-
-    /**
      * 获取完整分组Name
      * @access public
      * @return string
@@ -513,9 +283,9 @@ class RuleGroup extends Rule
     {
         if ('' === $method) {
             return $this->rules;
+        } else {
+            return isset($this->rules[strtolower($method)]) ? $this->rules[strtolower($method)] : [];
         }
-
-        return isset($this->rules[strtolower($method)]) ? $this->rules[strtolower($method)] : [];
     }
 
 }

+ 136 - 154
thinkphp/library/think/route/RuleItem.php

@@ -11,8 +11,6 @@
 
 namespace think\route;
 
-use think\Container;
-use think\Exception;
 use think\Route;
 
 class RuleItem extends Rule
@@ -21,7 +19,7 @@ class RuleItem extends Rule
      * 路由规则
      * @var string
      */
-    protected $rule;
+    protected $name;
 
     /**
      * 路由地址
@@ -39,29 +37,23 @@ class RuleItem extends Rule
      * 架构函数
      * @access public
      * @param  Route             $router 路由实例
-     * @param  RuleGroup         $parent 上级对象
-     * @param  string            $name 路由标识
-     * @param  string|array      $rule 路由规则
+     * @param  RuleGroup         $group 路由所属分组对象
+     * @param  string|array      $name 路由规则
      * @param  string            $method 请求类型
      * @param  string|\Closure   $route 路由地址
      * @param  array             $option 路由参数
      * @param  array             $pattern 变量规则
      */
-    public function __construct(Route $router, RuleGroup $parent, $name, $rule, $route, $method = '*', $option = [], $pattern = [])
+    public function __construct(Route $router, RuleGroup $group, $name, $route, $method = '*', $option = [], $pattern = [])
     {
         $this->router  = $router;
-        $this->parent  = $parent;
-        $this->name    = $name;
+        $this->parent  = $group;
         $this->route   = $route;
         $this->method  = $method;
         $this->option  = $option;
         $this->pattern = $pattern;
 
-        $this->setRule($rule);
-
-        if (!empty($option['cross_domain'])) {
-            $this->router->setCrossDomainRule($this, $method);
-        }
+        $this->setRule($name);
     }
 
     /**
@@ -79,30 +71,7 @@ class RuleItem extends Rule
             $this->option['complete_match'] = true;
         }
 
-        $rule = '/' != $rule ? ltrim($rule, '/') : '';
-
-        if ($this->parent && $prefix = $this->parent->getFullName()) {
-            $rule = $prefix . ($rule ? '/' . ltrim($rule, '/') : '');
-        }
-
-        if (false !== strpos($rule, ':')) {
-            $this->rule = preg_replace(['/\[\:(\w+)\]/', '/\:(\w+)/'], ['<\1?>', '<\1>'], $rule);
-        } else {
-            $this->rule = $rule;
-        }
-
-        // 生成路由标识的快捷访问
-        $this->setRuleName();
-    }
-
-    /**
-     * 获取当前路由规则
-     * @access public
-     * @return string
-     */
-    public function getRule()
-    {
-        return $this->rule;
+        $this->name($rule);
     }
 
     /**
@@ -116,67 +85,42 @@ class RuleItem extends Rule
     }
 
     /**
-     * 获取当前路由的请求类型
+     * 设置为自动路由
      * @access public
-     * @return string
+     * @return $this
      */
-    public function getMethod()
+    public function isAuto()
     {
-        return strtolower($this->method);
+        $this->parent->setAutoRule($this);
+        return $this;
     }
 
     /**
-     * 检查后缀
+     * 设置为MISS路由
      * @access public
-     * @param  string     $ext
      * @return $this
      */
-    public function ext($ext = '')
+    public function isMiss()
     {
-        $this->option('ext', $ext);
-        $this->setRuleName(true);
-
+        $this->parent->setMissRule($this);
         return $this;
     }
 
     /**
-     * 设置路由标识 用于URL反解生成
-     * @access protected
-     * @param  bool     $first   是否插入开头
-     * @return void
-     */
-    protected function setRuleName($first = false)
-    {
-        if ($this->name) {
-            $vars = $this->parseVar($this->rule);
-            $name = strtolower($this->name);
-
-            if (isset($this->option['ext'])) {
-                $suffix = $this->option['ext'];
-            } elseif ($this->parent->getOption('ext')) {
-                $suffix = $this->parent->getOption('ext');
-            } else {
-                $suffix = null;
-            }
-
-            $value = [$this->rule, $vars, $this->parent->getDomain(), $suffix];
-
-            Container::get('rule_name')->set($name, $value, $first);
-        }
-    }
-
-    /**
      * 检测路由
      * @access public
      * @param  Request      $request  请求对象
      * @param  string       $url      访问地址
-     * @param  array        $match    匹配路由变量
      * @param  string       $depr     路径分隔符
      * @param  bool         $completeMatch   路由是否完全匹配
-     * @return Dispatch|false
+     * @return Dispatch
      */
-    public function checkRule($request, $url, $match = null, $depr = '/', $completeMatch = false)
+    public function check($request, $url, $depr = '/', $completeMatch = false)
     {
+        if ($this->parent && $prefix = $this->parent->getFullName()) {
+            $this->name = $prefix . ($this->name ? '/' . ltrim($this->name, '/') : '');
+        }
+
         if ($dispatch = $this->checkCrossDomain($request)) {
             // 允许跨域
             return $dispatch;
@@ -188,124 +132,162 @@ class RuleItem extends Rule
         }
 
         // 合并分组参数
-        $option = $this->mergeGroupOptions();
+        $this->mergeGroupOptions();
+        $option = $this->option;
 
-        // 检查前置行为
-        if (isset($option['before']) && false === $this->checkBefore($option['before'])) {
-            return false;
-        }
-
-        $url = $this->urlSuffixCheck($request, $url, $option);
-
-        if (is_null($match)) {
-            $match = $this->match($url, $option, $depr, $completeMatch);
+        if (!empty($option['append'])) {
+            $request->route($option['append']);
         }
 
-        if (false !== $match) {
-            return $this->parseRule($request, $this->rule, $this->route, $url, $option, $match);
-        }
-
-        return false;
-    }
-
-    /**
-     * 检测路由(含路由匹配)
-     * @access public
-     * @param  Request      $request  请求对象
-     * @param  string       $url      访问地址
-     * @param  string       $depr     路径分隔符
-     * @param  bool         $completeMatch   路由是否完全匹配
-     * @return Dispatch|false
-     */
-    public function check($request, $url, $depr = '/', $completeMatch = false)
-    {
-        return $this->checkRule($request, $url, null, $depr, $completeMatch);
-    }
-
-    /**
-     * URL后缀及Slash检查
-     * @access protected
-     * @param  Request      $request  请求对象
-     * @param  string       $url      访问地址
-     * @param  array        $option   路由参数
-     * @return string
-     */
-    protected function urlSuffixCheck($request, $url, $option = [])
-    {
         // 是否区分 / 地址访问
-        if (!empty($option['remove_slash']) && '/' != $this->rule) {
-            $this->rule = rtrim($this->rule, '/');
+        if (!empty($option['remove_slash']) && '/' != $this->name) {
+            $this->name = rtrim($this->name, '/');
             $url        = rtrim($url, '|');
         }
 
+        // 检查前置行为
+        if (isset($option['before']) && false === $this->checkBefore($option['before'])) {
+            return false;
+        }
+
         if (isset($option['ext'])) {
             // 路由ext参数 优先于系统配置的URL伪静态后缀参数
             $url = preg_replace('/\.(' . $request->ext() . ')$/i', '', $url);
         }
 
-        return $url;
+        return $this->checkRule($request, $url, $depr, $completeMatch, $option);
     }
 
     /**
-     * 检测URL和规则路由是否匹配
+     * 检测路由规则
      * @access private
+     * @param  Request   $request 请求对象
      * @param  string    $url URL地址
-     * @param  array     $option    路由参数
      * @param  string    $depr URL分隔符(全局)
      * @param  bool      $completeMatch   路由是否完全匹配
+     * @param  array     $option   路由参数
      * @return array|false
      */
-    private function match($url, $option, $depr, $completeMatch)
+    private function checkRule($request, $url, $depr, $completeMatch = false, $option = [])
     {
-        if (isset($option['complete_match'])) {
-            $completeMatch = $option['complete_match'];
-        }
-
-        $pattern = array_merge($this->parent->getPattern(), $this->pattern);
-
         // 检查完整规则定义
-        if (isset($pattern['__url__']) && !preg_match(0 === strpos($pattern['__url__'], '/') ? $pattern['__url__'] : '/^' . $pattern['__url__'] . '/', str_replace('|', $depr, $url))) {
+        if (isset($this->pattern['__url__']) && !preg_match(0 === strpos($this->pattern['__url__'], '/') ? $this->pattern['__url__'] : '/^' . $this->pattern['__url__'] . '/', str_replace('|', $depr, $url))) {
             return false;
         }
 
-        $var  = [];
-        $url  = $depr . str_replace('|', $depr, $url);
-        $rule = $depr . str_replace('/', $depr, $this->rule);
-
-        if ($depr == $rule && $depr != $url) {
-            return false;
+        // 检查路由的参数分隔符
+        if (isset($option['param_depr'])) {
+            $url = str_replace(['|', $option['param_depr']], [$depr, '|'], $url);
         }
 
-        if (false === strpos($rule, '<')) {
-            if (0 === strcasecmp($rule, $url) || (!$completeMatch && 0 === strncasecmp($rule, $url, strlen($rule)))) {
-                return $var;
-            }
-            return false;
+        $len1 = substr_count($url, '|');
+        $len2 = substr_count($this->name, '/');
+
+        // 多余参数是否合并
+        $merge = !empty($option['merge_extra_vars']) ? true : false;
+
+        if ($merge && $len1 > $len2) {
+            $url = str_replace('|', $depr, $url);
+            $url = implode('|', explode($depr, $url, $len2 + 1));
         }
 
-        $slash = preg_quote('/-' . $depr, '/');
+        if (isset($option['complete_match'])) {
+            $completeMatch = $option['complete_match'];
+        }
 
-        if ($matchRule = preg_split('/[' . $slash . ']?<\w+\??>/', $rule, 2)) {
-            if ($matchRule[0] && 0 !== strncasecmp($rule, $url, strlen($matchRule[0]))) {
+        if ($len1 >= $len2 || strpos($this->name, '[')) {
+            // 完整匹配
+            if ($completeMatch && (!$merge && $len1 != $len2 && (false === strpos($this->name, '[') || $len1 > $len2 || $len1 < $len2 - substr_count($this->name, '[')))) {
                 return false;
             }
+
+            $pattern = array_merge($this->parent->getPattern(), $this->pattern);
+
+            if (false !== $match = $this->match($url, $pattern)) {
+                // 匹配到路由规则
+                return $this->parseRule($request, $this->name, $this->route, $url, $option, $match);
+            }
         }
 
-        if (preg_match_all('/[' . $slash . ']?<?\w+\??>?/', $rule, $matches)) {
-            $regex = $this->buildRuleRegex($rule, $matches[0], $pattern, $option, $completeMatch);
+        return false;
+    }
 
-            try {
-                if (!preg_match('/^' . $regex . ($completeMatch ? '$' : '') . '/', $url, $match)) {
+    /**
+     * 检测URL和规则路由是否匹配
+     * @access private
+     * @param  string    $url URL地址
+     * @param  array     $pattern 变量规则
+     * @return array|false
+     */
+    private function match($url, $pattern)
+    {
+        $m2 = explode('/', $this->name);
+        $m1 = explode('|', $url);
+
+        $var = [];
+
+        foreach ($m2 as $key => $val) {
+            // val中定义了多个变量 <id><name>
+            if (false !== strpos($val, '<') && preg_match_all('/<(\w+(\??))>/', $val, $matches)) {
+                $value   = [];
+                $replace = [];
+
+                foreach ($matches[1] as $name) {
+                    if (strpos($name, '?')) {
+                        $name      = substr($name, 0, -1);
+                        $replace[] = '(' . (isset($pattern[$name]) ? $pattern[$name] : '\w+') . ')?';
+                    } else {
+                        $replace[] = '(' . (isset($pattern[$name]) ? $pattern[$name] : '\w+') . ')';
+                    }
+                    $value[] = $name;
+                }
+
+                $val = str_replace($matches[0], $replace, $val);
+
+                if (preg_match('/^' . $val . '$/', isset($m1[$key]) ? $m1[$key] : '', $match)) {
+                    array_shift($match);
+                    foreach ($value as $k => $name) {
+                        if (isset($match[$k])) {
+                            $var[$name] = $match[$k];
+                        }
+                    }
+                    continue;
+                } else {
                     return false;
                 }
-            } catch (\Exception $e) {
-                throw new Exception('route pattern error');
             }
 
-            foreach ($match as $key => $val) {
-                if (is_string($key)) {
-                    $var[$key] = $val;
+            if (0 === strpos($val, '[:')) {
+                // 可选参数
+                $val      = substr($val, 1, -1);
+                $optional = true;
+            } else {
+                $optional = false;
+            }
+
+            if (0 === strpos($val, ':')) {
+                // URL变量
+                $name = substr($val, 1);
+
+                if (!$optional && !isset($m1[$key])) {
+                    return false;
+                }
+
+                if (isset($m1[$key]) && isset($pattern[$name])) {
+                    // 检查变量规则
+                    if ($pattern[$name] instanceof \Closure) {
+                        $result = call_user_func_array($pattern[$name], [$m1[$key]]);
+                        if (false === $result) {
+                            return false;
+                        }
+                    } elseif (!preg_match(0 === strpos($pattern[$name], '/') ? $pattern[$name] : '/^' . $pattern[$name] . '$/', $m1[$key])) {
+                        return false;
+                    }
                 }
+
+                $var[$name] = isset($m1[$key]) ? $m1[$key] : '';
+            } elseif (!isset($m1[$key]) || 0 !== strcasecmp($val, $m1[$key])) {
+                return false;
             }
         }
 

+ 0 - 63
thinkphp/library/think/route/RuleName.php

@@ -1,63 +0,0 @@
-<?php
-// +----------------------------------------------------------------------
-// | ThinkPHP [ WE CAN DO IT JUST THINK ]
-// +----------------------------------------------------------------------
-// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
-// +----------------------------------------------------------------------
-// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
-// +----------------------------------------------------------------------
-// | Author: liu21st <liu21st@gmail.com>
-// +----------------------------------------------------------------------
-
-namespace think\route;
-
-class RuleName
-{
-    protected $item = [];
-
-    /**
-     * 注册路由标识
-     * @access public
-     * @param  string   $name      路由标识
-     * @param  array    $value     路由规则
-     * @param  bool     $first     是否置顶
-     * @return void
-     */
-    public function set($name, $value, $first = false)
-    {
-        if ($first) {
-            array_unshift($this->item[$name], $value);
-        } else {
-            $this->item[$name][] = $value;
-        }
-    }
-
-    /**
-     * 导入路由标识
-     * @access public
-     * @param  array   $name      路由标识
-     * @return void
-     */
-    public function import($item)
-    {
-        $this->item = $item;
-    }
-
-    /**
-     * 根据路由标识获取路由信息(用于URL生成)
-     * @access public
-     * @param  string   $name      路由标识
-     * @return array|null
-     */
-    public function get($name = null)
-    {
-        if (is_null($name)) {
-            return $this->item;
-        }
-
-        $name = strtolower($name);
-
-        return isset($this->item[$name]) ? $this->item[$name] : null;
-    }
-
-}

+ 7 - 17
thinkphp/library/think/route/dispatch/Module.php

@@ -11,7 +11,6 @@
 
 namespace think\route\dispatch;
 
-use ReflectionMethod;
 use think\Container;
 use think\exception\ClassNotFoundException;
 use think\exception\HttpException;
@@ -55,7 +54,7 @@ class Module extends Dispatch
                 $this->app->init($module);
 
                 // 加载当前模块语言包
-                $this->app['lang']->load($this->app->getAppPath() . $module . DIRECTORY_SEPARATOR . 'lang' . DIRECTORY_SEPARATOR . $this->app['request']->langset() . '.php');
+                $this->app['lang']->load($this->app->getAppPath() . $module . '/lang/' . $this->app['request']->langset() . '.php');
 
                 // 模块请求缓存检查
                 $this->app['request']->cache(
@@ -73,7 +72,7 @@ class Module extends Dispatch
         }
 
         // 当前模块路径
-        $this->app->setModulePath($this->app->getAppPath() . ($module ? $module . DIRECTORY_SEPARATOR : ''));
+        $this->app->setModulePath($this->app->getAppPath() . ($module ? $module . '/' : ''));
 
         // 是否自动转换控制器和操作名
         $convert = is_bool($this->convert) ? $this->convert : $this->app->config('app.url_convert');
@@ -83,9 +82,10 @@ class Module extends Dispatch
 
         // 获取操作名
         $actionName = strip_tags($result[2] ?: $this->app->config('app.default_action'));
+        $actionName = $convert ? strtolower($actionName) : $actionName;
 
         // 设置当前请求的控制器、操作
-        $this->app['request']->controller(Loader::parseName($controller, 1));
+        $this->app['request']->controller(Loader::parseName($controller, 1))->action($actionName);
 
         // 监听module_init
         $this->app['hook']->listen('module_init');
@@ -106,24 +106,14 @@ class Module extends Dispatch
         if (is_callable([$instance, $action])) {
             // 执行操作方法
             $call = [$instance, $action];
-
-            // 严格获取当前操作方法名
-            $reflect    = new ReflectionMethod($instance, $action);
-            $methodName = $reflect->getName();
-            $suffix     = $this->app->config('app.action_suffix');
-            $actionName = $suffix ? substr($methodName, 0, -strlen($suffix)) : $methodName;
-            $this->app['request']->action($actionName);
-
             // 自动获取请求变量
             $vars = $this->app->config('app.url_param_type')
             ? $this->app['request']->route()
             : $this->app['request']->param();
         } elseif (is_callable([$instance, '_empty'])) {
             // 空操作
-            $this->app['request']->action($actionName);
-            $call    = [$instance, '_empty'];
-            $vars    = [$actionName];
-            $reflect = new ReflectionMethod($instance, '_empty');
+            $call = [$instance, '_empty'];
+            $vars = [$actionName];
         } else {
             // 操作不存在
             throw new HttpException(404, 'method not exists:' . get_class($instance) . '->' . $action . '()');
@@ -131,6 +121,6 @@ class Module extends Dispatch
 
         $this->app['hook']->listen('action_begin', $call);
 
-        return Container::getInstance()->invokeReflectMethod($instance, $reflect, $vars);
+        return Container::getInstance()->invokeMethod($call, $vars);
     }
 }

+ 1 - 1
vendor/autoload.php

@@ -4,4 +4,4 @@
 
 require_once __DIR__ . '/composer/autoload_real.php';
 
-return ComposerAutoloaderInitcf980ce2ebc944e5d847ad4152559ece::getLoader();
+return ComposerAutoloaderInitba64bd31f645bcd87c20ea0144cdca77::getLoader();

+ 7 - 7
vendor/composer/autoload_real.php

@@ -2,7 +2,7 @@
 
 // autoload_real.php @generated by Composer
 
-class ComposerAutoloaderInitcf980ce2ebc944e5d847ad4152559ece
+class ComposerAutoloaderInitba64bd31f645bcd87c20ea0144cdca77
 {
     private static $loader;
 
@@ -19,15 +19,15 @@ class ComposerAutoloaderInitcf980ce2ebc944e5d847ad4152559ece
             return self::$loader;
         }
 
-        spl_autoload_register(array('ComposerAutoloaderInitcf980ce2ebc944e5d847ad4152559ece', 'loadClassLoader'), true, true);
+        spl_autoload_register(array('ComposerAutoloaderInitba64bd31f645bcd87c20ea0144cdca77', 'loadClassLoader'), true, true);
         self::$loader = $loader = new \Composer\Autoload\ClassLoader();
-        spl_autoload_unregister(array('ComposerAutoloaderInitcf980ce2ebc944e5d847ad4152559ece', 'loadClassLoader'));
+        spl_autoload_unregister(array('ComposerAutoloaderInitba64bd31f645bcd87c20ea0144cdca77', 'loadClassLoader'));
 
         $useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded());
         if ($useStaticLoader) {
             require_once __DIR__ . '/autoload_static.php';
 
-            call_user_func(\Composer\Autoload\ComposerStaticInitcf980ce2ebc944e5d847ad4152559ece::getInitializer($loader));
+            call_user_func(\Composer\Autoload\ComposerStaticInitba64bd31f645bcd87c20ea0144cdca77::getInitializer($loader));
         } else {
             $map = require __DIR__ . '/autoload_namespaces.php';
             foreach ($map as $namespace => $path) {
@@ -48,19 +48,19 @@ class ComposerAutoloaderInitcf980ce2ebc944e5d847ad4152559ece
         $loader->register(true);
 
         if ($useStaticLoader) {
-            $includeFiles = Composer\Autoload\ComposerStaticInitcf980ce2ebc944e5d847ad4152559ece::$files;
+            $includeFiles = Composer\Autoload\ComposerStaticInitba64bd31f645bcd87c20ea0144cdca77::$files;
         } else {
             $includeFiles = require __DIR__ . '/autoload_files.php';
         }
         foreach ($includeFiles as $fileIdentifier => $file) {
-            composerRequirecf980ce2ebc944e5d847ad4152559ece($fileIdentifier, $file);
+            composerRequireba64bd31f645bcd87c20ea0144cdca77($fileIdentifier, $file);
         }
 
         return $loader;
     }
 }
 
-function composerRequirecf980ce2ebc944e5d847ad4152559ece($fileIdentifier, $file)
+function composerRequireba64bd31f645bcd87c20ea0144cdca77($fileIdentifier, $file)
 {
     if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {
         require $file;

+ 4 - 4
vendor/composer/autoload_static.php

@@ -4,7 +4,7 @@
 
 namespace Composer\Autoload;
 
-class ComposerStaticInitcf980ce2ebc944e5d847ad4152559ece
+class ComposerStaticInitba64bd31f645bcd87c20ea0144cdca77
 {
     public static $files = array (
         '1cfd2761b63b0a29ed23657ea394cb2d' => __DIR__ . '/..' . '/topthink/think-captcha/src/helper.php',
@@ -257,9 +257,9 @@ class ComposerStaticInitcf980ce2ebc944e5d847ad4152559ece
     public static function getInitializer(ClassLoader $loader)
     {
         return \Closure::bind(function () use ($loader) {
-            $loader->prefixLengthsPsr4 = ComposerStaticInitcf980ce2ebc944e5d847ad4152559ece::$prefixLengthsPsr4;
-            $loader->prefixDirsPsr4 = ComposerStaticInitcf980ce2ebc944e5d847ad4152559ece::$prefixDirsPsr4;
-            $loader->classMap = ComposerStaticInitcf980ce2ebc944e5d847ad4152559ece::$classMap;
+            $loader->prefixLengthsPsr4 = ComposerStaticInitba64bd31f645bcd87c20ea0144cdca77::$prefixLengthsPsr4;
+            $loader->prefixDirsPsr4 = ComposerStaticInitba64bd31f645bcd87c20ea0144cdca77::$prefixDirsPsr4;
+            $loader->classMap = ComposerStaticInitba64bd31f645bcd87c20ea0144cdca77::$classMap;
 
         }, null, ClassLoader::class);
     }

+ 6 - 6
vendor/composer/installed.json

@@ -175,17 +175,17 @@
     },
     {
         "name": "topthink/framework",
-        "version": "5.1.6",
-        "version_normalized": "5.1.6.0",
+        "version": "v5.1.5",
+        "version_normalized": "5.1.5.0",
         "source": {
             "type": "git",
             "url": "https://github.com/top-think/framework.git",
-            "reference": "98aaf52dd364af7fdecc7214224678d180676b4f"
+            "reference": "f81c4282cdf401be44fbe1a28b3e3df425e3017f"
         },
         "dist": {
             "type": "zip",
-            "url": "https://files.phpcomposer.com/files/top-think/framework/98aaf52dd364af7fdecc7214224678d180676b4f.zip",
-            "reference": "98aaf52dd364af7fdecc7214224678d180676b4f",
+            "url": "https://files.phpcomposer.com/files/top-think/framework/f81c4282cdf401be44fbe1a28b3e3df425e3017f.zip",
+            "reference": "f81c4282cdf401be44fbe1a28b3e3df425e3017f",
             "shasum": ""
         },
         "require": {
@@ -201,7 +201,7 @@
             "sebastian/phpcpd": "2.*",
             "squizlabs/php_codesniffer": "2.*"
         },
-        "time": "2018-03-26T07:10:00+00:00",
+        "time": "2018-02-02T05:39:38+00:00",
         "type": "think-framework",
         "installation-source": "dist",
         "notification-url": "https://packagist.org/downloads/",