Passed
Push — 5.2 ( 800eb7...a4e475 )
by liu
02:54
created

App::getRootPath()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

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

584
        date_default_timezone_set(/** @scrutinizer ignore-type */ $this->config->get('app.default_timezone', 'Asia/Shanghai'));
Loading history...
585
586
        // 设置开启事件机制
587
        $this->event->withEvent($this->withEvent);
588
589
        return $this;
590
    }
591
592
    protected function debugModeInit(): void
0 ignored issues
show
Coding Style introduced by
Missing function doc comment
Loading history...
593
    {
594
        // 应用调试模式
595
        if (!$this->appDebug) {
596
            $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...
597
        }
598
599
        if (!$this->appDebug) {
600
            ini_set('display_errors', 'Off');
601
        } elseif (PHP_SAPI != 'cli') {
602
            //重新申请一块比较大的buffer
603
            if (ob_get_level() > 0) {
604
                $output = ob_get_clean();
605
            }
606
            ob_start();
607
            if (!empty($output)) {
608
                echo $output;
609
            }
610
        }
611
    }
612
613
    protected function setDependPath(): void
0 ignored issues
show
Coding Style introduced by
Missing function doc comment
Loading history...
614
    {
615
        if ($this->multi) {
616
            $this->namespace = null;
617
            $this->appPath   = null;
618
619
            $path = $this->request->path();
620
621
            if ($this->auto && $path) {
622
                $name = current(explode('/', $path));
623
624
                if (isset($this->map[$name]) && $this->map[$name] instanceof \Closure) {
625
                    call_user_func_array($this->map[$name], [$this]);
626
                } elseif ($name) {
627
                    $this->name = $this->map[$name] ?? $name;
628
                } else {
629
                    $this->name = $this->defaultApp;
630
                }
631
            } else {
632
                $this->name = $this->name ?: $this->getScriptName();
633
            }
634
635
            $this->runtimePath = $this->rootPath . 'runtime' . DIRECTORY_SEPARATOR . $this->name . DIRECTORY_SEPARATOR;
636
            $this->routePath   = $this->rootPath . 'route' . DIRECTORY_SEPARATOR . $this->name . DIRECTORY_SEPARATOR;
637
        } else {
638
            $this->runtimePath = $this->rootPath . 'runtime' . DIRECTORY_SEPARATOR;
639
            $this->routePath   = $this->rootPath . 'route' . DIRECTORY_SEPARATOR;
640
        }
641
642
        if (!$this->appPath) {
643
            $this->appPath = $this->multi ? $this->basePath . $this->name . DIRECTORY_SEPARATOR : $this->basePath;
644
        }
645
646
        if (!$this->namespace) {
647
            $this->namespace = $this->multi ? $this->rootNamespace . '\\' . $this->name : $this->rootNamespace;
648
        }
649
650
        $this->configPath = $this->rootPath . 'config' . DIRECTORY_SEPARATOR;
651
652
        $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...
653
            'think_path'   => $this->thinkPath,
654
            'root_path'    => $this->rootPath,
655
            'app_path'     => $this->appPath,
656
            'runtime_path' => $this->runtimePath,
657
            'route_path'   => $this->routePath,
658
            'config_path'  => $this->configPath,
659
        ]);
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...
660
    }
661
662
    /**
663
     * 初始化应用
664
     * @access public
665
     * @return void
666
     */
667
    public function init(): void
668
    {
669
        // 加载初始化文件
670
        if (is_file($this->runtimePath . 'init.php')) {
671
            include $this->runtimePath . 'init.php';
672
        } else {
673
            $this->loadAppFile();
674
        }
675
676
        $this->request->setApp($this->name ?: '');
677
678
        // 监听AppInit
679
        $this->event->trigger('AppInit');
680
    }
681
682
    /**
683
     * 加载应用文件和配置
684
     * @access protected
685
     * @return void
686
     */
687
    protected function loadAppFile(): void
