Passed
Push — 6.0 ( 13ba92...b35061 )
by liu
02:31
created

App::debugModeInit()   B

Complexity

Conditions 7
Paths 18

Size

Total Lines 17
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 7
eloc 10
nc 18
nop 0
dl 0
loc 17
rs 8.8333
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\initializer\BootService;
18
use think\initializer\Error;
19
use think\initializer\RegisterService;
20
21
/**
22
 * App 基础类
23
 */
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...
24
class App extends Container
25
{
26
    const VERSION = '6.0.0RC1';
27
28
    /**
29
     * 应用调试模式
30
     * @var bool
31
     */
32
    protected $appDebug = true;
33
34
    /**
35
     * 应用开始时间
36
     * @var float
37
     */
38
    protected $beginTime;
39
40
    /**
41
     * 应用内存初始占用
42
     * @var integer
43
     */
44
    protected $beginMem;
45
46
    /**
47
     * 当前应用类库命名空间
48
     * @var string
49
     */
50
    protected $namespace = 'app';
51
52
    /**
53
     * 应用根目录
54
     * @var string
55
     */
56
    protected $rootPath = '';
57
58
    /**
59
     * 框架目录
60
     * @var string
61
     */
62
    protected $thinkPath = '';
63
64
    /**
65
     * 应用目录
66
     * @var string
67
     */
68
    protected $appPath = '';
69
70
    /**
71
     * Runtime目录
72
     * @var string
73
     */
74
    protected $runtimePath = '';
75
76
    /**
77
     * 配置后缀
78
     * @var string
79
     */
80
    protected $configExt = '.php';
81
82
    /**
83
     * 应用初始化器
84
     * @var array
85
     */
86
    protected $initializers = [
87
        Error::class,
88
        RegisterService::class,
89
        BootService::class,
90
    ];
91
92
    /**
93
     * 注册的系统服务
94
     * @var array
95
     */
96
    protected $services = [];
97
98
    /**
99
     * 初始化
100
     * @var bool
101
     */
102
    protected $initialized = false;
103
104
    /**
105
     * 架构方法
106
     * @access public
107
     * @param string $rootPath 应用根目录
1 ignored issue
show
Coding Style introduced by
Tag value indented incorrectly; expected 2 spaces but found 1
Loading history...
108
     */
109
    public function __construct(string $rootPath = '')
110
    {
111
        $this->thinkPath   = dirname(__DIR__) . DIRECTORY_SEPARATOR;
112
        $this->rootPath    = $rootPath ? realpath($rootPath) . DIRECTORY_SEPARATOR : $this->getDefaultRootPath();
113
        $this->appPath     = $this->rootPath . 'app' . DIRECTORY_SEPARATOR;
114
        $this->runtimePath = $this->rootPath . 'runtime' . DIRECTORY_SEPARATOR;
115
116
        static::setInstance($this);
117
118
        $this->instance('app', $this);
119
        $this->instance('think\Container', $this);
120
    }
121
122
    /**
123
     * 注册服务
124
     * @access public
125
     * @param Service|string $service 服务
1 ignored issue
show
Coding Style introduced by
Tag value indented incorrectly; expected 2 spaces but found 1
Loading history...
126
     * @param bool           $force   强制重新注册
1 ignored issue
show
Coding Style introduced by
Tag value indented incorrectly; expected 2 spaces but found 1
Loading history...
127
     * @return Service|null
128
     */
129
    public function register($service, bool $force = false)
130
    {
131
        $registered = $this->getService($service);
132
133
        if ($registered && !$force) {
134
            return $registered;
135
        }
136
137
        if (is_string($service)) {
138
            $service = new $service($this);
139
        }
140
141
        if (method_exists($service, 'register')) {
142
            $service->register();
143
        }
144
145
        $this->services[] = $service;
146
    }
147
148
    /**
149
     * 执行服务
150
     * @access public
151
     * @param Service $service 服务
1 ignored issue
show
Coding Style introduced by
Tag value indented incorrectly; expected 2 spaces but found 1
Loading history...
152
     * @return mixed
153
     */
154
    public function bootService($service)
155
    {
156
        if (method_exists($service, 'boot')) {
157
            return $this->invoke([$service, 'boot']);
158
        }
159
    }
160
161
    /**
162
     * 获取服务
163
     * @param string|Service $service
1 ignored issue
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Tag value indented incorrectly; expected 2 spaces but found 1
Loading history...
164
     * @return Service|null
165
     */
166
    public function getService($service)
167
    {
168
        $name = is_string($service) ? $service : get_class($service);
169
        return array_values(array_filter($this->services, function ($value) use ($name) {
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...
170
            return $value instanceof $name;
171
        }, ARRAY_FILTER_USE_BOTH))[0] ?? null;
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...
172
    }
173
174
    /**
175
     * 开启应用调试模式
176
     * @access public
177
     * @param bool $debug 开启应用调试模式
1 ignored issue
show
Coding Style introduced by
Tag value indented incorrectly; expected 2 spaces but found 1
Loading history...
178
     * @return $this
179
     */
180
    public function debug(bool $debug = true)
181
    {
182
        $this->appDebug = $debug;
183
        return $this;
184
    }
185
186
    /**
187
     * 是否为调试模式
188
     * @access public
189
     * @return bool
190
     */
191
    public function isDebug(): bool
192
    {
193
        return $this->appDebug;
194
    }
195
196
    /**
197
     * 设置应用命名空间
198
     * @access public
199
     * @param string $namespace 应用命名空间
1 ignored issue
show
Coding Style introduced by
Tag value indented incorrectly; expected 2 spaces but found 1
Loading history...
200
     * @return $this
201
     */
202
    public function setNamespace(string $namespace)
203
    {
204
        $this->namespace = $namespace;
205
        return $this;
206
    }
207
208
    /**
209
     * 获取应用类库命名空间
210
     * @access public
211
     * @return string
212
     */
213
    public function getNamespace(): string
214
    {
215
        return $this->namespace;
216
    }
217
218
    /**
219
     * 获取框架版本
220
     * @access public
221
     * @return string
222
     */
223
    public function version(): string
224
    {
225
        return static::VERSION;
226
    }
227
228
    /**
229
     * 获取应用根目录
230
     * @access public
231
     * @return string
232
     */
233
    public function getRootPath(): string
234
    {
235
        return $this->rootPath;
236
    }
237
238
    /**
239
     * 获取应用基础目录
240
     * @access public
241
     * @return string
242
     */
243
    public function getBasePath(): string
244
    {
245
        return $this->rootPath . 'app' . DIRECTORY_SEPARATOR;
246
    }
247
248
    /**
249
     * 获取当前应用目录
250
     * @access public
251
     * @return string
252
     */
253
    public function getAppPath(): string
254
    {
255
        return $this->appPath;
256
    }
257
258
    /**
0 ignored issues
show
Coding Style introduced by
Parameter $path should have a doc-comment as per coding-style.
Loading history...
259
     * 设置应用目录
260
     * @param $path
0 ignored issues
show
Coding Style Documentation introduced by
Missing parameter name
Loading history...
261
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
262
    public function setAppPath($path)
263
    {
264
        $this->appPath = $path;
265
    }
266
267
    /**
268
     * 获取应用运行时目录
269
     * @access public
270
     * @return string
271
     */
272
    public function getRuntimePath(): string
273
    {
274
        return $this->runtimePath;
275
    }
276
277
    /**
0 ignored issues
show
Coding Style introduced by
Parameter $path should have a doc-comment as per coding-style.
Loading history...
278
     * 设置runtime目录
279
     * @param $path
0 ignored issues
show
Coding Style Documentation introduced by
Missing parameter name
Loading history...
280
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
281
    public function setRuntimePath($path)
282
    {
283
        $this->runtimePath = $path;
284
    }
285
286
    /**
287
     * 获取核心框架目录
288
     * @access public
289
     * @return string
290
     */
291
    public function getThinkPath(): string
292
    {
293
        return $this->thinkPath;
294
    }
295
296
    /**
297
     * 获取应用配置目录
298
     * @access public
299
     * @return string
300
     */
301
    public function getConfigPath(): string
302
    {
303
        return $this->rootPath . 'config' . DIRECTORY_SEPARATOR;
304
    }
305
306
    /**
307
     * 获取配置后缀
308
     * @access public
309
     * @return string
310
     */
311
    public function getConfigExt(): string
312
    {
313
        return $this->configExt;
314
    }
315
316
    /**
317
     * 获取应用开启时间
318
     * @access public
319
     * @return float
320
     */
321
    public function getBeginTime(): float
322
    {
323
        return $this->beginTime;
324
    }
325
326
    /**
327
     * 获取应用初始内存占用
328
     * @access public
329
     * @return integer
330
     */
331
    public function getBeginMem(): int
332
    {
333
        return $this->beginMem;
334
    }
335
336
    /**
337
     * 初始化应用
338
     * @access public
339
     * @return $this
340
     */
341
    public function initialize()
342
    {
343
        $this->initialized = true;
344
345
        $this->beginTime = microtime(true);
346
        $this->beginMem  = memory_get_usage();
347
348
        // 加载环境变量
349
        if (is_file($this->rootPath . '.env')) {
350
            $this->env->load($this->rootPath . '.env');
351
        }
352
353
        $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...
354
355
        // 加载全局初始化文件
356
        if (is_file($this->getRuntimePath() . 'init.php')) {
357
            //直接加载缓存
358
            include $this->getRuntimePath() . 'init.php';
359
        } else {
360
            $this->load();
361
        }
362
363
        $this->debugModeInit();
364
365
        // 监听AppInit
366
        $this->app->event->trigger('AppInit');
0 ignored issues
show
Bug Best Practice introduced by
The property app does not exist on think\App. Since you implemented __get, consider adding a @property annotation.
Loading history...
367
368
        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

368
        date_default_timezone_set(/** @scrutinizer ignore-type */ $this->config->get('app.default_timezone', 'Asia/Shanghai'));
Loading history...
369
370
        // 初始化
371
        foreach ($this->initializers as $initializer) {
372
            $this->make($initializer)->init($this);
373
        }
374
375
        return $this;
376
    }
377
378
    /**
379
     * 是否初始化过
380
     * @return bool
381
     */
382
    public function initialized()
383
    {
384
        return $this->initialized;
385
    }
386
387
    /**
388
     * 引导应用
389
     * @access public
390
     * @return void
391
     */
392
    public function boot(): void
393
    {
394
        array_walk($this->services, function ($service) {
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...
395
            $this->bootService($service);
396
        });
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...
397
    }
398
399
    /**
400
     * 加载应用文件和配置
401
     * @access protected
402
     * @return void
403
     */
404
    protected function load(): void
405
    {
406
        $appPath = $this->getAppPath();
407
408
        if (is_file($appPath . 'common.php')) {
409
            include_once $appPath . 'common.php';
410
        }
411
412
        include $this->thinkPath . 'helper.php';
413
414
        $configPath = $this->getConfigPath();
415
416
        $files = [];
417
418
        if (is_dir($configPath)) {
419
            $files = glob($configPath . '*' . $this->configExt);
420
        }
421
422
        foreach ($files as $file) {
423
            $this->config->load($file, pathinfo($file, PATHINFO_FILENAME));
424
        }
425
426
        if (is_file($appPath . 'event.php')) {
427
            $this->loadEvent(include $appPath . 'event.php');
428
        }
429
430
        if (is_file($appPath . 'middleware.php')) {
431
            $this->middleware->import(include $appPath . 'middleware.php');
432
        }
433
434
        if (is_file($appPath . 'provider.php')) {
435
            $this->bind(include $appPath . 'provider.php');
436
        }
437
    }
438
439
    /**
440
     * 调试模式设置
441
     * @access protected
442
     * @return void
443
     */
444
    protected function debugModeInit(): void
445
    {
446
        // 应用调试模式
447
        if (!$this->appDebug) {
448
            $this->appDebug = $this->env->get('app_debug') ? true : false;
449
        }
450
451
        if (!$this->appDebug) {
452
            ini_set('display_errors', 'Off');
453
        } elseif (!$this->runningInConsole()) {
454
            //重新申请一块比较大的buffer
455
            if (ob_get_level() > 0) {
456
                $output = ob_get_clean();
457
            }
458
            ob_start();
459
            if (!empty($output)) {
460
                echo $output;
461
            }
462
        }
463
    }
464
465
    /**
466
     * 注册应用事件
467
     * @access protected
468
     * @param array $event 事件数据
1 ignored issue
show
Coding Style introduced by
Tag value indented incorrectly; expected 2 spaces but found 1
Loading history...
469
     * @return void
470
     */
471
    public function loadEvent(array $event): void
472
    {
473
        if (isset($event['bind'])) {
474
            $this->event->bind($event['bind']);
475
        }
476
477
        if (isset($event['listen'])) {
478
            $this->event->listenEvents($event['listen']);
479
        }
480
481
        if (isset($event['subscribe'])) {
482
            $this->event->subscribe($event['subscribe']);
483
        }
484
    }
485
486
    /**
487
     * 解析应用类的类名
488
     * @access public
489
     * @param string $layer 层名 controller model ...
1 ignored issue
show
Coding Style introduced by
Tag value indented incorrectly; expected 2 spaces but found 1
Loading history...
490
     * @param string $name  类名
1 ignored issue
show
Coding Style introduced by
Tag value indented incorrectly; expected 2 spaces but found 1
Loading history...
491
     * @return string
492
     */
493
    public function parseClass(string $layer, string $name): string
494
    {
495
        $name  = str_replace(['/', '.'], '\\', $name);
496
        $array = explode('\\', $name);
497
        $class = self::parseName(array_pop($array), 1);
498
        $path  = $array ? implode('\\', $array) . '\\' : '';
499
500
        return $this->namespace . '\\' . $layer . '\\' . $path . $class;
501
    }
502
503
    /**
504
     * 是否运行在命令行下
505
     * @return bool
506
     */
507
    public function runningInConsole()
508
    {
509
        return php_sapi_name() === 'cli' || php_sapi_name() === 'phpdbg';
510
    }
511
512
    /**
513
     * 获取应用根目录
514
     * @access protected
515
     * @return string
516
     */
517
    protected function getDefaultRootPath(): string
518
    {
519
        $path = dirname(dirname(dirname(dirname($this->thinkPath))));
520
521
        return $path . DIRECTORY_SEPARATOR;
522
    }
523
524
    /**
525
     * 字符串命名风格转换
526
     * type 0 将Java风格转换为C的风格 1 将C风格转换为Java的风格
527
     * @access public
528
     * @param string  $name    字符串
1 ignored issue
show
Coding Style introduced by
Tag value indented incorrectly; expected 2 spaces but found 1
Loading history...
529
     * @param integer $type    转换类型
1 ignored issue
show
Coding Style introduced by
Tag value indented incorrectly; expected 2 spaces but found 1
Loading history...
530
     * @param bool    $ucfirst 首字母是否大写(驼峰规则)
1 ignored issue
show
Coding Style introduced by
Tag value indented incorrectly; expected 2 spaces but found 1
Loading history...
531
     * @return string
532
     */
533
    public static function parseName(string $name = null, int $type = 0, bool $ucfirst = true): string
534
    {
535
        if ($type) {
536
            $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...
537
                return strtoupper($match[1]);
538
            }, $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...
539
            return $ucfirst ? ucfirst($name) : lcfirst($name);
540
        }
541
542
        return strtolower(trim(preg_replace("/[A-Z]/", "_\\0", $name), "_"));
543
    }
