mirror of
https://github.com/zhamao-robot/zhamao-framework.git
synced 2026-03-18 05:04:51 +08:00
refactor container injection
This commit is contained in:
parent
f2aff5882d
commit
7253a309c7
@ -15,6 +15,7 @@ class Container extends WorkerContainer
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
$this->parent = WorkerContainer::getInstance();
|
||||
}
|
||||
|
||||
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -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();
|
||||
|
||||
@ -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')) {
|
||||
|
||||
@ -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';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -628,7 +628,6 @@ function zm_internal_errcode($code): string
|
||||
}
|
||||
|
||||
/**
|
||||
<<<<<<< HEAD
|
||||
* 将可能为数组的参数转换为字符串
|
||||
*
|
||||
* 如传入字符串则为原样返回
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user