Passed
Push — 5.2 ( 998c15...800eb7 )
by liu
03:18
created

App::setDependPath()   C

Complexity

Conditions 12
Paths 45

Size

Total Lines 43
Code Lines 29

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 12
eloc 29
nc 45
nop 0
dl 0
loc 43
rs 6.9666
c 0
b 0
f 0

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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 $runtimePath = '';
109
110
    /**
111
     * 配置目录
112
     * @var string
113
     */
114
    protected $configPath = '';
115
116
    /**
117
     * 路由目录
118
     * @var string
119
     */
120
    protected $routePath = '';
121
122
    /**
123
     * 配置后缀
124
     * @var string
125
     */
126
    protected $configExt = '.php';
127
128
    /**
129
     * 初始化
130
     * @var bool
131
     */
132
    protected $initialized = false;
133
134
    /**
135
     * 是否为多应用模式
136
     * @var bool
137
     */
138
    protected $multi = false;
139
140
    /**
141
     * 是否为自动多应用
142
     * @var bool
143
     */
144
    protected $auto = false;
145
146
    /**
147
     * 应用映射
148
     * @var array
149
     */
150
    protected $map = [];
151
152
    /**
153
     * 是否需要事件响应
154
     * @var bool
155
     */
156
    protected $withEvent = true;
157
158
    /**
159
     * 是否需要使用路由
160
     * @var bool
161
     */
162
    protected $withRoute = true;
163
164
    /**
165
     * 访问控制器层名称
166
     * @var string
167
     */
168
    protected $controllerLayer = 'controller';
169
170
    /**
171
     * 是否使用控制器类库后缀
172
     * @var bool
173
     */
174
    protected $controllerSuffix = false;
175
176
    /**
177
     * 空控制器名称
178
     * @var string
179
     */
180
    protected $emptyController = 'Error';
181
182
    /**
183
     * 架构方法
184
     * @access public
185
     * @param  string $rootPath 应用根目录
186
     */
187
    public function __construct(string $rootPath = '')
188
    {
189
        $this->thinkPath = dirname(__DIR__) . DIRECTORY_SEPARATOR;
190
        $this->rootPath  = $rootPath ? realpath($rootPath) . DIRECTORY_SEPARATOR : $this->getDefaultRootPath();
191
        $this->basePath  = $this->rootPath . 'app' . DIRECTORY_SEPARATOR;
192
193
        $this->multi = is_dir($this->basePath . 'controller') ? false : true;
194
195
        static::setInstance($this);
196
197
        $this->instance('app', $this);
198
199
        // 注册错误和异常处理机制
200
        Error::register();
201
    }
202
203
    /**
204
     * 自动多应用访问
205
     * @access public
206
     * @param  array $map 应用路由映射
207
     * @return $this
208
     */
209
    public function autoMulti(array $map = [])
210
    {
211
        $this->multi = true;
212
        $this->auto  = true;
213
        $this->map   = $map;
214
215
        return $this;
216
    }
217
218
    /**
219
     * 是否为自动多应用模式
220
     * @access public
221
     * @return bool
222
     */
223
    public function isAutoMulti(): bool
224
    {
225
        return $this->auto;
226
    }
227
228
    /**
229
     * 设置应用模式
230
     * @access public
231
     * @param  bool $multi
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
232
     * @return $this
233
     */
234
    public function multi(bool $multi)
235
    {
236
        $this->multi = $multi;
237
        return $this;
238
    }
239
240
    /**
241
     * 是否为多应用模式
242
     * @access public
243
     * @return bool
244
     */
245
    public function isMulti(): bool
246
    {
247
        return $this->multi;
248
    }
249
250
    /**
251
     * 设置是否使用事件机制
252
     * @access public
253
     * @param  bool $event
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
254
     * @return $this
255
     */
256
    public function withEvent(bool $event)
257
    {
258
        $this->withEvent = $event;
259
        return $this;
260
    }
261
262
    /**
263
     * 设置是否使用路由
264
     * @access public
265
     * @param  bool $route
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
266
     * @return $this
267
     */
268
    public function withRoute(bool $route)
269
    {
270
        $this->withRoute = $route;
271
        return $this;
272
    }
273
274
    /**
275
     * 设置应用路径
276
     * @access public
277
     * @param  string $path 应用目录
278
     * @return $this
279
     */
280
    public function path(string $path)
281
    {
282
        $this->appPath = $path;
283
        return $this;
284
    }
285
286
    /**
287
     * 开启应用调试模式
288
     * @access public
289
     * @param  bool $debug 开启应用调试模式
290
     * @return $this
291
     */
292
    public function debug(bool $debug = true)
293
    {
294
        $this->appDebug = $debug;
295
        return $this;
296
    }
297
298
    /**
299
     * 是否为调试模式
300
     * @access public
301
     * @return bool
302
     */
303
    public function isDebug(): bool
304
    {
305
        return $this->appDebug;
306
    }
307
308
    /**
309
     * 设置应用名称
310
     * @access public
311
     * @param  string $name 应用名称
312
     * @return $this
313
     */
314
    public function name(string $name)
315
    {
316
        $this->name = $name;
317
        return $this;
318
    }
319
320
    /**
321
     * 设置控制器层名称
322
     * @access public
323
     * @param  string $layer 控制器层名称
324
     * @return $this
325
     */