544
545
    /**
546
     * 获取类名(不包含命名空间)
547
     * @access public
548
     * @param string|object $class
1 ignored issue
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Tag value indented incorrectly; expected 2 spaces but found 1
Loading history...
549
     * @return string
550
     */
551
    public static function classBaseName($class): string
552
    {
553
        $class = is_object($class) ? get_class($class) : $class;
554
        return basename(str_replace('\\', '/', $class));
555
    }
556
557
    /**
0 ignored issues
show
Coding Style introduced by
Parameter ...$args should have a doc-comment as per coding-style.
Loading history...
558
     * 创建工厂对象实例
559
     * @access public
560
     * @param string $name      工厂类名
1 ignored issue
show
Coding Style introduced by
Tag value indented incorrectly; expected 2 spaces but found 1
Loading history...
561
     * @param string $namespace 默认命名空间
1 ignored issue
show
Coding Style introduced by
Tag value indented incorrectly; expected 2 spaces but found 1
Loading history...
562
     * @return mixed
563
     */
564
    public static function factory(string $name, string $namespace = '', ...$args)
565
    {
566
        $class = false !== strpos($name, '\\') ? $name : $namespace . ucwords($name);
567
568
        if (class_exists($class)) {
569
            return Container::getInstance()->invokeClass($class, $args);
570
        }
571
572
        throw new ClassNotFoundException('class not exists:' . $class, $class);
573
    }
574
575
    public static function serialize($data): string
0 ignored issues
show
Coding Style introduced by
Missing function doc comment
Loading history...
576
    {
577
        SerializableClosure::enterContext();
578
        SerializableClosure::wrapClosures($data);
579
        $data = \serialize($data);
580
        SerializableClosure::exitContext();
581
        return $data;
582
    }
583
584
    public static function unserialize(string $data)
0 ignored issues
show
Coding Style introduced by
Missing function doc comment
Loading history...
585
    {
586
        SerializableClosure::enterContext();
587
        $data = \unserialize($data);
588
        SerializableClosure::unwrapClosures($data);
589
        SerializableClosure::exitContext();
590
        return $data;
591
    }
592
}
593