688
    {
689
        if ($this->multi && is_file($this->basePath . 'event.php')) {
690
            $this->loadEvent(include $this->basePath . 'event.php');
691
        }
692
693
        if (is_file($this->appPath . 'event.php')) {
694
            $this->loadEvent(include $this->appPath . 'event.php');
695
        }
696
697
        if ($this->multi && is_file($this->basePath . 'common.php')) {
698
            include_once $this->basePath . 'common.php';
699
        }
700
701
        if (is_file($this->appPath . 'common.php')) {
702
            include_once $this->appPath . 'common.php';
703
        }
704
705
        include $this->thinkPath . 'helper.php';
706
707
        if ($this->multi && is_file($this->basePath . 'middleware.php')) {
708
            $this->middleware->import(include $this->basePath . 'middleware.php');
709
        }
710
711
        if (is_file($this->appPath . 'middleware.php')) {
712
            $this->middleware->import(include $this->appPath . 'middleware.php');
713
        }
714
715
        if ($this->multi && is_file($this->basePath . 'provider.php')) {
716
            $this->bind(include $this->basePath . 'provider.php');
717
        }
718
719
        if (is_file($this->appPath . 'provider.php')) {
720
            $this->bind(include $this->appPath . 'provider.php');
721
        }
722
723
        $files = [];
724
725
        if (is_dir($this->configPath)) {
726
            $files = glob($this->configPath . '*' . $this->configExt);
727
        }
728
729
        if ($this->multi) {
730
            if (is_dir($this->appPath . 'config')) {
731
                $files = array_merge($files, glob($this->appPath . 'config' . DIRECTORY_SEPARATOR . '*' . $this->configExt));
732
            } elseif (is_dir($this->configPath . $this->name)) {
733
                $files = array_merge($files, glob($this->configPath . $this->name . DIRECTORY_SEPARATOR . '*' . $this->configExt));
734
            }
735
        }
736
737
        foreach ($files as $file) {
738
            $this->config->load($file, pathinfo($file, PATHINFO_FILENAME));
739
        }
740
    }
741
742
    protected function loadEvent(array $event): void
0 ignored issues
show
Coding Style introduced by
Missing function doc comment
Loading history...
743
    {
744
        if (isset($event['bind'])) {
745
            $this->event->bind($event['bind']);
746
        }
747
748
        if (isset($event['listen'])) {
749
            $this->event->listenEvents($event['listen']);
750
        }
751
752
        if (isset($event['subscribe'])) {
753
            $this->event->subscribe($event['subscribe']);
754
        }
755
    }
756
757
    public function getRealPath()
0 ignored issues
show
Coding Style introduced by
Missing function doc comment
Loading history...
758
    {
759
        $path = $this->request->path();
760
761
        if ($path && $this->auto) {
762
            $path = substr_replace($path, '', 0, strpos($path, '/') ? strpos($path, '/') + 1 : strlen($path));
763
        }
764
765
        return $path;
766
    }
767
768
    /**
769
     * 执行应用程序
770
     * @access public
771
     * @return Response
772
     * @throws Exception
773
     */
774
    public function run(): Response
775
    {
776
        try {
777
            if ($this->withRoute) {
778
                $dispatch = $this->routeCheck()->init();
779
            } else {
780
                $dispatch = $this->route->url($this->getRealPath())->init();
781
            }
782
783
            // 监听AppBegin
784
            $this->event->trigger('AppBegin');
785
786
            $data = null;
787
        } catch (HttpResponseException $exception) {
788
            $dispatch = null;
789
            $data     = $exception->getResponse();
790
        }
791
792
        $this->middleware->add(function (Request $request, $next) use ($dispatch, $data) {
0 ignored issues
show
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

792
        $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...
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

792
        $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...
Coding Style introduced by
The opening parenthesis of a multi-line function call should be the last content on the line.
Loading history...
793
            return is_null($data) ? $dispatch->run() : $data;
794
        });
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...
795
796
        $response = $this->middleware->dispatch($this->request);
797
798
        // 监听AppEnd
799
        $this->event->trigger('AppEnd', $response);
800
801
        return $response;
802
    }
