从bin/swoft开始,阅读Swoft框架源码(一)--Application的初始化

马尔科夫尼可夫

bean/swoft中的代码如下:

// 引入bootstrap.php文件
// 实际上bootstrap.php只干了一件事:引入/vendor/autoload.php
// 由autoload.php来加载项目中的库类
// Bootstrap
require_once __DIR__ . '/bootstrap.php';

// 设置最大协程数量
SwooleCoroutine::set([
 'max_coroutine' => 300000,
]);

// 实例化application
// 调用application的run方法执行应用
// run方法声明在Swoft\Contract\ApplicationInterface
// 实现在Swoft\SwoftApplication
// Run application
(new AppApplication())->run();

AppApplication的实现很简单:

class Application extends SwoftApplication
{
     protected function beforeInit(): void
     {
         parent::beforeInit();
         
         // 设置时区
         // you can init php setting.
         date_default_timezone_set('Asia/Shanghai');
     }
     /**
     * @return array
     */ public function getCLoggerConfig(): array
     {
         $config = parent::getCLoggerConfig();
         // False: Dont print log to terminal
         // 将控制台输出打开
         $config['enable'] = true;
         return $config;
     }
}

里面只是重写了父类SwoftApplication的beforeInit方法和`
getCLoggerConfig方法.

所以实例化application的操作还是在父类SwoftApplication的构造方法中完成的,先看父类的构造方法代码:

public function __construct(array $config = [])
{
     // 第一件事情是检查当前的运行环境
     // 后附检查运行时环境的代码
     // 主要检测PHP版本、swoole版本以及是否加载了有冲突的扩展
     // Check runtime env
     SwoftHelper::checkRuntime();
     
     // Storage as global static property.
     // 将当前实例保存在Swoft类的静态属性上
     Swoft::$app = $this;
     
     // 调用(触发)beforeInit函数(事件)
     // 在Application的beforeInit中先调用了父类的beforeInit
     // 父类中检测并定义了是否在Phar包中执行的常量IN_PHAR
     // 然后子类中设置了当前时区
     // Before init
     $this->beforeInit();
     
     
     // 初始化控制台日志logger
     // 后附日志初始化代码
     // Init console logger
     $this->initCLogger();
     
     // 设置额外属性 此处因为未传构造参数 所以不会执行
     // Can setting properties by array
     if ($config) {
        ObjectHelper::init($this, $config);
     }
     
     // 初始化应用
     // 后附实现代码
     // Init application
     $this->init();
     
     // afterInit方法(事件)调用(触发)
     // 如果是在phar环境下面会设置runtime目录,未做其它额外操作
     // After init
     $this->afterInit();
}

运行时环境检测代码:

public static function checkRuntime(string $minPhp = '7.1', string $minSwoole = '4.4.1'): void
{
     // 检测php版本是否大于7.1 不满足条件就抛出RuntimeException
     if (version_compare(PHP_VERSION, $minPhp, '<')) {
        throw new RuntimeException('Run the server requires PHP version > ' . $minPhp . '! current is ' . PHP_VERSION);
     }
     
     // 检测是否加载了swoole扩展 
     if (!extension_loaded('swoole')) {
        throw new RuntimeException("Run the server, extension 'swoole' is required!");
     }
     
     // 检测swoole扩展版本是否大于4.4.1
     if (version_compare(SWOOLE_VERSION, $minSwoole, '<')) {
        throw new RuntimeException('Run the server requires swoole version > ' . $minSwoole . '! current is ' . SWOOLE_VERSION);
     }
     
     // 冲突扩展
     $conflicts = [
         'blackfire',
         'xdebug',
         'uopz',
         'xhprof',
         'zend',
         'trace',
     ];
     
     // 遍历冲突扩展 如果检测到加载了这些冲突扩展 则抛出异常
     foreach ($conflicts as $ext) {
         if (extension_loaded($ext)) {
            throw new RuntimeException("The extension of '{$ext}' must be closed, otherwise swoft will be affected!");
         }
     }
 }

SwoftApplication的beforeInit:

protected function beforeInit(): void
{
     // Check phar env
     // 检测运行环境是否为phar包
     if (!defined('IN_PHAR')) {
        define('IN_PHAR', false);
     }
}

日志初始化代码:

private function initCLogger(): void
{
     // 获取日志配置(此处为父类的返回) 
     // [
     //     'name' => 'swoft',
     //     'enable' => true,
     //     'output' => true,
     //     'levels' => '',
     //     'logFile' => ''
     // ]
     // Console logger config
     // 子类中再次将enable设置为true
     $config = $this->getCLoggerConfig();
     
     // 初始化控制台logger
     // swoft的CLog使用monolog,在monolog的基础上
     // 封装了getTrace方法,方便swoole的调试
     // 后附代码
     // Init console log
     CLog::init($config);
}

CLog::init代码:

public static function init(array $config): void
{
     // self::$cLogger不为null表示已经有logger,无需再次初始化
     if (self::$cLogger !== null) {
        return;
     }
     
     // config配置
     $name = $config['name'] ?? '';
     $enable = $config['enable'] ?? true;
     $output = $config['output'] ?? true;
     $levels = $config['levels'] ?? '';
     $logFile = $config['logFile'] ?? '';
     
     // 此处使用monolog的LineFormatter作为后续
     // CEchoHandler和CFileHandler的组件
     $lineFormatter = new LineFormatter();
     
     // 初始化CEchoHandler并设置
     $cEchoHandler = new CEchoHandler();
     $cEchoHandler->setFormatter($lineFormatter);
     $cEchoHandler->setLevels($levels);
     $cEchoHandler->setOutput($output);
     
     // 初始化CFileHandler并设置
     $cFileHandler = new CFileHandler();
     $cFileHandler->setFormatter($lineFormatter);
     $cFileHandler->setLevels($levels);
     $cFileHandler->setLogFile($logFile);
     
     // 初始化CLogger 该logger继承于monolog
     $cLogger = new CLogger();
     $cLogger->setName($name);
     $cLogger->setEnable($enable);
     $cLogger->setHandlers([$cEchoHandler, $cFileHandler]);
     
     // 将初始化好的控制台logger保存在cLogger属性上
     self::$cLogger = $cLogger;
}

Application的初始化:

protected function init(): void
{
     // Init system path aliases
     
     // 设置基础路径(项目根目录)
     $this->findBasePath();
     
     // 设置并打印@base@app@config@runtime的路径别名
     $this->setSystemAlias();
     
     // 初始化EnvProcessor、ConfigProcessor、AnnotationProcessor
     // BeanProcessor、EventProcessor、ConsoleProcessor
     // 此6个处理器内容太多且只是初始化 后续章节实际调用时将说明
     $processors = $this->processors();
     
     // 初始化当前应用的处理器
     $this->processor = new ApplicationProcessor($this);
     
     // 将前面初始化的处理器交给当前应用处理器统一管理调度
     $this->processor->addFirstProcessor(...$processors);
}

总结:

Application初始化顺序:
1.检查运行时环境.
2.触发初始化前事件.
3.初始化控制台logger.
4.初始化应用.
5.触发初始化后事件.
阅读 272

酷白发,小酒窝,主角标配的帅小伙~

7 声望
2 粉丝
0 条评论
你知道吗?

酷白发,小酒窝,主角标配的帅小伙~

7 声望
2 粉丝
宣传栏