Passed
Push — 5.2 ( 38a73e...b7aaad )
by liu
02:26
created

App::parse()   A

Complexity

Conditions 6
Paths 18

Size

Total Lines 29
Code Lines 19

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 6
eloc 19
nc 18
nop 0
dl 0
loc 29
rs 9.0111
c 0
b 0
f 0
1
<?php
2
// +----------------------------------------------------------------------
1 ignored issue
show
Coding Style introduced by
You must use "/**" style comments for a file comment
Loading history...
3
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
4
// +----------------------------------------------------------------------
5
// | Copyright (c) 2006~2019 http://thinkphp.cn All rights reserved.
6
// +----------------------------------------------------------------------
7
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
8
// +----------------------------------------------------------------------
9
// | Author: liu21st <[email protected]>
10
// +----------------------------------------------------------------------
11
declare (strict_types = 1);
12
13
namespace think;
14
15
use Opis\Closure\SerializableClosure;
16
use think\exception\ClassNotFoundException;
17
use think\exception\HttpException;
18
use think\exception\HttpResponseException;
19
use think\route\Dispatch;
20
21
/**
22
 * App 应用管理
23
 * @property Route $route
24
 * @property Config $config
25
 * @property Cache $cache
26
 * @property Request $request
27
 * @property Env $env
28
 * @property Debug $debug
29
 * @property Event $event
30
 * @property Middleware $middleware
31
 * @property Log $log
32
 * @property Lang $lang
33
 * @property Db $db
34
 * @property Cookie $cookie
35
 * @property Session $session
36
 * @property Url $url
37
 * @property Validate $validate
38
 * @property Build $build
39
 * @property \think\route\RuleName $rule_name
40
 */