803
804
    /**
805
     * 实例化访问控制器 格式:控制器名
806
     * @access public
807
     * @param  string $name              资源地址
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 14 found
Loading history...
808
     * @return object
809
     * @throws ClassNotFoundException
810
     */
811
    public function controller(string $name)
812
    {
813
        $suffix = $this->controllerSuffix ? 'Controller' : '';
814
        $class  = $this->parseClass($this->controllerLayer, $name . $suffix);
815
816
        if (class_exists($class)) {
817
            return $this->make($class, [], true);
818
        } elseif ($this->emptyController && class_exists($emptyClass = $this->parseClass($this->controllerLayer, $this->emptyController . $suffix))) {
819
            return $this->make($emptyClass, [], true);
820
        }
821
822
        throw new ClassNotFoundException('class not exists:' . $class, $class);
823
    }
824
825
    /**
826
     * 解析应用类的类名
827
     * @access public
828
     * @param  string $layer  层名 controller model ...
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 2 found
Loading history...
829
     * @param  string $name   类名
0 ignored issues
show
Coding Style introduced by
Expected 2 spaces after parameter name; 3 found
Loading history...
830
     * @return string
831
     */
832
    public function parseClass(string $layer, string $name): string
833
    {
834
        $name  = str_replace(['/', '.'], '\\', $name);
835
        $array = explode('\\', $name);
836
        $class = self::parseName(array_pop($array), 1);
837
        $path  = $array ? implode('\\', $array) . '\\' : '';
838
839
        return $this->namespace . '\\' . $layer . '\\' . $path . $class;
840
    }
841
842
    // 获取应用根目录
843
    public function getDefaultRootPath(): string
0 ignored issues
show
Coding Style introduced by
You must use "/**" style comments for a function comment
Loading history...
844
    {
845
        $path = dirname(dirname(dirname(dirname($this->thinkPath))));
846
847
        return $path . DIRECTORY_SEPARATOR;
848
    }
849
850
    /**
851
     * 路由初始化(路由规则注册)
852
     * @access protected
853
     * @return void
854
     */
855
    protected function routeInit(): void
856
    {
857
        // 加载路由定义
858
        if (is_dir($this->routePath)) {
859
            $files = glob($this->routePath . DIRECTORY_SEPARATOR . '*.php');
860
            foreach ($files as $file) {
861
                include $file;
862
            }
863
        }
864
865
        if ($this->route->config('route_annotation')) {
866
            // 自动生成注解路由定义
867
            if ($this->isDebug()) {
868
                $this->build->buildRoute();
869
            }
870
871
            $filename = $this->runtimePath . 'build_route.php';
872
873
            if (is_file($filename)) {
874
                include $filename;
875
            }
876
        }
877
    }
878
879
    /**
880
     * URL路由检测(根据PATH_INFO)
881
     * @access protected
882
     * @return Dispatch
883
     */
884
    protected function routeCheck(): Dispatch
885
    {
886
        // 检测路由缓存
887
        if (!$this->isDebug() && $this->route->config('route_check_cache')) {
888
            $routeKey = $this->getRouteCacheKey();
889
            $option   = $this->route->config('route_cache_option');
890
891
            if ($option && $this->cache->connect($option)->has($routeKey)) {
892
                return $this->cache->connect($option)->get($routeKey);
893
            } elseif ($this->cache->has($routeKey)) {
894
                return $this->cache->get($routeKey);
895
            }
896
        }
897
898
        $this->routeInit();
899
900
        // 路由检测
901
        $dispatch = $this->route->check($this->getRealPath());
902
903
        if (!empty($routeKey)) {
904
            try {
905
                if (!empty($option)) {
906
                    $this->cache->connect($option)->tag('route_cache')->set($routeKey, $dispatch);
907
                } else {
908
                    $this->cache->tag('route_cache')->set($routeKey, $dispatch);
909
                }
910
            } catch (\Exception $e) {
911
                // 存在闭包的时候缓存无效
912
            }
913
        }
914
915
        return $dispatch;
916
    }
