Passed
Push — 5.2 ( 5de8a0...f2908c )
by liu
02:29
created

App::run()   A

Complexity

Conditions 4
Paths 6

Size

Total Lines 28
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
eloc 15
nc 6
nop 0
dl 0
loc 28
rs 9.7666
c 0
b 0
f 0

3 Methods

Rating   Name   Duplication   Size   Complexity  
A App::getName() 0 3 2
A App::version() 0 3 1
A App::getRootPath() 0 3 1
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
18
/**
19
 * App 基础类
20
 */
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...
21
abstract class App extends Container
22
{
23
    const VERSION = '5.2.0RC1';
24
25
    /**
26
     * 应用名称
27
     * @var string
28
     */
29
    protected $name;
30
31
    /**
32
     * 应用调试模式
33
     * @var bool
34
     */
35
    protected $appDebug = true;
36
37
    /**
38
     * 应用映射
39
     * @var array
40
     */
41
    protected $map = [];
42
43
    /**
44
     * 应用开始时间
45
     * @var float
46
     */
47
    protected $beginTime;
48
49
    /**
50
     * 应用内存初始占用
51
     * @var integer
52
     */
53
    protected $beginMem;
54
55
    /**
56
     * 应用类库顶级命名空间
57
     * @var string
58
     */
59
    protected $rootNamespace = 'app';
60
61
    /**
62
     * 当前应用类库命名空间
63
     * @var string
64
     */
65
    protected $namespace = '';
66
67
    /**
68
     * 应用根目录
69
     * @var string
70
     */
71
    protected $rootPath = '';
72
73
    /**
74
     * 框架目录
75
     * @var string
76
     */
77
    protected $thinkPath = '';
78
79
    /**
80
     * 应用基础目录
81
     * @var string
82
     */
83
    protected $basePath = '';
84
85
    /**
86
     * 应用类库目录
87
     * @var string
88
     */
89
    protected $appPath = '';
90
91
    /**
92
     * 运行时目录
93
     * @var string
94
     */
95
    protected $runtimePath = '';
96
97
    /**
98
     * 配置目录
99
     * @var string
100
     */
101
    protected $configPath = '';
102
103
    /**
104
     * 配置后缀
105
     * @var string
106
     */
107
    protected $configExt = '.php';
108
109
    /**
110
     * 是否需要事件响应
111
     * @var bool
112
     */
113
    protected $withEvent = true;
114
115
    /**
116
     * 注册的系统服务
117
     * @var array
118
     */
119
    protected static $servicer = [
120
        Error::class,
121
    ];
122
123
    /**
124
     * 架构方法
125
     * @access public
126
     * @param  string $rootPath 应用根目录
127
     */
128
    public function __construct(string $rootPath = '')
129
    {
130
        $this->thinkPath = dirname(__DIR__) . DIRECTORY_SEPARATOR;
131
        $this->rootPath  = $rootPath ? realpath($rootPath) . DIRECTORY_SEPARATOR : $this->getDefaultRootPath();
132
        $this->basePath  = $this->rootPath . 'app' . DIRECTORY_SEPARATOR;
133
134
        static::setInstance($this);
135
136
        $this->instance('app', $this);
137
138
        // 注册系统服务
139
        foreach (self::$servicer as $servicer) {
140
            $this->make($servicer)->register($this);
141
        }
142
    }
143
144
    /**
145
     * 注册一个系统服务
146
     * @access public
147
     * @param  string $servicer
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
148
     * @return void
149
     */
150
    public static function service(string $servicer): void
151
    {
152
        self::$servicer[] = $servicer;
153
    }
154
155
    /**
156
     * 设置是否使用事件机制
157
     * @access public
158
     * @param  bool $event
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
159
     * @return $this
160
     */
161
    public function withEvent(bool $event)
162
    {
163
        $this->withEvent = $event;
164
        return $this;
165
    }
166
167
    /**
168
     * 设置应用路径
169
     * @access public
170
     * @param  string $path 应用目录
171
     * @return $this
172
     */
173
    public function path(string $path)
174
    {
175
        $this->appPath = $path;
176
        return $this;
177
    }
178
179
    /**
180
     * 开启应用调试模式
181
     * @access public
182
     * @param  bool $debug 开启应用调试模式
183
     * @return $this
184
     */
185
    public function debug(bool $debug = true)
186
    {
187
        $this->appDebug = $debug;
188
        return $this;
189
    }
190
191
    /**
192
     * 是否为调试模式
193
     * @access public
194
     * @return bool
195
     */
196
    public function isDebug(): bool
197
    {
198
        return $this->appDebug;
199
    }
200
201
    /**
202
     * 设置应用名称
203
     * @access public
204
     * @param  string $name 应用名称
205
     * @return $this
206
     */
207
    public function name(string $name)
208
    {
209
        $this->name = $name;
210
        return $this;
211
    }
212
213
    /**
214
     * 设置应用命名空间
215
     * @access public
216
     * @param  string $namespace 应用命名空间
217
     * @return $this
218
     */
219
    public function setNamespace(string $namespace)
220
    {
221
        $this->namespace = $namespace;
222
        return $this;
223
    }
224
225
    /**
226
     * 设置应用根命名空间
227
     * @access public
228
     * @param  string $rootNamespace 应用命名空间
229
     * @return $this
230
     */
231
    public function setRootNamespace(string $rootNamespace)
232
    {
233
        $this->rootNamespace = $rootNamespace;
234
        return $this;
235
    }
236
237
    /**
238
     * 获取框架版本
239
     * @access public
240
     * @return string
241
     */
242
    public function version(): string
243
    {
244
        return static::VERSION;
245
    }
246
247
    /**
248
     * 获取应用名称
249
     * @access public
250
     * @return string
251
     */
252
    public function getName(): string
253
    {
254
        return $this->name ?: '';
255
    }
256
257
    /**
258
     * 获取应用根目录
259
     * @access public
260
     * @return string
261
     */
262
    public function getRootPath(): string
263
    {
264
        return $this->rootPath;
265
    }
266
267
    /**
268
     * 获取应用基础目录
269
     * @access public
270
     * @return string
271
     */
272
    public function getBasePath(): string
273
    {
274
        return $this->basePath;
275
    }
276
277
    /**
278
     * 获取当前应用目录
279
     * @access public
280
     * @return string
281
     */
282
    public function getAppPath(): string
283
    {
284
        return $this->appPath;
285
    }
286
287
    /**
288
     * 获取应用运行时目录
289
     * @access public
290
     * @return string
291
     */
292
    public function getRuntimePath(): string
293
    {
294
        return $this->runtimePath;
295
    }
296
297
    /**
298
     * 获取核心框架目录
299
     * @access public
300
     * @return string
301
     */
302
    public function getThinkPath(): string
303
    {
304
        return $this->thinkPath;
305
    }
306
307
    /**
308
     * 获取应用配置目录
309
     * @access public
310
     * @return string
311
     */
312
    public function getConfigPath(): string
313
    {
314
        return $this->configPath;
315
    }
316
317
    /**
318
     * 获取配置后缀
319
     * @access public
320
     * @return string
321
     */
322
    public function getConfigExt(): string
323
    {
324
        return $this->configExt;
325
    }
326
327
    /**
328
     * 获取应用类基础命名空间
329
     * @access public
330
     * @return string
331
     */
332
    public function getRootNamespace(): string
333
    {
334
        return $this->rootNamespace;
335
    }
336
337
    /**
338
     * 获取应用类库命名空间
339
     * @access public
340
     * @return string
341
     */
342
    public function getNamespace(): string
343
    {
344
        return $this->namespace;
345
    }
346
347
    /**
348
     * 获取应用开启时间
349
     * @access public
350
     * @return float
351
     */
352
    public function getBeginTime(): float
353
    {
354
        return $this->beginTime;
355
    }
356
357
    /**
358
     * 获取应用初始内存占用
359
     * @access public
360
     * @return integer
361
     */
362
    public function getBeginMem(): int
363
    {
364
        return $this->beginMem;
365
    }
366
367
    /**
368
     * 初始化应用
369
     * @access public
370
     * @return $this
371
     */
372
    public function initialize()
373
    {
374
        $this->beginTime = microtime(true);
375
        $this->beginMem  = memory_get_usage();
376
377
        $this->parse();
378
379
        $this->init();
380
381
        return $this;
382
    }
383
384
    /**
385
     * 分析应用(参数)
386
     * @access protected
387
     * @return void
388
     */
389
    abstract protected function parse(): void;
390
391
    /**
392
     * 初始化应用
393
     * @access public
394
     * @return void
395
     */
396
    public function init(): void
397
    {
398
        // 加载初始化文件
399
        if (is_file($this->runtimePath . 'init.php')) {
400
            include $this->runtimePath . 'init.php';
401
        } else {
402
            $this->load();
403
        }
404
405
        // 设置开启事件机制
406
        $this->event->withEvent($this->withEvent);
0 ignored issues
show
Bug Best Practice introduced by
The property event does not exist on think\App. Since you implemented __get, consider adding a @property annotation.
Loading history...
407
408
        // 监听AppInit
409
        $this->event->trigger('AppInit');
410
411
        $this->debugModeInit();
412
413
        date_default_timezone_set($this->config->get('app.default_timezone', 'Asia/Shanghai'));
0 ignored issues
show
Bug Best Practice introduced by
The property config does not exist on think\App. Since you implemented __get, consider adding a @property annotation.
Loading history...
414
    }
415
416
    /**
417
     * 加载应用文件和配置
418
     * @access protected
419
     * @return void
420
     */
421
    protected function load(): void
422
    {
423
        if (is_file($this->appPath . 'event.php')) {
424
            $this->loadEvent(include $this->appPath . 'event.php');
425
        }
426
427
        if (is_file($this->appPath . 'common.php')) {
428
            include_once $this->appPath . 'common.php';
429
        }
430
431
        include $this->thinkPath . 'helper.php';
432
433
        if (is_file($this->appPath . 'middleware.php')) {
434
            $this->middleware->import(include $this->appPath . 'middleware.php');
0 ignored issues
show
Bug Best Practice introduced by
The property middleware does not exist on think\App. Since you implemented __get, consider adding a @property annotation.
Loading history...
435
        }
436
437
        if (is_file($this->appPath . 'provider.php')) {
438
            $this->bind(include $this->appPath . 'provider.php');
439
        }
440
441
        $files = [];
442
443
        if (is_dir($this->configPath)) {
444
            $files = glob($this->configPath . '*' . $this->configExt);
445
        }
446
447
        foreach ($files as $file) {
448
            $this->config->load($file, pathinfo($file, PATHINFO_FILENAME));
0 ignored issues
show
Bug Best Practice introduced by
The property config does not exist on think\App. Since you implemented __get, consider adding a @property annotation.
Loading history...
449
        }
450
    }
451
452
    /**
453
     * 调试模式设置
454
     * @access protected
455
     * @return void
456
     */
457
    protected function debugModeInit(): void
458
    {
459
        // 应用调试模式
460
        if (!$this->appDebug) {
461
            $this->appDebug = $this->env->get('app_debug', false);
0 ignored issues
show
Bug Best Practice introduced by
The property env does not exist on think\App. Since you implemented __get, consider adding a @property annotation.
Loading history...
462
        }
463
464
        if (!$this->appDebug) {
465
            ini_set('display_errors', 'Off');
466
        } elseif (PHP_SAPI != 'cli') {
467
            //重新申请一块比较大的buffer
468
            if (ob_get_level() > 0) {
469
                $output = ob_get_clean();
470
            }
471
            ob_start();
472
            if (!empty($output)) {
473
                echo $output;
474
            }
475
        }
476
    }
477
478
    /**
479
     * 注册应用事件
480
     * @access protected
481
     * @param array $event
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...
482
     * @return void
483
     */
484
    protected function loadEvent(array $event): void
485
    {
486
        if (isset($event['bind'])) {
487
            $this->event->bind($event['bind']);
0 ignored issues
show
Bug Best Practice introduced by
The property event does not exist on think\App. Since you implemented __get, consider adding a @property annotation.
Loading history...
488
        }
489
490
        if (isset($event['listen'])) {
491
            $this->event->listenEvents($event['listen']);
492
        }
493
494
        if (isset($event['subscribe'])) {
495
            $this->event->subscribe($event['subscribe']);
496
        }
497
    }
498
499
    abstract public function run();
0 ignored issues
show
Coding Style introduced by
Missing function doc comment
Loading history...
500
501
    /**
502
     * 解析应用类的类名
503
     * @access public
504
     * @param  string $layer 层名 controller model ...
505
     * @param  string $name  类名
506
     * @return string
507
     */
508
    public function parseClass(string $layer, string $name): string
509
    {
510
        $name  = str_replace(['/', '.'], '\\', $name);
511
        $array = explode('\\', $name);
512
        $class = self::parseName(array_pop($array), 1);
513
        $path  = $array ? implode('\\', $array) . '\\' : '';
514
515
        return $this->namespace . '\\' . $layer . '\\' . $path . $class;
516
    }
517
518
    /**
519
     * 获取应用根目录
520
     * @access protected
521
     * @return string
522
     */
523
    protected function getDefaultRootPath(): string
524
    {
525
        $path = dirname(dirname(dirname(dirname($this->thinkPath))));
526
527
        return $path . DIRECTORY_SEPARATOR;
528
    }
529
530
    /**
531
     * 字符串命名风格转换
532
     * type 0 将Java风格转换为C的风格 1 将C风格转换为Java的风格
533
     * @access public
534
     * @param  string  $name    字符串
535
     * @param  integer $type    转换类型
536
     * @param  bool    $ucfirst 首字母是否大写(驼峰规则)
537
     * @return string
538
     */
539
    public static function parseName(string $name = null, int $type = 0, bool $ucfirst = true): string
540
    {
541
        if ($type) {
542
            $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...
543
                return strtoupper($match[1]);
544
            }, $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...
545
            return $ucfirst ? ucfirst($name) : lcfirst($name);
546
        }
547
548
        return strtolower(trim(preg_replace("/[A-Z]/", "_\\0", $name), "_"));
549
    }