326
    public function controllerLayer(string $layer)
327
    {
328
        $this->controllerLayer = $layer;
329
        return $this;
330
    }
331
332
    /**
333
     * 设置空控制器名称
334
     * @access public
335
     * @param  string $empty 空控制器名称
336
     * @return $this
337
     */
338
    public function emptyController(string $empty)
339
    {
340
        $this->emptyController = $empty;
341
        return $this;
342
    }
343
344
    /**
345
     * 设置应用命名空间
346
     * @access public
347
     * @param  string $namespace 应用命名空间
348
     * @return $this
349
     */
350
    public function setNamespace(string $namespace)
351
    {
352
        $this->namespace = $namespace;
353
        return $this;
354
    }
355
356
    /**
357
     * 设置应用根命名空间
358
     * @access public
359
     * @param  string $rootNamespace 应用命名空间
360
     * @return $this
361
     */
362
    public function setRootNamespace(string $rootNamespace)
363
    {
364
        $this->rootNamespace = $rootNamespace;
365
        return $this;
366
    }
367
368
    /**
369
     * 设置是否启用控制器类库后缀
370
     * @access public
371
     * @param  bool  $suffix 启用控制器类库后缀
372
     * @return $this
373
     */
374
    public function controllerSuffix(bool $suffix = true)
375
    {
376
        $this->controllerSuffix = $suffix;
377
        return $this;
378
    }
379
380
    /**
381
     * 获取框架版本
382
     * @access public
383
     * @return string
384
     */
385
    public function version(): string
386
    {
387
        return static::VERSION;
388
    }
389
390
    /**
391
     * 获取应用名称
392
     * @access public
393
     * @return string
394
     */
395
    public function getName(): string
396
    {
397
        return $this->name ?: '';
398
    }
399
400
    /**
401
     * 获取应用根目录
402
     * @access public
403
     * @return string
404
     */
405
    public function getRootPath(): string
406
    {
407
        return $this->rootPath;
408
    }
409
410
    /**
411
     * 获取应用基础目录
412
     * @access public
413
     * @return string
414
     */
415
    public function getBasePath(): string
416
    {
417
        return $this->basePath;
418
    }
419
420
    /**
421
     * 获取当前应用目录
422
     * @access public
423
     * @return string
424
     */
425
    public function getAppPath(): string
426
    {
427
        return $this->appPath;
428
    }
429
430
    /**
431
     * 获取应用运行时目录
432
     * @access public
433
     * @return string
434
     */
435
    public function getRuntimePath(): string
436
    {
437
        return $this->runtimePath;
438
    }
439
440
    /**
441
     * 获取核心框架目录
442
     * @access public
443
     * @return string
444
     */
445
    public function getThinkPath(): string
446
    {
447
        return $this->thinkPath;
448
    }
449
450
    /**
451
     * 获取路由目录
452
     * @access public
453
     * @return string
454
     */
455
    public function getRoutePath(): string
456
    {
457
        return $this->routePath;
458
    }
459
460
    /**
461
     * 获取应用配置目录
462
     * @access public
463
     * @return string
464
     */
465
    public function getConfigPath(): string
466
    {
467
        return $this->configPath;
468
    }
469
470
    /**
471
     * 获取配置后缀
472
     * @access public
473
     * @return string
474
     */
475
    public function getConfigExt(): string
476
    {
477
        return $this->configExt;
478
    }
479
480
    /**
481
     * 获取应用类基础命名空间
482
     * @access public
483
     * @return string
484
     */
485
    public function getRootNamespace(): string
486
    {
487
        return $this->rootNamespace;
488
    }
489
490
    /**
491
     * 获取应用类库命名空间
492
     * @access public
493
     * @return string
494
     */
495
    public function getNamespace(): string
496
    {
497
        return $this->namespace;
498
    }
499
500
    /**
501
     * 是否启用控制器类库后缀
502
     * @access public
503
     * @return bool
504
     */
505
    public function hasControllerSuffix(): bool
506
    {
507
        return $this->controllerSuffix;
508
    }
509
510
    /**
511
     * 获取应用开启时间
512
     * @access public
513
     * @return float
514
     */
515
    public function getBeginTime(): float
516
    {
517
        return $this->beginTime;
518
    }
519
520
    /**
521
     * 获取应用初始内存占用
522
     * @access public
523
     * @return integer
524
     */
525
    public function getBeginMem(): int
526
    {
527
        return $this->beginMem;
528
    }
529
530
    /**
531
     * 获取控制器层名称
532
     * @access public
533
     * @return string
534
     */
535
    public function getControllerLayer(): string
536
    {
537
        return $this->controllerLayer;
538
    }
539
540
    /**
541
     * 初始化应用
542
     * @access public
543
     * @return $this
544
     */
545
    public function initialize()
546
    {
547
        $this->beginTime = microtime(true);
548
        $this->beginMem  = memory_get_usage();
549
550
        if (is_file($this->rootPath . '.env')) {
551
            $this->env->load($this->rootPath . '.env');
552
        }
553
554
        $this->setDependPath();
555
556
        $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...
557
558
        $this->init();
559
560
        $this->debugModeInit();
561
562
        if ($this->config->get('app.exception_handle')) {
563
            Error::setExceptionHandler($this->config->get('app.exception_handle'));
564
        }
565
566
        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

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

771
        $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

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