mirror of
https://github.com/zhamao-robot/zhamao-framework.git
synced 2026-03-18 05:04:51 +08:00
Merge pull request #172 from zhamao-robot/orgianze-bootstrap
重新组织 Bootstraper
This commit is contained in:
commit
ea74a531b4
@ -197,10 +197,10 @@ function sql_builder(string $name = '')
|
||||
* 不传参数,返回配置容器
|
||||
*
|
||||
* @param null|array|string $key 键名
|
||||
* @param mixed $default 默认值
|
||||
* @param null|mixed $default 默认值
|
||||
* @return mixed|void|ZMConfig
|
||||
*/
|
||||
function config($key = null, $default = null)
|
||||
function config(array|string $key = null, mixed $default = null)
|
||||
{
|
||||
$config = ZMConfig::getInstance();
|
||||
if (is_null($key)) {
|
||||
|
||||
37
src/ZM/Bootstrap/HandleExceptions.php
Normal file
37
src/ZM/Bootstrap/HandleExceptions.php
Normal file
@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace ZM\Bootstrap;
|
||||
|
||||
use OneBot\Driver\ExceptionHandler;
|
||||
use ZM\Exception\Handler;
|
||||
|
||||
class HandleExceptions
|
||||
{
|
||||
public function bootstrap(array $config): void
|
||||
{
|
||||
// 注册全局错误处理器
|
||||
set_error_handler(function ($error_no, $error_msg, $error_file, $error_line) {
|
||||
$tips = [
|
||||
E_WARNING => ['PHP Warning: ', 'warning'],
|
||||
E_NOTICE => ['PHP Notice: ', 'notice'],
|
||||
E_USER_ERROR => ['PHP Error: ', 'error'],
|
||||
E_USER_WARNING => ['PHP Warning: ', 'warning'],
|
||||
E_USER_NOTICE => ['PHP Notice: ', 'notice'],
|
||||
E_STRICT => ['PHP Strict: ', 'notice'],
|
||||
E_RECOVERABLE_ERROR => ['PHP Recoverable Error: ', 'error'],
|
||||
E_DEPRECATED => ['PHP Deprecated: ', 'notice'],
|
||||
E_USER_DEPRECATED => ['PHP User Deprecated: ', 'notice'],
|
||||
];
|
||||
$level_tip = $tips[$error_no] ?? ['PHP Unknown: ', 'error'];
|
||||
$error = $level_tip[0] . $error_msg . ' in ' . $error_file . ' on ' . $error_line;
|
||||
logger()->{$level_tip[1]}($error);
|
||||
// 如果 return false 则错误会继续递交给 PHP 标准错误处理
|
||||
return true;
|
||||
}, E_ALL | E_STRICT);
|
||||
|
||||
// 重载异常处理器
|
||||
ExceptionHandler::getInstance()->overrideWith(new Handler());
|
||||
}
|
||||
}
|
||||
71
src/ZM/Bootstrap/LoadConfiguration.php
Normal file
71
src/ZM/Bootstrap/LoadConfiguration.php
Normal file
@ -0,0 +1,71 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace ZM\Bootstrap;
|
||||
|
||||
use OneBot\Driver\Workerman\Worker;
|
||||
use ZM\Config\ZMConfig;
|
||||
|
||||
class LoadConfiguration
|
||||
{
|
||||
public function bootstrap(array $config): void
|
||||
{
|
||||
$config_i = config();
|
||||
$config_i->addConfigPath($this->getConfigDir($config));
|
||||
$config_i->setEnvironment($this->getConfigEnvironment($config));
|
||||
$this->parseArgvToConfig($config, $config_i);
|
||||
}
|
||||
|
||||
private function getConfigDir(array $config): string
|
||||
{
|
||||
$config_dir = $config['config-dir'];
|
||||
// 默认配置文件目录
|
||||
$find_dir = [
|
||||
WORKING_DIR . '/config',
|
||||
SOURCE_ROOT_DIR . '/config',
|
||||
];
|
||||
// 如果启动参数指定了配置文件目录,则优先使用
|
||||
if ($config_dir !== null) {
|
||||
array_unshift($find_dir, $config_dir);
|
||||
}
|
||||
|
||||
// 遍历目录,找到第一个存在的目录
|
||||
foreach ($find_dir as $dir) {
|
||||
if (is_dir($dir)) {
|
||||
return $dir;
|
||||
}
|
||||
}
|
||||
|
||||
// 如果没有找到目录,则抛出异常
|
||||
throw new \RuntimeException('No config directory found');
|
||||
}
|
||||
|
||||
private function getConfigEnvironment(array $config): string
|
||||
{
|
||||
return $config['env'] ?? 'development';
|
||||
}
|
||||
|
||||
private function parseArgvToConfig(array $argv, ZMConfig $config): void
|
||||
{
|
||||
foreach ($argv as $x => $y) {
|
||||
// 当值为 true/false 时,表示该参数为可选参数。当值为 null 时,表示该参数必定会有一个值,如果是 null,说明没指定
|
||||
if ($y === false || is_null($y)) {
|
||||
continue;
|
||||
}
|
||||
switch ($x) {
|
||||
case 'driver': // 动态设置驱动类型
|
||||
$config->set('global.driver', $y);
|
||||
break;
|
||||
case 'worker-num': // 动态设置 Worker 数量
|
||||
$config->set('global.swoole_options.swoole_set.worker_num', (int) $y);
|
||||
$config->set('global.workerman_options.workerman_worker_num', (int) $y);
|
||||
break;
|
||||
case 'daemon': // 启动为守护进程
|
||||
$config->set('global.swoole_options.swoole_set.daemonize', 1);
|
||||
Worker::$daemonize = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
13
src/ZM/Bootstrap/LoadGlobalDefines.php
Normal file
13
src/ZM/Bootstrap/LoadGlobalDefines.php
Normal file
@ -0,0 +1,13 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace ZM\Bootstrap;
|
||||
|
||||
class LoadGlobalDefines
|
||||
{
|
||||
public function bootstrap(array $config): void
|
||||
{
|
||||
require zm_dir(SOURCE_ROOT_DIR . '/src/Globals/global_defines_framework.php');
|
||||
}
|
||||
}
|
||||
16
src/ZM/Bootstrap/RegisterEventProvider.php
Normal file
16
src/ZM/Bootstrap/RegisterEventProvider.php
Normal file
@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace ZM\Bootstrap;
|
||||
|
||||
use ZM\Event\EventProvider;
|
||||
|
||||
class RegisterEventProvider
|
||||
{
|
||||
public function bootstrap(array $config): void
|
||||
{
|
||||
global $ob_event_provider;
|
||||
$ob_event_provider = EventProvider::getInstance();
|
||||
}
|
||||
}
|
||||
20
src/ZM/Bootstrap/RegisterLogger.php
Normal file
20
src/ZM/Bootstrap/RegisterLogger.php
Normal file
@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace ZM\Bootstrap;
|
||||
|
||||
use ZM\Logger\ConsoleLogger;
|
||||
|
||||
class RegisterLogger
|
||||
{
|
||||
public function bootstrap(array $config): void
|
||||
{
|
||||
// 初始化 Logger
|
||||
if (!ob_logger_registered()) {
|
||||
// 如果没有注册过 Logger,那么就初始化一个,在启动框架前注册的话,就不会初始化了,可替换为其他 Logger
|
||||
$logger = new ConsoleLogger($config['log-level'] ?? 'info');
|
||||
ob_logger_register($logger);
|
||||
}
|
||||
}
|
||||
}
|
||||
13
src/ZM/Bootstrap/SetInternalTimezone.php
Normal file
13
src/ZM/Bootstrap/SetInternalTimezone.php
Normal file
@ -0,0 +1,13 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace ZM\Bootstrap;
|
||||
|
||||
class SetInternalTimezone
|
||||
{
|
||||
public function bootstrap(array $config): void
|
||||
{
|
||||
date_default_timezone_set(config('global.runtime.timezone', 'UTC'));
|
||||
}
|
||||
}
|
||||
32
src/ZM/Exception/Handler.php
Normal file
32
src/ZM/Exception/Handler.php
Normal file
@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace ZM\Exception;
|
||||
|
||||
use OneBot\Driver\ExceptionHandler;
|
||||
|
||||
class Handler extends ExceptionHandler
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
// 我们知道此处没有调用父类的构造函数,这是设计上的缺陷
|
||||
// 将会在稍后修复
|
||||
}
|
||||
|
||||
public function handle(\Throwable $e): void
|
||||
{
|
||||
if ($e instanceof ZMKnownException) {
|
||||
// 如果是已知异常,则可以输出问题说明和解决方案
|
||||
// TODO
|
||||
}
|
||||
|
||||
if (is_null($this->whoops)) {
|
||||
ob_logger()->error('Uncaught ' . get_class($e) . ': ' . $e->getMessage() . ' at ' . $e->getFile() . '(' . $e->getLine() . ')');
|
||||
ob_logger()->error($e->getTraceAsString());
|
||||
return;
|
||||
}
|
||||
|
||||
// $this->whoops->handleException($e);
|
||||
}
|
||||
}
|
||||
@ -27,10 +27,8 @@ use ZM\Event\Listener\ManagerEventListener;
|
||||
use ZM\Event\Listener\MasterEventListener;
|
||||
use ZM\Event\Listener\WorkerEventListener;
|
||||
use ZM\Event\Listener\WSEventListener;
|
||||
use ZM\Exception\ConfigException;
|
||||
use ZM\Exception\InitException;
|
||||
use ZM\Exception\ZMKnownException;
|
||||
use ZM\Logger\ConsoleLogger;
|
||||
use ZM\Logger\TablePrinter;
|
||||
use ZM\Process\ProcessStateManager;
|
||||
|
||||
@ -57,6 +55,16 @@ class Framework
|
||||
/** @var array<array<string, string>> 启动注解列表 */
|
||||
protected array $setup_annotations = [];
|
||||
|
||||
protected array $bootstrappers = [
|
||||
// 驱动前置
|
||||
Bootstrap\LoadConfiguration::class,
|
||||
Bootstrap\LoadGlobalDefines::class,
|
||||
Bootstrap\RegisterLogger::class,
|
||||
Bootstrap\HandleExceptions::class,
|
||||
Bootstrap\RegisterEventProvider::class,
|
||||
Bootstrap\SetInternalTimezone::class,
|
||||
];
|
||||
|
||||
/**
|
||||
* 框架初始化文件
|
||||
*
|
||||
@ -81,8 +89,13 @@ class Framework
|
||||
*/
|
||||
public function init(): Framework
|
||||
{
|
||||
// 执行一些 Driver 前置条件的内容
|
||||
$this->initDriverPrerequisites();
|
||||
// 顺序执行引导器
|
||||
foreach ($this->bootstrappers as $bootstrapper) {
|
||||
app($bootstrapper)->bootstrap($this->argv);
|
||||
}
|
||||
|
||||
// 初始化 @OnSetup 事件
|
||||
$this->initSetupAnnotations();
|
||||
|
||||
// 初始化 Driver 及框架内部需要监听的事件
|
||||
$this->initDriver();
|
||||
@ -166,85 +179,6 @@ class Framework
|
||||
return $this->driver;
|
||||
}
|
||||
|
||||
/**
|
||||
* 在框架的 Driver 层初始化前的一些前提条件
|
||||
*
|
||||
* 1. 设置 config 读取的目录
|
||||
* 2. 初始化框架运行时的常量
|
||||
* 3. 初始化 Logger
|
||||
* 4. 初始化 EventProvider
|
||||
* 5. 设置时区,防止 Logger 时间乱跳
|
||||
* 6. 覆盖 PHP 报错样式解析
|
||||
* 7. 解析命令行参数
|
||||
* 8. 读取、解析并执行 OnSetup 注解
|
||||
*
|
||||
* @throws ConfigException
|
||||
*/
|
||||
public function initDriverPrerequisites()
|
||||
{
|
||||
// 寻找配置文件目录
|
||||
if ($this->argv['config-dir'] !== null) { // 如果启动参数指定了config寻找目录,那么就在指定的寻找,不在别的地方寻找了
|
||||
$find_dir = [$this->argv['config-dir']];
|
||||
logger()->debug('使用命令参数指定的config-dir:' . $this->argv['config-dir']);
|
||||
} else { // 否则就从默认的工作目录或源码根目录寻找
|
||||
$find_dir = [WORKING_DIR . '/config', SOURCE_ROOT_DIR . '/config'];
|
||||
}
|
||||
foreach ($find_dir as $v) {
|
||||
if (is_dir($v)) {
|
||||
config()->addConfigPath($v);
|
||||
config()->setEnvironment($this->argv['env'] = ($this->argv['env'] ?? 'development'));
|
||||
$config_done = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// 找不到的话直接崩溃,因为框架依赖全局配置文件(但其实这个错误在 3.0 开始应该永远无法执行到)
|
||||
if (!isset($config_done)) {
|
||||
echo zm_internal_errcode('E00007') . 'Global config load failed' . "\nPlease init first!\nSee: https://github.com/zhamao-robot/zhamao-framework/issues/37\n";
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// 初始化框架本体运行需要的常量,比如运行时间等
|
||||
require zm_dir(__DIR__ . '/../Globals/global_defines_framework.php');
|
||||
|
||||
// 初始化 Logger,此处为 Master 进程第一次初始化,在后续的多进程环境下,还需要在 Worker 进程中初始化
|
||||
if (!ob_logger_registered()) { // 如果没有注册过 Logger,那么就初始化一个,在启动框架前注册的话,就不会初始化了,可替换为其他 Logger
|
||||
ob_logger_register(new ConsoleLogger($this->argv['log-level'] ?? 'info'));
|
||||
}
|
||||
|
||||
// 注册自己的EventProvider
|
||||
global $ob_event_provider;
|
||||
$ob_event_provider = EventProvider::getInstance();
|
||||
|
||||
// 初始化时区,默认为上海时区
|
||||
date_default_timezone_set(config('global.runtime.timezone'));
|
||||
|
||||
// 注册全局错误处理器
|
||||
set_error_handler(static function ($error_no, $error_msg, $error_file, $error_line) {
|
||||
$tips = [
|
||||
E_WARNING => ['PHP Warning: ', 'warning'],
|
||||
E_NOTICE => ['PHP Notice: ', 'notice'],
|
||||
E_USER_ERROR => ['PHP Error: ', 'error'],
|
||||
E_USER_WARNING => ['PHP Warning: ', 'warning'],
|
||||
E_USER_NOTICE => ['PHP Notice: ', 'notice'],
|
||||
E_STRICT => ['PHP Strict: ', 'notice'],
|
||||
E_RECOVERABLE_ERROR => ['PHP Recoverable Error: ', 'error'],
|
||||
E_DEPRECATED => ['PHP Deprecated: ', 'notice'],
|
||||
E_USER_DEPRECATED => ['PHP User Deprecated: ', 'notice'],
|
||||
];
|
||||
$level_tip = $tips[$error_no] ?? ['PHP Unknown: ', 'error'];
|
||||
$error = $level_tip[0] . $error_msg . ' in ' . $error_file . ' on ' . $error_line;
|
||||
logger()->{$level_tip[1]}($error);
|
||||
// 如果 return false 则错误会继续递交给 PHP 标准错误处理
|
||||
return true;
|
||||
}, E_ALL | E_STRICT);
|
||||
|
||||
// 解析命令行参数
|
||||
$this->parseArgs();
|
||||
|
||||
// 初始化 @OnSetup 事件
|
||||
$this->initSetupAnnotations();
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化驱动及相关事件
|
||||
* 实例化 Driver 对象
|
||||
@ -459,32 +393,6 @@ class Framework
|
||||
echo $motd;
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析 argv 参数
|
||||
*/
|
||||
private function parseArgs()
|
||||
{
|
||||
foreach ($this->argv as $x => $y) {
|
||||
// 当值为 true/false 时,表示该参数为可选参数。当值为 null 时,表示该参数必定会有一个值,如果是 null,说明没指定
|
||||
if ($y === false || is_null($y)) {
|
||||
continue;
|
||||
}
|
||||
switch ($x) {
|
||||
case 'driver': // 动态设置驱动类型
|
||||
config()->set('global.driver', $y);
|
||||
break;
|
||||
case 'worker-num': // 动态设置 Worker 数量
|
||||
config()->set('global.swoole_options.swoole_set.worker_num', intval($y));
|
||||
config()->set('global.workerman_options.workerman_worker_num', intval($y));
|
||||
break;
|
||||
case 'daemon': // 启动为守护进程
|
||||
config()->set('global.swoole_options.swoole_set.daemonize', 1);
|
||||
Worker::$daemonize = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化 OnSetup 注解
|
||||
*/
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user