refactor container injection

This commit is contained in:
sunxyw 2022-04-11 23:31:49 +08:00
parent f2aff5882d
commit 7253a309c7
No known key found for this signature in database
GPG Key ID: CEA01A083E98C578
8 changed files with 141 additions and 101 deletions

View File

@ -15,6 +15,7 @@ class Container extends WorkerContainer
public function __construct()
{
parent::__construct();
$this->parent = WorkerContainer::getInstance();
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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();

View File

@ -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')) {

View File

@ -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';
}
}
}

View File

@ -628,7 +628,6 @@ function zm_internal_errcode($code): string
}
/**
<<<<<<< HEAD
* 将可能为数组的参数转换为字符串
*
* 如传入字符串则为原样返回