From 7253a309c7073e9a9d77d4ad2e3390152dffde64 Mon Sep 17 00:00:00 2001 From: sunxyw Date: Mon, 11 Apr 2022 23:31:49 +0800 Subject: [PATCH] refactor container injection --- src/ZM/Container/Container.php | 1 + src/ZM/Container/WorkerContainer.php | 98 ++++++++++++++-------- src/ZM/Event/SwooleEvent/OnMessage.php | 28 ++++--- src/ZM/Event/SwooleEvent/OnWorkerStart.php | 26 ++++-- src/ZM/Event/SwooleEvent/OnWorkerStop.php | 3 - src/ZM/Framework.php | 49 +---------- src/ZM/Utils/ReflectionUtil.php | 36 ++++++++ src/ZM/global_functions.php | 1 - 8 files changed, 141 insertions(+), 101 deletions(-) diff --git a/src/ZM/Container/Container.php b/src/ZM/Container/Container.php index a235aea0..3ab833ca 100644 --- a/src/ZM/Container/Container.php +++ b/src/ZM/Container/Container.php @@ -15,6 +15,7 @@ class Container extends WorkerContainer public function __construct() { + parent::__construct(); $this->parent = WorkerContainer::getInstance(); } diff --git a/src/ZM/Container/WorkerContainer.php b/src/ZM/Container/WorkerContainer.php index 96d8860b..e0d48f2e 100644 --- a/src/ZM/Container/WorkerContainer.php +++ b/src/ZM/Container/WorkerContainer.php @@ -29,13 +29,20 @@ class WorkerContainer implements ContainerInterface /** * @var array[] */ - protected $buildStack = []; + protected $build_stack = []; /** * @var array[] */ protected $with = []; + /** + * 日志前缀 + * + * @var string + */ + protected $log_prefix; + /** * @var array[] */ @@ -56,6 +63,13 @@ class WorkerContainer implements ContainerInterface */ private static $extenders = []; + public function __construct() + { + if ($this->shouldLog()) { + $this->log('Container created'); + } + } + /** * 判断对应的类或接口是否已经注册 * @@ -119,7 +133,10 @@ class WorkerContainer implements ContainerInterface $concrete = $abstract; } - $concrete_name = is_string($concrete) ? $concrete : 'Closure'; + $concrete_name = ''; + if ($this->shouldLog()) { + $concrete_name = ReflectionUtil::variableToString($concrete); + } // 如果不是闭包,则认为是类名,此时将其包装在一个闭包中,以方便后续处理 if (!$concrete instanceof Closure) { @@ -191,7 +208,8 @@ class WorkerContainer implements ContainerInterface self::$instances[$abstract] = $instance; if ($this->shouldLog()) { - $this->log("[{$abstract}] is bound to [{$instance}] (instance)"); + $class_name = ReflectionUtil::variableToString($instance); + $this->log("[{$abstract}] is bound to [{$class_name}] (instance)"); } return $instance; @@ -219,8 +237,12 @@ class WorkerContainer implements ContainerInterface self::$instances = []; $this->shared = []; - $this->buildStack = []; + $this->build_stack = []; $this->with = []; + + if ($this->shouldLog()) { + $this->log('Container flushed'); + } } /** @@ -319,13 +341,13 @@ class WorkerContainer implements ContainerInterface $this->notInstantiable($concrete); } - $this->buildStack[] = $concrete; + $this->build_stack[] = $concrete; $constructor = $reflection->getConstructor(); // 如果不存在构造函数,则代表不需要进一步解析,直接实例化即可 if (is_null($constructor)) { - array_pop($this->buildStack); + array_pop($this->build_stack); return new $concrete(); } @@ -335,11 +357,11 @@ class WorkerContainer implements ContainerInterface try { $instances = $this->resolveDependencies($dependencies); } catch (EntryResolutionException $e) { - array_pop($this->buildStack); + array_pop($this->build_stack); throw $e; } - array_pop($this->buildStack); + array_pop($this->build_stack); return $reflection->newInstanceArgs($instances); } @@ -355,11 +377,17 @@ class WorkerContainer implements ContainerInterface public function call($callback, array $parameters = [], string $default_method = null) { if ($this->shouldLog()) { + if (count($parameters)) { + $str_parameters = array_map([ReflectionUtil::class, 'variableToString'], $parameters); + $str_parameters = implode(', ', $str_parameters); + } else { + $str_parameters = ''; + } $this->log(sprintf( - '[%s] called%s%s', - $this->getCallableName($callback), - ($default_method ? ' defaulting' . $default_method : ''), - ($parameters ? ' with ' . implode(', ', $parameters) : '') + 'Called %s%s(%s)', + ReflectionUtil::variableToString($callback), + ($default_method ? '@' . $default_method : ''), + $str_parameters )); } return BoundMethod::call($this, $callback, $parameters, $default_method); @@ -425,6 +453,22 @@ class WorkerContainer implements ContainerInterface } } + /** + * 获取日志前缀 + */ + public function getLogPrefix(): string + { + return ($this->log_prefix ?: '[WorkerContainer(U)]') . ' '; + } + + /** + * 设置日志前缀 + */ + public function setLogPrefix(string $prefix): void + { + $this->log_prefix = $prefix; + } + /** * 获取对应类型的所有扩展器 * @@ -490,8 +534,8 @@ class WorkerContainer implements ContainerInterface */ protected function notInstantiable(string $concrete, string $reason = ''): void { - if (!empty($this->buildStack)) { - $previous = implode(', ', $this->buildStack); + if (!empty($this->build_stack)) { + $previous = implode(', ', $this->build_stack); $message = "类 {$concrete} 无法实例化,其被 {$previous} 依赖"; } else { $message = "类 {$concrete} 无法实例化"; @@ -677,37 +721,19 @@ class WorkerContainer implements ContainerInterface && $this->bindings[$abstract]['shared'] === true); } - /** - * 获取回调的名称 - * - * @param callable|string $callable 回调 - */ - private function getCallableName($callable): string - { - $name = is_string($callable) ? $callable : '{closure}'; - if (is_array($callable)) { - if (is_object($callable[0])) { - $name = get_class($callable[0]) . '@' . $callable[1]; - } else { - $name = $callable[0] . '::' . $callable[1]; - } - } - return $name; - } - /** * 判断是否输出日志 */ - private function shouldLog(): bool + protected function shouldLog(): bool { return Console::getLevel() >= 4; } /** - * 记录日志 + * 记录日志(自动附加容器日志前缀) */ - private function log(string $message): void + protected function log(string $message): void { - Console::debug($message); + Console::debug($this->getLogPrefix() . $message); } } diff --git a/src/ZM/Event/SwooleEvent/OnMessage.php b/src/ZM/Event/SwooleEvent/OnMessage.php index b7ddbdfa..2a38acdf 100644 --- a/src/ZM/Event/SwooleEvent/OnMessage.php +++ b/src/ZM/Event/SwooleEvent/OnMessage.php @@ -5,7 +5,6 @@ declare(strict_types=1); namespace ZM\Event\SwooleEvent; use Swoole\Coroutine; -use Swoole\Http\Server; use Swoole\WebSocket\Frame; use Throwable; use ZM\Annotation\Swoole\OnMessageEvent; @@ -15,6 +14,7 @@ use ZM\ConnectionManager\ConnectionObject; use ZM\ConnectionManager\ManagerGM; use ZM\Console\Console; use ZM\Console\TermColor; +use ZM\Container\Container; use ZM\Context\Context; use ZM\Context\ContextInterface; use ZM\Event\EventDispatcher; @@ -33,13 +33,7 @@ class OnMessage implements SwooleEvent $conn = ManagerGM::get($frame->fd); set_coroutine_params(['server' => $server, 'frame' => $frame, 'connection' => $conn]); - container()->instance(Server::class, $server); - container()->instance(Frame::class, $frame); - container()->instance(ConnectionObject::class, $conn); - container()->bind(ContextInterface::class, function () { - return ctx(); - }); - container()->alias(ContextInterface::class, Context::class); + $this->registerRequestContainerBindings($frame, $conn); $dispatcher1 = new EventDispatcher(OnMessageEvent::class); $dispatcher1->setRuleFunction(function ($v) use ($conn) { @@ -70,9 +64,21 @@ class OnMessage implements SwooleEvent Console::trace(); } finally { container()->flush(); - if (Console::getLevel() >= 4) { - Console::debug(sprintf('Request container [fd=%d, cid=%d] flushed.', $frame->fd, Coroutine::getCid())); - } } } + + /** + * 注册请求容器绑定 + */ + private function registerRequestContainerBindings(Frame $frame, ?ConnectionObject $conn): void + { + $container = Container::getInstance(); + $container->setLogPrefix("[Container#{$frame->fd}]"); + $container->instance(Frame::class, $frame); + $container->instance(ConnectionObject::class, $conn); + $container->bind(ContextInterface::class, function () { + return ctx(); + }); + $container->alias(ContextInterface::class, Context::class); + } } diff --git a/src/ZM/Event/SwooleEvent/OnWorkerStart.php b/src/ZM/Event/SwooleEvent/OnWorkerStart.php index 893d4b8f..d3bc0338 100644 --- a/src/ZM/Event/SwooleEvent/OnWorkerStart.php +++ b/src/ZM/Event/SwooleEvent/OnWorkerStart.php @@ -54,11 +54,7 @@ class OnWorkerStart implements SwooleEvent } unset(Context::$context[Coroutine::getCid()]); - /* @noinspection PhpExpressionResultUnusedInspection */ - new WorkerContainer(); - if (Console::getLevel() >= 4) { - Console::debug(sprintf('Worker container [id=%d,cid=%d] booted', $worker_id, Coroutine::getCid())); - } + $this->registerWorkerContainerBindings($server); if ($server->taskworker === false) { Framework::saveProcessState(ZM_PROCESS_WORKER, $server->worker_pid, ['worker_id' => $worker_id]); @@ -292,4 +288,24 @@ class OnWorkerStart implements SwooleEvent DB::initTableList($real_conf['dbname']); } } + + /** + * 注册进程容器绑定 + */ + private function registerWorkerContainerBindings(Server $server): void + { + $container = WorkerContainer::getInstance(); + $container->setLogPrefix("[WorkerContainer#{$server->worker_id}]"); + // 路径 + $container->instance('path.working', DataProvider::getWorkingDir()); + $container->instance('path.source', DataProvider::getSourceRootDir()); + $container->alias('path.source', 'path.base'); + $container->instance('path.config', DataProvider::getSourceRootDir() . '/config'); + $container->instance('path.module_config', ZMConfig::get('global', 'config_dir')); + $container->instance('path.data', DataProvider::getDataFolder()); + $container->instance('path.framework', DataProvider::getFrameworkRootDir()); + // 基础 + $container->instance('server', $server); + $container->instance('worker_id', $server->worker_id); + } } diff --git a/src/ZM/Event/SwooleEvent/OnWorkerStop.php b/src/ZM/Event/SwooleEvent/OnWorkerStop.php index 919916ed..507bee74 100644 --- a/src/ZM/Event/SwooleEvent/OnWorkerStop.php +++ b/src/ZM/Event/SwooleEvent/OnWorkerStop.php @@ -22,9 +22,6 @@ class OnWorkerStop implements SwooleEvent public function onCall(Server $server, $worker_id) { WorkerContainer::getInstance()->flush(); - if (Console::getLevel() >= 4) { - Console::debug(sprintf('Worker container [id=%d] flushed', $worker_id)); - } if ($worker_id == (ZMConfig::get('worker_cache')['worker'] ?? 0)) { LightCache::savePersistence(); diff --git a/src/ZM/Framework.php b/src/ZM/Framework.php index efef8004..f970b0a5 100644 --- a/src/ZM/Framework.php +++ b/src/ZM/Framework.php @@ -19,8 +19,6 @@ use ZM\Config\ZMConfig; use ZM\ConnectionManager\ManagerGM; use ZM\Console\Console; use ZM\Console\TermColor; -use ZM\Container\Container; -use ZM\Container\ContainerInterface; use ZM\Exception\ZMKnownException; use ZM\Store\LightCache; use ZM\Store\LightCacheInside; @@ -72,13 +70,6 @@ class Framework */ private $setup_events = []; - /** - * 容器 - * - * @var ContainerInterface - */ - private $container; - /** * 创建一个新的框架实例 * @@ -91,13 +82,8 @@ class Framework self::$instant_mode = $instant_mode; self::$argv = $args; - // 初始化全局容器 - $this->container = new Container(); - $this->bindPathsInContainer(); - $this->registerBaseBindings(); - // 初始化配置 - ZMConfig::setDirectory(app('path.config')); + ZMConfig::setDirectory(DataProvider::getSourceRootDir() . '/config'); ZMConfig::setEnv($args['env'] ?? ''); if (ZMConfig::get('global') === false) { echo zm_internal_errcode('E00007') . 'Global config load failed: ' . ZMConfig::$last_error . "\nError path: " . DataProvider::getSourceRootDir() . "\nPlease init first!\nSee: https://github.com/zhamao-robot/zhamao-framework/issues/37\n"; @@ -108,8 +94,8 @@ class Framework require_once 'global_defines.php'; // 确保目录存在 - DataProvider::createIfNotExists(app('path.data')); - DataProvider::createIfNotExists(app('path.module_config')); + DataProvider::createIfNotExists(ZMConfig::get('global', 'zm_data')); + DataProvider::createIfNotExists(ZMConfig::get('global', 'config_dir')); DataProvider::createIfNotExists(ZMConfig::get('global', 'crash_dir')); // 初始化连接池? @@ -589,7 +575,7 @@ class Framework echo str_pad('', $max_border, '=') . PHP_EOL; } - public static function getTtyWidth(): int + public function getTtyWidth(): int { $size = exec('stty size'); if (empty($size)) { @@ -615,33 +601,6 @@ class Framework return file_put_contents(DataProvider::getDataFolder() . '.state.json', json_encode($data, 64 | 128 | 256)); } - /** - * 注册所有应用路径到容器 - */ - protected function bindPathsInContainer(): void - { - $this->container->instance('path.working', DataProvider::getWorkingDir()); - $this->container->instance('path.source', DataProvider::getSourceRootDir()); - $this->container->alias('path.source', 'path.base'); - $this->container->instance('path.config', DataProvider::getSourceRootDir() . '/config'); - $this->container->singleton('path.module_config', function () { - return ZMConfig::get('global', 'config_dir'); - }); - $this->container->singleton('path.data', function () { - return DataProvider::getDataFolder(); - }); - $this->container->instance('path.framework', DataProvider::getFrameworkRootDir()); - } - - /** - * 注册基础绑定到容器 - */ - protected function registerBaseBindings(): void - { - $this->container->instance('framework', $this); - $this->container->alias('framework', 'app'); - } - private static function printMotd($tty_width) { if (file_exists(DataProvider::getSourceRootDir() . '/config/motd.txt')) { diff --git a/src/ZM/Utils/ReflectionUtil.php b/src/ZM/Utils/ReflectionUtil.php index faea361a..e6710d81 100644 --- a/src/ZM/Utils/ReflectionUtil.php +++ b/src/ZM/Utils/ReflectionUtil.php @@ -40,4 +40,40 @@ class ReflectionUtil return $class_name; } + + /** + * 将传入变量转换为字符串 + * + * @param mixed $var + */ + public static function variableToString($var): string + { + switch (true) { + case is_callable($var): + if (is_array($var)) { + if (is_object($var[0])) { + return get_class($var[0]) . '@' . $var[1]; + } + return $var[0] . '::' . $var[1]; + } + return 'closure'; + case is_string($var): + return $var; + case is_array($var): + return 'array' . json_encode($var); + case is_object($var): + return get_class($var); + case is_resource($var): + return 'resource' . get_resource_type($var); + case is_null($var): + return 'null'; + case is_bool($var): + return $var ? 'true' : 'false'; + case is_float($var): + case is_int($var): + return (string) $var; + default: + return 'unknown'; + } + } } diff --git a/src/ZM/global_functions.php b/src/ZM/global_functions.php index bf6c05c2..81c5d7e7 100644 --- a/src/ZM/global_functions.php +++ b/src/ZM/global_functions.php @@ -628,7 +628,6 @@ function zm_internal_errcode($code): string } /** -<<<<<<< HEAD * 将可能为数组的参数转换为字符串 * * 如传入字符串则为原样返回