5 ignored issues
show
Coding Style introduced by
Missing @category tag in class comment
Loading history...
Coding Style introduced by
Missing @package tag in class comment
Loading history...
Coding Style introduced by
Missing @author tag in class comment
Loading history...
Coding Style introduced by
Missing @license tag in class comment
Loading history...
Coding Style introduced by
Missing @link tag in class comment
Loading history...
41
class App extends Container
42
{
43
    const VERSION = '5.2.0RC1';
44
45
    /**
46
     * 应用名称
47
     * @var string
48
     */
49
    protected $name;
50
51
    /**
52
     * 应用调试模式
53
     * @var bool
54
     */
55
    protected $appDebug = true;
56
57
    /**
58
     * 应用开始时间
59
     * @var float
60
     */
61
    protected $beginTime;
62
63
    /**
64
     * 应用内存初始占用
65
     * @var integer
66
     */
67
    protected $beginMem;
68
69
    /**
70
     * 应用类库顶级命名空间
71
     * @var string
72
     */
73
    protected $rootNamespace = 'app';
74
75
    /**
76
     * 当前应用类库命名空间
77
     * @var string
78
     */
79
    protected $namespace = '';
80
81
    /**
82
     * 应用根目录
83
     * @var string
84
     */
85
    protected $rootPath = '';
86
87
    /**
88
     * 框架目录
89
     * @var string
90
     */
91
    protected $thinkPath = '';
92
93
    /**
94
     * 应用基础目录
95
     * @var string
96
     */
97
    protected $basePath = '';
98
99
    /**
100
     * 应用类库目录
101
     * @var string
102
     */
103
    protected $appPath = '';
104
105
    /**
106
     * 默认应用名(多应用模式)
107
     * @var string
108
     */
109
    protected $defaultApp = 'index';
110
111
    /**
112
     * 运行时目录
113
     * @var string
114
     */
115
    protected $runtimePath = '';
116
117
    /**
118
     * 配置目录
119
     * @var string
120
     */
121
    protected $configPath = '';
122
123
    /**
124
     * 路由目录
125
     * @var string
126
     */
127
    protected $routePath = '';
128
129
    /**
130
     * 配置后缀
131
     * @var string
132
     */
133
    protected $configExt = '.php';
134
135
    /**
136
     * 初始化
137
     * @var bool
138
     */
139
    protected $initialized = false;
140
141
    /**
142
     * 是否为多应用模式
143
     * @var bool
144
     */
145
    protected $multi = false;
146
147
    /**
148
     * 是否为自动多应用
149
     * @var bool
150
     */
151
    protected $auto = false;
152
153
    /**
154
     * 应用映射
155
     * @var array
156
     */
157
    protected $map = [];
158
159
    /**
160
     * 是否需要事件响应
161
     * @var bool
162
     */
163
    protected $withEvent = true;
164
165
    /**
166
     * 是否需要使用路由
167
     * @var bool
168
     */
169
    protected $withRoute = true;
170
171
    /**
172
     * 访问控制器层名称
173
     * @var string
174
     */
175
    protected $controllerLayer = 'controller';
176
177
    /**
178
     * 是否使用控制器类库后缀
179
     * @var bool
180
     */
181
    protected $controllerSuffix = false;
182
183
    /**
184
     * 空控制器名称
185
     * @var string
186
     */
187
    protected $emptyController = 'Error';
188
189
    /**
190
     * 架构方法
191
     * @access public
192
     * @param  string $rootPath 应用根目录
193
     */
194
    public function __construct(string $rootPath = '')
195
    {
196
        $this->thinkPath = dirname(__DIR__) . DIRECTORY_SEPARATOR;
197
        $this->rootPath  = $rootPath ? realpath($rootPath) . DIRECTORY_SEPARATOR : $this->getDefaultRootPath();
198
        $this->basePath  = $this->rootPath . 'app' . DIRECTORY_SEPARATOR;
199
200
        $this->multi = is_dir($this->basePath . 'controller') ? false : true;
201
202
        static::setInstance($this);
203
204
        $this->instance('app', $this);
205
206
        // 注册错误和异常处理机制
207
        Error::register();
208
    }
209
210
    /**
211
     * 自动多应用访问
212
     * @access public
213
     * @param  array $map 应用路由映射
214
     * @return $this
215
     */
216
    public function autoMulti(array $map = [])
217
    {
218
        $this->multi = true;
219
        $this->auto  = true;
220
        $this->map   = $map;
221
222
        return $this;
223
    }
224
225
    /**
226
     * 是否为自动多应用模式
227
     * @access public
228
     * @return bool
229
     */
230
    public function isAutoMulti(): bool
231
    {
232
        return $this->auto;
233
    }
234
235
    /**
236
     * 设置应用模式
237
     * @access public
238
     * @param  bool $multi
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
239
     * @return $this
240
     */
241
    public function multi(bool $multi)
242
    {
243
        $this->multi = $multi;
244
        return $this;
245
    }
246
247
    /**
248
     * 是否为多应用模式
249
     * @access public
250
     * @return bool
251
     */
252
    public function isMulti(): bool
253
    {
254
        return $this->multi;
255
    }
256
257
    /**
258
     * 设置是否使用事件机制
259
     * @access public
260
     * @param  bool $event
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
261
     * @return $this
262
     */
263
    public function withEvent(bool $event)
264
    {
265
        $this->withEvent = $event;
266
        return $this;
267
    }
268
269
    /**
270
     * 设置是否使用路由
271
     * @access public
272
     * @param  bool $route
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
273
     * @return $this
274
     */
275
    public function withRoute(bool $route)
276
    {
277
        $this->withRoute = $route;
278
        return $this;
279
    }
280
281
    /**
282
     * 设置应用路径
283
     * @access public
284
     * @param  string $path 应用目录
285
     * @return $this
286
     */
287
    public function path(string $path)
288
    {
289
        $this->appPath = $path;
290
        return $this;
291
    }
292
293
    /**
294
     * 开启应用调试模式
295
     * @access public
296
     * @param  bool $debug 开启应用调试模式
297
     * @return $this
298
     */
299
    public function debug(bool $debug = true)
300
    {
301
        $this->appDebug = $debug;
302
        return $this;
303
    }
304
305
    /**
306
     * 是否为调试模式
307
     * @access public
308
     * @return bool
309
     */
310
    public function isDebug(): bool
311
    {
312
        return $this->appDebug;
313
    }
314
315
    /**
316
     * 设置应用名称
317
     * @access public
318
     * @param  string $name 应用名称
319
     * @return $this
320
     */
321
    public function name(string $name)
322
    {
323
        $this->name = $name;
324
        return $this;
325
    }
326
327
    /**
328
     * 设置默认应用(对多应用有效)
329
     * @access public
330
     * @param  string $name 应用名
331
     * @return $this
332
     */
333
    public function defaultApp(string $name)
334
    {
335
        $this->defaultApp = $name;
336
        return $this;
337
    }
338
339
    /**
340
     * 设置控制器层名称
341
     * @access public
342
     * @param  string $layer 控制器层名称
343
     * @return $this
344
     */
345
    public function controllerLayer(string $layer)
346
    {
347
        $this->controllerLayer = $layer;
348
        return $this;
349
    }
350
351
    /**
352
     * 设置空控制器名称
353
     * @access public
354
     * @param  string $empty 空控制器名称
355
     * @return $this
356
     */
357
    public function emptyController(string $empty)
358
    {
359
        $this->emptyController = $empty;
360
        return $this;
361
    }
362
363
    /**
364
     * 设置应用命名空间
365
     * @access public
366
     * @param  string $namespace 应用命名空间
367
     * @return $this
368
     */
369
    public function setNamespace(string $namespace)
370
    {
371
        $this->namespace = $namespace;
372
        return $this;
373
    }
374
375
    /**
376
     * 设置应用根命名空间
377
     * @access public
378
     * @param  string $rootNamespace 应用命名空间
379
     * @return $this
380
     */
381
    public function setRootNamespace(string $rootNamespace)
382
    {
383
        $this->rootNamespace = $rootNamespace;
384
        return $this;
385
    }
386
387
    /**
388
     * 设置是否启用控制器类库后缀
389
     * @access public
390
     * @param  bool  $suffix 启用控制器类库后缀
391
     * @return $this
392
     */
393
    public function controllerSuffix(bool $suffix = true)
394
    {
395
        $this->controllerSuffix = $suffix;
396
        return $this;
397
    }
398
399
    /**
400
     * 获取框架版本
401
     * @access public
402
     * @return string
403
     */
404
    public function version(): string
405
    {
406
        return static::VERSION;
407
    }
408
409
    /**
410
     * 获取应用名称
411
     * @access public
412
     * @return string
413
     */
414
    public function getName(): string
415
    {
416
        return $this->name ?: '';
417
    }
418
419
    /**
420
     * 获取应用根目录
421
     * @access public
422
     * @return string
423
     */
424
    public function getRootPath(): string
425
    {
426
        return $this->rootPath;
427
    }
428
429
    /**
430
     * 获取应用基础目录
431
     * @access public
432
     * @return string
433
     */
434
    public function getBasePath(): string
435
    {
436
        return $this->basePath;
437
    }
438
439
    /**
440
     * 获取当前应用目录
441
     * @access public
442
     * @return string
443
     */
444
    public function getAppPath(): string
445
    {
446
        return $this->appPath;
447
    }
448
449
    /**
450
     * 获取应用运行时目录
451
     * @access public
452
     * @return string
453
     */
454
    public function getRuntimePath(): string
455
    {
456
        return $this->runtimePath;
457
    }
458
459
    /**
460
     * 获取核心框架目录
461
     * @access public
462
     * @return string
463
     */
464
    public function getThinkPath(): string
465
    {
466
        return $this->thinkPath;
467
    }
468
469
    /**
470
     * 获取路由目录
471
     * @access public
472
     * @return string
473
     */
474
    public function getRoutePath(): string
475
    {
476
        return $this->routePath;
477
    }
478
479
    /**
480
     * 获取应用配置目录
481
     * @access public
482
     * @return string
483
     */
484
    public function getConfigPath(): string
485
    {
486
        return $this->configPath;
487
    }
488
489
    /**
490
     * 获取配置后缀
491
     * @access public
492
     * @return string
493
     */
494
    public function getConfigExt(): string
495
    {
496
        return $this->configExt;
497
    }
498
499
    /**
500
     * 获取应用类基础命名空间
501
     * @access public
502
     * @return string
503
     */
504
    public function getRootNamespace(): string
505
    {
506
        return $this->rootNamespace;
507
    }
508
509
    /**
510
     * 获取应用类库命名空间
511
     * @access public
512
     * @return string
513
     */
514
    public function getNamespace(): string
515
    {
516
        return $this->namespace;
517
    }
518
519
    /**
520
     * 是否启用控制器类库后缀
521
     * @access public
522
     * @return bool
523
     */
524
    public function hasControllerSuffix(): bool
525
    {
526
        return $this->controllerSuffix;
527
    }
528
529
    /**
530
     * 获取应用开启时间
531
     * @access public
532
     * @return float
533
     */
534
    public function getBeginTime(): float
535
    {
536
        return $this->beginTime;
537
    }
538
539
    /**
540
     * 获取应用初始内存占用
541
     * @access public
542
     * @return integer
543
     */
544
    public function getBeginMem(): int
545
    {
546
        return $this->beginMem;
547
    }
548
549
    /**
550
     * 获取控制器层名称
551
     * @access public
552
     * @return string
553
     */
554
    public function getControllerLayer(): string
555
    {
556
        return $this->controllerLayer;
557
    }
558
559
    /**
560
     * 初始化应用
561
     * @access public
562
     * @return $this
563
     */
564
    public function initialize()
565
    {
566
        $this->beginTime = microtime(true);
567
        $this->beginMem  = memory_get_usage();
568
569
        if (is_file($this->rootPath . '.env')) {
570
            $this->env->load($this->rootPath . '.env');
571
        }
572
573
        $this->parse();
574
575
        $this->configExt = $this->env->get('config_ext', '.php');
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->env->get('config_ext', '.php') can also be of type boolean. However, the property $configExt is declared as type string. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
576
577
        $this->init();
578
579
        $this->debugModeInit();
580
581
        if ($this->config->get('app.exception_handle')) {
582
            Error::setExceptionHandler($this->config->get('app.exception_handle'));
583
        }
584
585
        date_default_timezone_set($this->config->get('app.default_timezone', 'Asia/Shanghai'));
0 ignored issues
show
Bug introduced by
It seems like $this->config->get('app....zone', 'Asia/Shanghai') can also be of type array and array; however, parameter $timezone_identifier of date_default_timezone_set() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

585
        date_default_timezone_set(/** @scrutinizer ignore-type */ $this->config->get('app.default_timezone', 'Asia/Shanghai'));
Loading history...
586
587
        // 设置开启事件机制
588
        $this->event->withEvent($this->withEvent);
589
590
        return $this;
591
    }
592
593
    protected function debugModeInit(): void
0 ignored issues
show
Coding Style introduced by
Missing function doc comment
Loading history...
594
    {
595
        // 应用调试模式
596
        if (!$this->appDebug) {
597
            $this->appDebug = $this->env->get('app_debug', false);
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->env->get('app_debug', false) can also be of type string. However, the property $appDebug is declared as type boolean. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
598
        }
599
600
        if (!$this->appDebug) {
601
            ini_set('display_errors', 'Off');
602
        } elseif (PHP_SAPI != 'cli') {
603
            //重新申请一块比较大的buffer
604
            if (ob_get_level() > 0) {
605
                $output = ob_get_clean();
606
            }
607
            ob_start();
608
            if (!empty($output)) {
609
                echo $output;
610
            }
611
        }
612
    }
613
614
    /**
615
     * 分析应用(参数)
616
     * @access protected
617
     * @return void
618
     */
619
    protected function parse(): void
620
    {
621
        if ($this->multi) {
622
            $this->parseAppName();
623
624
            $this->runtimePath = $this->rootPath . 'runtime' . DIRECTORY_SEPARATOR . $this->name . DIRECTORY_SEPARATOR;
625
            $this->routePath   = $this->rootPath . 'route' . DIRECTORY_SEPARATOR . $this->name . DIRECTORY_SEPARATOR;
626
        } else {
627
            $this->runtimePath = $this->rootPath . 'runtime' . DIRECTORY_SEPARATOR;
628
            $this->routePath   = $this->rootPath . 'route' . DIRECTORY_SEPARATOR;
629
        }
630
631
        if (!$this->appPath) {
632
            $this->appPath = $this->multi ? $this->basePath . $this->name . DIRECTORY_SEPARATOR : $this->basePath;
633
        }
634
635
        if (!$this->namespace) {
636
            $this->namespace = $this->multi ? $this->rootNamespace . '\\' . $this->name : $this->rootNamespace;
637
        }
638
639
        $this->configPath = $this->rootPath . 'config' . DIRECTORY_SEPARATOR;
640
641
        $this->env->set([
0 ignored issues
show
Coding Style introduced by
The opening parenthesis of a multi-line function call should be the last content on the line.
Loading history...
642
            'think_path'   => $this->thinkPath,
643
            'root_path'    => $this->rootPath,
644
            'app_path'     => $this->appPath,
645
            'runtime_path' => $this->runtimePath,
646
            'route_path'   => $this->routePath,
647
            'config_path'  => $this->configPath,
648
        ]);
0 ignored issues
show
Coding Style introduced by
For multi-line function calls, the closing parenthesis should be on a new line.

If a function call spawns multiple lines, the coding standard suggests to move the closing parenthesis to a new line:

someFunctionCall(
    $firstArgument,
    $secondArgument,
    $thirdArgument
); // Closing parenthesis on a new line.
Loading history...
649
    }
650
651
    /**
652
     * 分析当前请求的应用名(多应用模式下)
653
     * @access protected
654
     * @return void
655
     */
656
    protected function parseAppName(): void
657
    {
658
        $path = $this->request->path();
659
660
        if ($this->auto && $path) {
661
            // 自动多应用识别
662
            $name = current(explode('/', $path));
663
664
            if (isset($this->map[$name])) {
665
                if ($this->map[$name] instanceof \Closure) {
666
                    call_user_func_array($this->map[$name], [$this]);
667
                } else {
668
                    $this->name = $this->map[$name];
669
                }
670
            } elseif ($name && array_search($name, $this->map)) {
671
                throw new HttpException(404, 'app not exists:' . $name);
672
            } else {
673
                $this->name = $name ?: $this->defaultApp;
674
            }
675
        } else {
676
            $this->name = $this->name ?: $this->getScriptName();
677
        }
678
    }
679
680
    /**
681
     * 初始化应用
682
     * @access public
683
     * @return void
684
     */
685
    public function init(): void
686
    {
687
        // 加载初始化文件
688
        if (is_file($this->runtimePath . 'init.php')) {
689
            include $this->runtimePath . 'init.php';
690
        } else {
691
            $this->loadAppFile();
692
        }
693
694
        $this->request->setApp($this->name ?: '');
695
696
        // 监听AppInit
697
        $this->event->trigger('AppInit');
698
    }
699
700
    /**
701
     * 加载应用文件和配置
702
     * @access protected
703
     * @return void
704
     */
705
    protected function loadAppFile(): void
706
    {
707
        if ($this->multi && is_file($this->basePath . 'event.php')) {
708
            $this->loadEvent(include $this->basePath . 'event.php');
709
        }
710
711
        if (is_file($this->appPath . 'event.php')) {
712
            $this->loadEvent(include $this->appPath . 'event.php');
713
        }
714
715
        if ($this->multi && is_file($this->basePath . 'common.php')) {
716
            include_once $this->basePath . 'common.php';
717
        }
718
719
        if (is_file($this->appPath . 'common.php')) {
720
            include_once $this->appPath . 'common.php';
721
        }
722
723
        include $this->thinkPath . 'helper.php';
724
725
        if ($this->multi && is_file($this->basePath . 'middleware.php')) {
726
            $this->middleware->import(include $this->basePath . 'middleware.php');
727
        }
728
729
        if (is_file($this->appPath . 'middleware.php')) {
730
            $this->middleware->import(include $this->appPath . 'middleware.php');
731
        }
732
733
        if ($this->multi && is_file($this->basePath . 'provider.php')) {
734
            $this->bind(include $this->basePath . 'provider.php');
735
        }
736
737
        if (is_file($this->appPath . 'provider.php')) {
738
            $this->bind(include $this->appPath . 'provider.php');
739
        }
740
741
        $files = [];
742
743
        if (is_dir($this->configPath)) {
744
            $files = glob($this->configPath . '*' . $this->configExt);
745
        }
746
747
        if ($this->multi) {
748
            if (is_dir($this->appPath . 'config')) {
749
                $files = array_merge($files, glob($this->appPath . 'config' . DIRECTORY_SEPARATOR . '*' . $this->configExt));
750
            } elseif (is_dir($this->configPath . $this->name)) {
751
                $files = array_merge($files, glob($this->configPath . $this->name . DIRECTORY_SEPARATOR . '*' . $this->configExt));
752
            }
753
        }
754
755
        foreach ($files as $file) {
756
            $this->config->load($file, pathinfo($file, PATHINFO_FILENAME));
757
        }
758
    }
759
760
    protected function loadEvent(array $event): void
0 ignored issues
show
Coding Style introduced by
Missing function doc comment
Loading history...
761
    {
762
        if (isset($event['bind'])) {
763
            $this->event->bind($event['bind']);
764
        }
765
766
        if (isset($event['listen'])) {
767
            $this->event->listenEvents($event['listen']);
768
        }
769
770
        if (isset($event['subscribe'])) {
771
            $this->event->subscribe($event['subscribe']);
772
        }
773
    }
774
775
    public function getRealPath()
0 ignored issues
show
Coding Style introduced by
Missing function doc comment
Loading history...
776
    {
777
        $path = $this->request->path();
778
779
        if ($path && $this->auto) {
780
            $path = substr_replace($path, '', 0, strpos($path, '/') ? strpos($path, '/') + 1 : strlen($path));
781
        }
782
783
        return $path;
784
    }
785
786
    /**
787
     * 执行应用程序
788
     * @access public
789
     * @return Response
790
     * @throws Exception
791
     */
792
    public function run(): Response
793
    {
794
        try {
795
            if ($this->withRoute) {
796
                $dispatch = $this->routeCheck()->init();
797
            } else {
798
                $dispatch = $this->route->url($this->getRealPath())->init();
799
            }
800
801
            // 监听AppBegin
802
            $this->event->trigger('AppBegin');
803
804
            $data = null;
805
        } catch (HttpResponseException $exception) {
806
            $dispatch = null;
807
            $data     = $exception->getResponse();
808
        }
809
810
        $this->middleware->add(function (Request $request, $next) use ($dispatch, $data) {
0 ignored issues
show
Unused Code introduced by
The parameter $request is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

810
        $this->middleware->add(function (/** @scrutinizer ignore-unused */ Request $request, $next) use ($dispatch, $data) {

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $next is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

810
        $this->middleware->add(function (Request $request, /** @scrutinizer ignore-unused */ $next) use ($dispatch, $data) {

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Coding Style introduced by
The opening parenthesis of a multi-line function call should be the last content on the line.
Loading history...
811
            return is_null($data) ? $dispatch->run() : $data;
812
        });
0 ignored issues
show
Coding Style introduced by
For multi-line function calls, the closing parenthesis should be on a new line.

If a function call spawns multiple lines, the coding standard suggests to move the closing parenthesis to a new line:

someFunctionCall(
    $firstArgument,
    $secondArgument,
    $thirdArgument
); // Closing parenthesis on a new line.
Loading history...
813
814
        $response = $this->middleware->dispatch($this->request);
815
816
        // 监听AppEnd
817
        $this->event->trigger('AppEnd', $response);
818
819
        return $response;
820
    }
821
822
    /**
823
     * 实例化访问控制器 格式:控制器名
824
     * @access public
825
     * @param  string $name              资源地址
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 14 found
Loading history...
826
     * @return object
827
     * @throws ClassNotFoundException
828
     */
829
    public function controller(string $name)
830
    {
831
        $suffix = $this->controllerSuffix ? 'Controller' : '';
832
        $class  = $this->parseClass($this->controllerLayer, $name . $suffix);
833
834
        if (class_exists($class)) {
835
            return $this->make($class, [], true);
836
        } elseif ($this->emptyController && class_exists($emptyClass = $this->parseClass($this->controllerLayer, $this->emptyController . $suffix))) {
837
            return $this->make($emptyClass, [], true);
838
        }
839
840
        throw new ClassNotFoundException('class not exists:' . $class, $class);
841
    }
842
843
    /**
844
     * 解析应用类的类名
845
     * @access public
846
     * @param  string $layer  层名 controller model ...
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 2 found
Loading history...
847
     * @param  string $name   类名
0 ignored issues
show
Coding Style introduced by
Expected 2 spaces after parameter name; 3 found
Loading history...
848
     * @return string
849
     */
850
    public function parseClass(string $layer, string $name): string
851
    {
852
        $name  = str_replace(['/', '.'], '\\', $name);
853
        $array = explode('\\', $name);
854
        $class = self::parseName(array_pop($array), 1);
855
        $path  = $array ? implode('\\', $array) . '\\' : '';
856
857
        return $this->namespace . '\\' . $layer . '\\' . $path . $class;
858
    }
859
860
    // 获取应用根目录
861
    public function getDefaultRootPath(): string
0 ignored issues
show
Coding Style introduced by
You must use "/**" style comments for a function comment
Loading history...
862
    {
863
        $path = dirname(dirname(dirname(dirname($this->thinkPath))));
864
865
        return $path . DIRECTORY_SEPARATOR;
866
    }
867
868
    /**
869
     * 路由初始化(路由规则注册)
870
     * @access protected
871
     * @return void
872
     */
873
    protected function routeInit(): void
874
    {
875
        // 加载路由定义
876
        if (is_dir($this->routePath)) {
877
            $files = glob($this->routePath . DIRECTORY_SEPARATOR . '*.php');
878
            foreach ($files as $file) {
879
                include $file;
880
            }
881
        }
882
883
        if ($this->route->config('route_annotation')) {
884
            // 自动生成注解路由定义
885
            if ($this->isDebug()) {
886
                $this->build->buildRoute();
887
            }
888
889
            $filename = $this->runtimePath . 'build_route.php';
890
891
            if (is_file($filename)) {
892
                include $filename;
893
            }
894
        }
895
    }
896
897
    /**
898
     * URL路由检测(根据PATH_INFO)
899
     * @access protected
900
     * @return Dispatch
901
     */
902
    protected function routeCheck(): Dispatch
903
    {
904
        // 检测路由缓存
905
        if (!$this->isDebug() && $this->route->config('route_check_cache')) {
906
            $routeKey = $this->getRouteCacheKey();
907
            $option   = $this->route->config('route_cache_option');
908
909
            if ($option && $this->cache->connect($option)->has($routeKey)) {
910
                return $this->cache->connect($option)->get($routeKey);
911
            } elseif ($this->cache->has($routeKey)) {
912
                return $this->cache->get($routeKey);
913
            }
914
        }
915
916
        $this->routeInit();
917
918
        // 路由检测
919
        $dispatch = $this->route->check($this->getRealPath());
920
921
        if (!empty($routeKey)) {
922
            try {
923
                if (!empty($option)) {
924
                    $this->cache->connect($option)->tag('route_cache')->set($routeKey, $dispatch);
925
                } else {
926
                    $this->cache->tag('route_cache')->set($routeKey, $dispatch);
927
                }
928
            } catch (\Exception $e) {
929
                // 存在闭包的时候缓存无效
930
            }
931
        }
932
933
        return $dispatch;
934
    }
935
936
    protected function getRouteCacheKey(): string
0 ignored issues
show
Coding Style introduced by
Missing function doc comment
Loading history...
937
    {
938
        if ($this->route->config('route_check_cache_key')) {
939
            $closure  = $this->route->config('route_check_cache_key');
940
            $routeKey = $closure($this->request);
941
        } else {
942
            $routeKey = md5($this->request->baseUrl(true) . ':' . $this->request->method());
943
        }
944
945
        return $routeKey;
946
    }
947
948
    protected function getScriptName(): string
0 ignored issues
show
Coding Style introduced by
Missing function doc comment
Loading history...
949
    {
950
        if (isset($_SERVER['SCRIPT_FILENAME'])) {
951
            $file = $_SERVER['SCRIPT_FILENAME'];
952
        } elseif (isset($_SERVER['argv'][0])) {
953
            $file = realpath($_SERVER['argv'][0]);
954
        }
955
956
        return isset($file) ? pathinfo($file, PATHINFO_FILENAME) : $this->defaultApp;
957
    }
958
959
    /**
960
     * 字符串命名风格转换
961
     * type 0 将Java风格转换为C的风格 1 将C风格转换为Java的风格
962
     * @access public
963
     * @param  string  $name 字符串
0 ignored issues
show
Coding Style introduced by
Expected 4 spaces after parameter name; 1 found
Loading history...
964
     * @param  integer $type 转换类型
0 ignored issues
show
Coding Style introduced by
Expected 4 spaces after parameter name; 1 found
Loading history...
965
     * @param  bool    $ucfirst 首字母是否大写(驼峰规则)
966
     * @return string
967
     */
968
    public static function parseName(string $name = null, int $type = 0, bool $ucfirst = true): string
969
    {
970
        if ($type) {
971
            $name = preg_replace_callback('/_([a-zA-Z])/', function ($match) {
0 ignored issues
show
Coding Style introduced by
The opening parenthesis of a multi-line function call should be the last content on the line.
Loading history...
972
                return strtoupper($match[1]);
973
            }, $name);
0 ignored issues
show
Coding Style introduced by
For multi-line function calls, the closing parenthesis should be on a new line.

If a function call spawns multiple lines, the coding standard suggests to move the closing parenthesis to a new line:

someFunctionCall(
    $firstArgument,
    $secondArgument,
    $thirdArgument
); // Closing parenthesis on a new line.
Loading history...
974
            return $ucfirst ? ucfirst($name) : lcfirst($name);
975
        }
976
977
        return strtolower(trim(preg_replace("/[A-Z]/", "_\\0", $name), "_"));
978
    }
979
980
    /**
981
     * 获取类名(不包含命名空间)
982
     * @access public
983
     * @param  string|object $class
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
984
     * @return string
985
     */
986
    public static function classBaseName($class): string
987
    {
988
        $class = is_object($class) ? get_class($class) : $class;
989
        return basename(str_replace('\\', '/', $class));
990
    }
991
992
    /**
0 ignored issues
show
Coding Style introduced by
Parameter ...$args should have a doc-comment as per coding-style.
Loading history...
993
     * 创建工厂对象实例
994
     * @access public
995
     * @param  string $name         工厂类名
0 ignored issues
show
Coding Style introduced by
Expected 6 spaces after parameter name; 9 found
Loading history...
996
     * @param  string $namespace    默认命名空间
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 4 found
Loading history...
997
     * @return mixed
998
     */
999
    public static function factory(string $name, string $namespace = '', ...$args)
1000
    {
1001
        $class = false !== strpos($name, '\\') ? $name : $namespace . ucwords($name);
1002
1003
        if (class_exists($class)) {
1004
            return Container::getInstance()->invokeClass($class, $args);
1005
        }
1006
1007
        throw new ClassNotFoundException('class not exists:' . $class, $class);
1008
    }
1009
1010
    public static function serialize($data): string
0 ignored issues
show
Coding Style introduced by
Missing function doc comment
Loading history...
1011
    {
1012
        SerializableClosure::enterContext();
1013
        SerializableClosure::wrapClosures($data);
1014
        $data = \serialize($data);
1015
        SerializableClosure::exitContext();
1016
        return $data;
1017
    }
1018
1019
    public static function unserialize(string $data)
0 ignored issues
show
Coding Style introduced by
Missing function doc comment
Loading history...
1020
    {
1021
        SerializableClosure::enterContext();
1022
        $data = \unserialize($data);
1023
        SerializableClosure::unwrapClosures($data);
1024
        SerializableClosure::exitContext();
1025
        return $data;
1026
    }
1027
}
1028