917
918
    protected function getRouteCacheKey(): string
0 ignored issues
show
Coding Style introduced by
Missing function doc comment
Loading history...
919
    {
920
        if ($this->route->config('route_check_cache_key')) {
921
            $closure  = $this->route->config('route_check_cache_key');
922
            $routeKey = $closure($this->request);
923
        } else {
924
            $routeKey = md5($this->request->baseUrl(true) . ':' . $this->request->method());
925
        }
926
927
        return $routeKey;
928
    }
929
930
    protected function getScriptName(): string
0 ignored issues
show
Coding Style introduced by
Missing function doc comment
Loading history...
931
    {
932
        if (isset($_SERVER['SCRIPT_FILENAME'])) {
933
            $file = $_SERVER['SCRIPT_FILENAME'];
934
        } elseif (isset($_SERVER['argv'][0])) {
935
            $file = realpath($_SERVER['argv'][0]);
936
        }
937
938
        return isset($file) ? pathinfo($file, PATHINFO_FILENAME) : $this->defaultApp;
939
    }
940
941
    /**
942
     * 字符串命名风格转换
943
     * type 0 将Java风格转换为C的风格 1 将C风格转换为Java的风格
944
     * @access public
945
     * @param  string  $name 字符串
0 ignored issues
show
Coding Style introduced by
Expected 4 spaces after parameter name; 1 found
Loading history...
946
     * @param  integer $type 转换类型
0 ignored issues
show
Coding Style introduced by
Expected 4 spaces after parameter name; 1 found
Loading history...
947
     * @param  bool    $ucfirst 首字母是否大写(驼峰规则)
948
     * @return string
949
     */
950
    public static function parseName(string $name = null, int $type = 0, bool $ucfirst = true): string
951
    {
952
        if ($type) {
953
            $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...
954
                return strtoupper($match[1]);
955
            }, $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...
956
            return $ucfirst ? ucfirst($name) : lcfirst($name);
957
        }
958
959
        return strtolower(trim(preg_replace("/[A-Z]/", "_\\0", $name), "_"));
960
    }
961
962
    /**
963
     * 获取类名(不包含命名空间)
964
     * @access public
965
     * @param  string|object $class
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
966
     * @return string
967
     */
968
    public static function classBaseName($class): string
969
    {
970
        $class = is_object($class) ? get_class($class) : $class;
971
        return basename(str_replace('\\', '/', $class));
972
    }
973
974
    /**
0 ignored issues
show
Coding Style introduced by
Parameter ...$args should have a doc-comment as per coding-style.
Loading history...
975
     * 创建工厂对象实例
976
     * @access public
977
     * @param  string $name         工厂类名
0 ignored issues
show
Coding Style introduced by
Expected 6 spaces after parameter name; 9 found
Loading history...
978
     * @param  string $namespace    默认命名空间
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 4 found
Loading history...
979
     * @return mixed
980
     */
981
    public static function factory(string $name, string $namespace = '', ...$args)
982
    {
983
        $class = false !== strpos($name, '\\') ? $name : $namespace . ucwords($name);
984
985
        if (class_exists($class)) {
986
            return Container::getInstance()->invokeClass($class, $args);
987
        }
988
989
        throw new ClassNotFoundException('class not exists:' . $class, $class);
990
    }
991
992
    public static function serialize($data): string
0 ignored issues
show
Coding Style introduced by
Missing function doc comment
Loading history...
993
    {
994
        SerializableClosure::enterContext();
995
        SerializableClosure::wrapClosures($data);
996
        $data = \serialize($data);
997
        SerializableClosure::exitContext();
998
        return $data;
999
    }
1000
1001
    public static function unserialize(string $data)
0 ignored issues
show
Coding Style introduced by
Missing function doc comment
Loading history...
1002
    {
1003
        SerializableClosure::enterContext();
1004
        $data = \unserialize($data);
1005
        SerializableClosure::unwrapClosures($data);
1006
        SerializableClosure::exitContext();
1007
        return $data;
1008
    }
1009
}
1010