550
551
    /**
552
     * 获取类名(不包含命名空间)
553
     * @access public
554
     * @param  string|object $class
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
555
     * @return string
556
     */
557
    public static function classBaseName($class): string
558
    {
559
        $class = is_object($class) ? get_class($class) : $class;
560
        return basename(str_replace('\\', '/', $class));
561
    }
562
563
    /**
0 ignored issues
show
Coding Style introduced by
Parameter ...$args should have a doc-comment as per coding-style.
Loading history...
564
     * 创建工厂对象实例
565
     * @access public
566
     * @param  string $name      工厂类名
567
     * @param  string $namespace 默认命名空间
568
     * @return mixed
569
     */
570
    public static function factory(string $name, string $namespace = '', ...$args)
571
    {
572
        $class = false !== strpos($name, '\\') ? $name : $namespace . ucwords($name);
573
574
        if (class_exists($class)) {
575
            return Container::getInstance()->invokeClass($class, $args);
576
        }
577
578
        throw new ClassNotFoundException('class not exists:' . $class, $class);
579
    }
580
581
    public static function serialize($data): string
0 ignored issues
show
Coding Style introduced by
Missing function doc comment
Loading history...
582
    {
583
        SerializableClosure::enterContext();
584
        SerializableClosure::wrapClosures($data);
585
        $data = \serialize($data);
586
        SerializableClosure::exitContext();
587
        return $data;
588
    }
589
590
    public static function unserialize(string $data)
0 ignored issues
show
Coding Style introduced by
Missing function doc comment
Loading history...
591
    {
592
        SerializableClosure::enterContext();
593
        $data = \unserialize($data);
594
        SerializableClosure::unwrapClosures($data);
595
        SerializableClosure::exitContext();
596
        return $data;
597
    }
598
}
599