更新hyperf
This commit is contained in:
parent
9f80c71d42
commit
e84acb95b9
@ -13,8 +13,8 @@ export default defineConfig({
|
|||||||
tipLabel: '提示',
|
tipLabel: '提示',
|
||||||
warningLabel: '警告',
|
warningLabel: '警告',
|
||||||
dangerLabel: '危险',
|
dangerLabel: '危险',
|
||||||
infoLabel: '信息',
|
infoLabel: 'info',
|
||||||
detailsLabel: '详细信息'
|
detailsLabel: '点我查看'
|
||||||
},
|
},
|
||||||
image: {
|
image: {
|
||||||
// 默认禁用图片懒加载
|
// 默认禁用图片懒加载
|
||||||
|
@ -16,6 +16,10 @@ export default [
|
|||||||
{ text: '路由寻址', link: hyperf + '路由寻址' },
|
{ text: '路由寻址', link: hyperf + '路由寻址' },
|
||||||
{ text: '中间件', link: hyperf + '中间件' },
|
{ text: '中间件', link: hyperf + '中间件' },
|
||||||
{ text: '响应', link: hyperf + '响应' },
|
{ text: '响应', link: hyperf + '响应' },
|
||||||
|
{ text: '附录1 container的get方法', link: hyperf + '附录1 container的get方法' },
|
||||||
|
{ text: '附录2 注解命令获取', link: hyperf + '附录2 注解命令获取' },
|
||||||
|
{ text: '附录3 命令注册Application', link: hyperf + '附录3 命令注册Application' },
|
||||||
|
{ text: '附录4 Application Run方法', link: hyperf + '附录4 Application_Run' },
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
title: 初始化容器类
|
title: 初始化容器类
|
||||||
---
|
---
|
||||||
# 初始化容器类
|
# 初始化容器类
|
||||||
|
|
||||||
本节分析容器类的实例化过程,
|
本节分析容器类的实例化过程,
|
||||||
|
|
||||||
```php
|
```php
|
||||||
@ -28,10 +29,14 @@ return ApplicationContext::setContainer($container);
|
|||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
::: tip
|
||||||
首先,可以看出,先是实例化了`DefinitionSourceFactory`类,然后使用方法的调用方式调用类,会触发该类的`__invoke`方法,最后返回的内容作为`Container`类的构造函数的参数,然后返回实例化后的容器类。
|
首先,可以看出,先是实例化了`DefinitionSourceFactory`类,然后使用方法的调用方式调用类,会触发该类的`__invoke`方法,最后返回的内容作为`Container`类的构造函数的参数,然后返回实例化后的容器类。
|
||||||
|
:::
|
||||||
|
|
||||||
|
### 生成包含依赖关系和配置的定义源
|
||||||
|
|
||||||
|
查看`DefinitionSourceFactory`工厂类做了哪些工作,
|
||||||
|
|
||||||
### DefinitionSourceFactory类
|
|
||||||
先看该类做了那些工作,
|
|
||||||
```php
|
```php
|
||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
namespace Hyperf\Di\Definition;
|
namespace Hyperf\Di\Definition;
|
||||||
@ -43,7 +48,6 @@ class DefinitionSourceFactory
|
|||||||
{
|
{
|
||||||
public function __invoke(): DefinitionSource
|
public function __invoke(): DefinitionSource
|
||||||
{
|
{
|
||||||
// 常量不存在,报错
|
|
||||||
if (! defined('BASE_PATH')) {
|
if (! defined('BASE_PATH')) {
|
||||||
throw new Exception('BASE_PATH is not defined.');
|
throw new Exception('BASE_PATH is not defined.');
|
||||||
}
|
}
|
||||||
@ -51,10 +55,9 @@ class DefinitionSourceFactory
|
|||||||
// 该方法上面一节分析过,获取所有的服务提供者返回的配置信息数组
|
// 该方法上面一节分析过,获取所有的服务提供者返回的配置信息数组
|
||||||
$configFromProviders = [];
|
$configFromProviders = [];
|
||||||
if (class_exists(ProviderConfig::class)) {
|
if (class_exists(ProviderConfig::class)) {
|
||||||
$configFromProviders = ProviderConfig::load();
|
$configFromProviders = :ProviderConfig:load();
|
||||||
}
|
}
|
||||||
|
|
||||||
// 同理,这里会获取配置文件中的依赖配置信息,如果存在相同的key,则覆盖掉
|
|
||||||
$serverDependencies = $configFromProviders['dependencies'] ?? [];
|
$serverDependencies = $configFromProviders['dependencies'] ?? [];
|
||||||
$dependenciesPath = BASE_PATH . '/config/autoload/dependencies.php';
|
$dependenciesPath = BASE_PATH . '/config/autoload/dependencies.php';
|
||||||
if (file_exists($dependenciesPath)) {
|
if (file_exists($dependenciesPath)) {
|
||||||
@ -65,11 +68,69 @@ class DefinitionSourceFactory
|
|||||||
return new DefinitionSource($serverDependencies);
|
return new DefinitionSource($serverDependencies);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
只有一个方法,也是会被调用的`__invoke`方法,获取依赖信息,并作为参数传递给`DefinitionSource`用作实例化参数。
|
||||||
|
|
||||||
|
`$serverDependencies`数组具体内容如下,
|
||||||
|
|
||||||
|
:::details
|
||||||
|
|
||||||
|
```php
|
||||||
|
Array
|
||||||
|
(
|
||||||
|
[Psr\SimpleCache\CacheInterface] => Hyperf\Cache\Cache
|
||||||
|
[Hyperf\Contract\ConfigInterface] => Hyperf\Config\ConfigFactory
|
||||||
|
[Hyperf\DbConnection\Pool\PoolFactory] => Hyperf\DbConnection\Pool\PoolFactory
|
||||||
|
[Hyperf\Database\Connectors\ConnectionFactory] => Hyperf\Database\Connectors\ConnectionFactory
|
||||||
|
[Hyperf\Database\ConnectionResolverInterface] => Hyperf\DbConnection\ConnectionResolver
|
||||||
|
[db.connector.mysql] => Hyperf\Database\Connectors\MySqlConnector
|
||||||
|
[Hyperf\Database\Migrations\MigrationRepositoryInterface] => Hyperf\DbConnection\DatabaseMigrationRepositoryFactory
|
||||||
|
[Hyperf\Di\MethodDefinitionCollectorInterface] => Hyperf\Di\MethodDefinitionCollector
|
||||||
|
[Hyperf\Di\ClosureDefinitionCollectorInterface] => Hyperf\Di\ClosureDefinitionCollector
|
||||||
|
[Hyperf\Engine\Contract\Socket\SocketFactoryInterface] => Hyperf\Engine\Socket\SocketFactory
|
||||||
|
[Psr\EventDispatcher\ListenerProviderInterface] => Hyperf\Event\ListenerProviderFactory
|
||||||
|
[Psr\EventDispatcher\EventDispatcherInterface] => Hyperf\Event\EventDispatcherFactory
|
||||||
|
[Hyperf\ExceptionHandler\Formatter\FormatterInterface] => Hyperf\ExceptionHandler\Formatter\DefaultFormatter
|
||||||
|
[League\Flysystem\Filesystem] => Hyperf\Filesystem\FilesystemInvoker
|
||||||
|
[Hyperf\Contract\ApplicationInterface] => Hyperf\Framework\ApplicationFactory
|
||||||
|
[Hyperf\Contract\StdoutLoggerInterface] => Hyperf\Framework\Logger\StdoutLogger
|
||||||
|
[Hyperf\HttpMessage\Server\RequestParserInterface] => Hyperf\HttpMessage\Server\Request\Parser
|
||||||
|
[Hyperf\HttpServer\Contract\RequestInterface] => Hyperf\HttpServer\Request
|
||||||
|
[Hyperf\HttpServer\Contract\ResponseInterface] => Hyperf\HttpServer\Response
|
||||||
|
[Psr\Http\Message\ServerRequestInterface] => Hyperf\HttpServer\Request
|
||||||
|
[Psr\Log\LoggerInterface] => Closure Object
|
||||||
|
(
|
||||||
|
[this] => Hyperf\Logger\ConfigProvider Object
|
||||||
|
(
|
||||||
|
)
|
||||||
|
|
||||||
|
[parameter] => Array
|
||||||
|
(
|
||||||
|
[$container] => <required>
|
||||||
|
)
|
||||||
|
|
||||||
|
)
|
||||||
|
|
||||||
|
[Redis] => Hyperf\Redis\Redis
|
||||||
|
[Symfony\Component\Serializer\Serializer] => Hyperf\Serializer\SerializerFactory
|
||||||
|
[Hyperf\Contract\NormalizerInterface] => Hyperf\Serializer\SimpleNormalizer
|
||||||
|
[Swoole\Server] => Hyperf\Server\SwooleServerFactory
|
||||||
|
[Hyperf\Contract\TranslatorLoaderInterface] => Hyperf\Translation\FileLoaderFactory
|
||||||
|
[Hyperf\Contract\TranslatorInterface] => Hyperf\Translation\TranslatorFactory
|
||||||
|
[Hyperf\Validation\Contract\PresenceVerifierInterface] => Hyperf\Validation\DatabasePresenceVerifierFactory
|
||||||
|
[Hyperf\Validation\Contract\ValidatorFactoryInterface] => Hyperf\Validation\ValidatorFactoryFactory
|
||||||
|
)
|
||||||
|
|
||||||
```
|
```
|
||||||
只有一个方法,也是会被调用的`__invoke`方法。这里返回实例化的`DefinitionSource`对象。
|
|
||||||
### DefinitionSource类
|
:::
|
||||||
|
可以看出,基本上是接口绑定对应的实现类。
|
||||||
|
|
||||||
|
#### 将抽象接口或类绑定到其对应的实现类或实例
|
||||||
|
|
||||||
> `DefinitionSource类`是管理容器中的绑定关系,即将抽象接口或类绑定到其对应的实现类或实例,来看源码。
|
> `DefinitionSource类`是管理容器中的绑定关系,即将抽象接口或类绑定到其对应的实现类或实例,来看源码。
|
||||||
|
>
|
||||||
```php
|
```php
|
||||||
namespace Hyperf\Di\Definition;
|
namespace Hyperf\Di\Definition;
|
||||||
|
|
||||||
@ -85,18 +146,18 @@ use function method_exists;
|
|||||||
|
|
||||||
class DefinitionSource implements DefinitionSourceInterface
|
class DefinitionSource implements DefinitionSourceInterface
|
||||||
{
|
{
|
||||||
protected array $source;
|
protected array $source; // [!code focus]
|
||||||
|
|
||||||
public function __construct(array $source)
|
public function __construct(array $source) // [!code focus:5]
|
||||||
{
|
{
|
||||||
// source 是服务提供者配置文件中的依赖配置信息
|
// source 是服务提供者配置文件中的依赖配置信息
|
||||||
$this->source = $this->normalizeSource($source);
|
$this->source = $this->normalizeSource($source);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Normalize the user definition source to a standard definition source.
|
* 将用户定义的源转换为标准源
|
||||||
*/
|
*/
|
||||||
protected function normalizeSource(array $source): array
|
protected function normalizeSource(array $source): array // [!code focus:11]
|
||||||
{
|
{
|
||||||
$definitions = [];
|
$definitions = [];
|
||||||
foreach ($source as $identifier => $definition) {
|
foreach ($source as $identifier => $definition) {
|
||||||
@ -107,24 +168,25 @@ class DefinitionSource implements DefinitionSourceInterface
|
|||||||
}
|
}
|
||||||
return $definitions;
|
return $definitions;
|
||||||
}
|
}
|
||||||
|
/** // [!code focus:23]
|
||||||
/**
|
|
||||||
* 绑定的内容可以是数组、类名、闭包
|
* 绑定的内容可以是数组、类名、闭包
|
||||||
* @param array|callable|string $definition
|
* @param array|callable|string $definition
|
||||||
*/
|
*/
|
||||||
protected function normalizeDefinition(string $identifier, $definition): ?DefinitionInterface
|
protected function normalizeDefinition(string $identifier, $definition): ?DefinitionInterface
|
||||||
{
|
{
|
||||||
if ($definition instanceof PriorityDefinition) {
|
if ($definition instanceof PriorityDefinition) {
|
||||||
$definition = $definition->getDefinition();
|
$definition = $definition->getDefinition();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_string($definition) && class_exists($definition)) {
|
if (is_string($definition) && class_exists($definition)) {
|
||||||
|
// 如果对应实现类存在__invoke方法,则包装为FactoryDefinition
|
||||||
if (method_exists($definition, '__invoke')) {
|
if (method_exists($definition, '__invoke')) {
|
||||||
return new FactoryDefinition($identifier, $definition, []);
|
return new FactoryDefinition($identifier, $definition, []);
|
||||||
}
|
}
|
||||||
|
// 普通实现则调用autowire自动装配方法
|
||||||
return $this->autowire($identifier, new ObjectDefinition($identifier, $definition));
|
return $this->autowire($identifier, new ObjectDefinition($identifier, $definition));
|
||||||
}
|
}
|
||||||
|
//如果是闭包,也包装为FactoryDefinition类
|
||||||
if (is_callable($definition)) {
|
if (is_callable($definition)) {
|
||||||
return new FactoryDefinition($identifier, $definition, []);
|
return new FactoryDefinition($identifier, $definition, []);
|
||||||
}
|
}
|
||||||
@ -134,7 +196,7 @@ class DefinitionSource implements DefinitionSourceInterface
|
|||||||
/**
|
/**
|
||||||
* 根据类名自动完成构造函数的依赖注入
|
* 根据类名自动完成构造函数的依赖注入
|
||||||
*/
|
*/
|
||||||
protected function autowire(string $name, ObjectDefinition $definition = null): ?ObjectDefinition
|
protected function autowire(string $name, ObjectDefinition $definition = null): ?ObjectDefinition // [!code focus:21]
|
||||||
{
|
{
|
||||||
$className = $definition ? $definition->getClassName() : $name;
|
$className = $definition ? $definition->getClassName() : $name;
|
||||||
if (! class_exists($className) && ! interface_exists($className)) {
|
if (! class_exists($className) && ! interface_exists($className)) {
|
||||||
@ -143,9 +205,7 @@ class DefinitionSource implements DefinitionSourceInterface
|
|||||||
|
|
||||||
$definition = $definition ?: new ObjectDefinition($name);
|
$definition = $definition ?: new ObjectDefinition($name);
|
||||||
|
|
||||||
/**
|
// 获取类反射,根据类的构造函数,自动注入依赖
|
||||||
* Constructor.
|
|
||||||
*/
|
|
||||||
$class = ReflectionManager::reflectClass($className);
|
$class = ReflectionManager::reflectClass($className);
|
||||||
$constructor = $class->getConstructor();
|
$constructor = $class->getConstructor();
|
||||||
if ($constructor && $constructor->isPublic()) {
|
if ($constructor && $constructor->isPublic()) {
|
||||||
@ -158,24 +218,32 @@ class DefinitionSource implements DefinitionSourceInterface
|
|||||||
}
|
}
|
||||||
|
|
||||||
```
|
```
|
||||||
> `normalizeSource`方法会将绑定的内容进行标准化,标准化后的内容是`DefinitionInterface`接口的实现类。(意思就是将绑定的`key`和`value`转换成`DefinitionInterface`接口的实现类)
|
|
||||||
|
|
||||||
最终,将绑定和对应的实现类保存到`$this->source`属性中。
|
::: tip
|
||||||
|
`normalizeSource`方法会将绑定的内容进行标准化,标准化后的内容是`DefinitionInterface`接口的实现类。(意思就是将绑定的`key`和`value`转换成`DefinitionInterface`接口的实现类)
|
||||||
|
:::
|
||||||
|
|
||||||
实际上,这里`(new DefinitionSourceFactory())()`执行过后返回的是一个`DefinitionSource`对象,该对象中保存了所有的绑定关系。
|
最终,将绑定和对应的实现类保存到`$this->source`属性中,返回自身实例。
|
||||||
|
|
||||||
|
> 实际上,这里`(new DefinitionSourceFactory())()`执行过后返回的是一个`DefinitionSource`对象,该对象中保存了所有的绑定关系。
|
||||||
|
|
||||||
|
### Container实例化
|
||||||
|
|
||||||
|
容器参数上面已经初始化完成,接下来进行容器的实例化。
|
||||||
|
|
||||||
然后继续往下看,
|
|
||||||
```php
|
```php
|
||||||
$container = new Container((new DefinitionSourceFactory())());
|
$container = new Container((new DefinitionSourceFactory())());
|
||||||
```
|
```
|
||||||
> 这里返回`DefinitionSource`对象后,再调用`new Container`方法,传入`DefinitionSource`对象,返回`Container`对象。
|
|
||||||
|
> 参数是`DefinitionSource`对象
|
||||||
|
|
||||||
查看`Container`类的构造函数源码,
|
查看`Container`类的构造函数源码,
|
||||||
|
|
||||||
```php
|
```php
|
||||||
public function __construct(protected Definition\DefinitionSourceInterface $definitionSource)
|
public function __construct(protected Definition\DefinitionSourceInterface $definitionSource)
|
||||||
{
|
{
|
||||||
$this->definitionResolver = new ResolverDispatcher($this);
|
$this->definitionResolver = new ResolverDispatcher($this);
|
||||||
// Auto-register the container.
|
// 将自身实例放到已解析绑定的数组中
|
||||||
$this->resolvedEntries = [
|
$this->resolvedEntries = [
|
||||||
self::class => $this,
|
self::class => $this,
|
||||||
PsrContainerInterface::class => $this,
|
PsrContainerInterface::class => $this,
|
||||||
@ -183,15 +251,124 @@ public function __construct(protected Definition\DefinitionSourceInterface $defi
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
总结:
|
|
||||||
|
构造函数所做的事情:
|
||||||
|
|
||||||
1. 将传入的`$definitionSource`对象放到`$this->definitionSource`属性中。
|
1. 将传入的`$definitionSource`对象放到`$this->definitionSource`属性中。
|
||||||
2. 创建`ResolverDispatcher`解析器,调度不同类型的解析器来处理容器中的定义,它会根据定义的类型(如类、工厂函数等)来选择适当的解析器进行解析
|
2. 创建`ResolverDispatcher`解析器,调度不同类型的解析器来处理容器中的定义,它会根据定义的类型(如类、工厂函数等)来选择适当的解析器进行解析
|
||||||
3. 注册容器本身的实例
|
::: details
|
||||||
|
|
||||||
|
```php
|
||||||
|
namespace Hyperf\Di\Resolver;
|
||||||
|
|
||||||
|
use Hyperf\Di\Definition\DefinitionInterface;
|
||||||
|
use Hyperf\Di\Definition\FactoryDefinition;
|
||||||
|
use Hyperf\Di\Definition\ObjectDefinition;
|
||||||
|
use Hyperf\Di\Definition\SelfResolvingDefinitionInterface;
|
||||||
|
use Hyperf\Di\Exception\InvalidDefinitionException;
|
||||||
|
use Psr\Container\ContainerInterface;
|
||||||
|
use RuntimeException;
|
||||||
|
|
||||||
|
class ResolverDispatcher implements ResolverInterface
|
||||||
|
{
|
||||||
|
protected ?ObjectResolver $objectResolver = null;
|
||||||
|
|
||||||
|
protected ?FactoryResolver $factoryResolver = null;
|
||||||
|
// 实例化传入容器对象
|
||||||
|
public function __construct(private ContainerInterface $container) // [!code focus:3]
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 解析definition对应的类实现或执行闭包
|
||||||
|
*
|
||||||
|
* @param DefinitionInterface $definition object that defines how the value should be obtained
|
||||||
|
* @param array $parameters optional parameters to use to build the entry
|
||||||
|
* @return mixed value obtained from the definition
|
||||||
|
* @throws InvalidDefinitionException if the definition cannot be resolved
|
||||||
|
*/
|
||||||
|
public function resolve(DefinitionInterface $definition, array $parameters = []) // [!code focus:15]
|
||||||
|
{
|
||||||
|
if ($definition instanceof SelfResolvingDefinitionInterface) {
|
||||||
|
return $definition->resolve($this->container);
|
||||||
|
}
|
||||||
|
|
||||||
|
$guard = DepthGuard::getInstance();
|
||||||
|
|
||||||
|
return $guard->call(
|
||||||
|
$definition->getName(),
|
||||||
|
fn () => $this->getDefinitionResolver($definition)->resolve($definition, $parameters)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断一个definition能否解析
|
||||||
|
*
|
||||||
|
* @param DefinitionInterface $definition object that defines how the value should be obtained
|
||||||
|
* @param array $parameters optional parameters to use to build the entry
|
||||||
|
*/
|
||||||
|
public function isResolvable(DefinitionInterface $definition, array $parameters = []): bool
|
||||||
|
{
|
||||||
|
if ($definition instanceof SelfResolvingDefinitionInterface) {
|
||||||
|
return $definition->isResolvable($this->container);
|
||||||
|
}
|
||||||
|
|
||||||
|
$guard = DepthGuard::getInstance();
|
||||||
|
|
||||||
|
return $guard->call(
|
||||||
|
$definition->getName(),
|
||||||
|
fn () => $this->getDefinitionResolver($definition)->isResolvable($definition, $parameters)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据definition类型,返回要使用的解析器
|
||||||
|
*
|
||||||
|
* @throws RuntimeException no definition resolver was found for this type of definition
|
||||||
|
*/
|
||||||
|
private function getDefinitionResolver(DefinitionInterface $definition): ResolverInterface // [!code focus:8]
|
||||||
|
{
|
||||||
|
return match (true) {
|
||||||
|
$definition instanceof ObjectDefinition => $this->objectResolver ??= new ObjectResolver($this->container, $this),
|
||||||
|
$definition instanceof FactoryDefinition => $this->factoryResolver ??= new FactoryResolver($this->container, $this),
|
||||||
|
default => throw new RuntimeException('No definition resolver was configured for definition of type ' . get_class($definition)),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
:::
|
||||||
|
3. 注册容器本身的实例
|
||||||
|
::: details
|
||||||
|
|
||||||
|
```php
|
||||||
|
$this->resolvedEntries = [
|
||||||
|
self::class => $this,
|
||||||
|
PsrContainerInterface::class => $this,
|
||||||
|
HyperfContainerInterface::class => $this,
|
||||||
|
];
|
||||||
|
```
|
||||||
|
|
||||||
|
:::
|
||||||
|
到此,容器实例化完成。
|
||||||
|
|
||||||
|
### ApplicationContext 类
|
||||||
|
|
||||||
|
```php
|
||||||
|
$container = new Container((new DefinitionSourceFactory())());
|
||||||
|
|
||||||
|
return ApplicationContext::setContainer($container); // [!code focus]
|
||||||
|
```
|
||||||
|
|
||||||
|
最后,将容器实例保存到`ApplicationContext`类的属性中。
|
||||||
|
后续在代码中获取容器类可以使用`ApplicationContext::getContainer()`方法获取容器实例。
|
||||||
|
|
||||||
|
## 总结
|
||||||
|
|
||||||
### 总结
|
|
||||||
1. 首先创建一个`DefinitionSourceFactory`工厂实例,并且触发该工厂实例的`__invoke`方法
|
1. 首先创建一个`DefinitionSourceFactory`工厂实例,并且触发该工厂实例的`__invoke`方法
|
||||||
2. `__invoke`方法中,首先加载配置文件包括类映射和依赖配置
|
2. `__invoke`方法中,首先加载配置文件包括类映射和依赖配置
|
||||||
3. 跟`config`目录下`dependencies.php`文件中的依赖配置进行合并
|
3. 跟`config`目录下`dependencies.php`文件中的依赖配置进行合并
|
||||||
4. 创建`DefinitionSource`对象,传入依赖配置信息,负责管理容器中的绑定关系和依赖注入的定义
|
4. 创建`DefinitionSource`对象,传入依赖配置信息,负责管理容器中的绑定关系和依赖注入的定义
|
||||||
5. 实例化容器对象,将`DefinitionSource`对象传入
|
5. 实例化容器对象,将`DefinitionSource`对象传入
|
||||||
6. 构造函数中实例化`ResolverDispatcher`调度器作为容器类的属性,并注册容器本身的实例
|
6. 构造函数中实例化`ResolverDispatcher`调度器作为容器类的属性,并注册容器本身的实例
|
||||||
|
1544
src/hyperf/启动服务.md
1544
src/hyperf/启动服务.md
File diff suppressed because it is too large
Load Diff
191
src/hyperf/附录1 container的get方法.md
Normal file
191
src/hyperf/附录1 container的get方法.md
Normal file
@ -0,0 +1,191 @@
|
|||||||
|
---
|
||||||
|
title: 附录1 container的get方法
|
||||||
|
---
|
||||||
|
|
||||||
|
分析一下`get`方法源码,
|
||||||
|
|
||||||
|
```php
|
||||||
|
public function get($id)
|
||||||
|
{
|
||||||
|
// 如果解析过,则直接返回
|
||||||
|
if (isset($this->resolvedEntries[$id]) || array_key_exists($id, $this->resolvedEntries)) {
|
||||||
|
return $this->resolvedEntries[$id];
|
||||||
|
}
|
||||||
|
return $this->resolvedEntries[$id] = $this->make($id);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
上面可以看出,首次解析不走`if`,查看`make`方法,
|
||||||
|
|
||||||
|
```php
|
||||||
|
public function make(string $name, array $parameters = [])
|
||||||
|
{
|
||||||
|
$definition = $this->getDefinition($name);
|
||||||
|
if (! $definition) {
|
||||||
|
throw new NotFoundException("No entry or class found for '{$name}'");
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->resolveDefinition($definition, $parameters);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
前面绑定阶段,已经将`ApplicationInterface`绑定到`Hyperf\Framework\ApplicationFactory`类上,通过`DefinitionSource`类,将对应实现转换成对应`DefinitionInterface`接口的实现类。
|
||||||
|
|
||||||
|
```php
|
||||||
|
// 调用逻辑
|
||||||
|
public function __construct(array $source)
|
||||||
|
{
|
||||||
|
$this->source = $this->normalizeSource($source);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function normalizeSource(array $source): array
|
||||||
|
{
|
||||||
|
$definitions = [];
|
||||||
|
foreach ($source as $identifier => $definition) {
|
||||||
|
$normalizedDefinition = $this->normalizeDefinition($identifier, $definition);
|
||||||
|
if (! is_null($normalizedDefinition)) {
|
||||||
|
$definitions[$identifier] = $normalizedDefinition;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $definitions;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function normalizeDefinition(string $identifier, $definition): ?DefinitionInterface
|
||||||
|
{
|
||||||
|
if ($definition instanceof PriorityDefinition) {
|
||||||
|
$definition = $definition->getDefinition();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (is_string($definition) && class_exists($definition)) {
|
||||||
|
if (method_exists($definition, '__invoke')) {
|
||||||
|
return new FactoryDefinition($identifier, $definition, []);
|
||||||
|
}
|
||||||
|
return $this->autowire($identifier, new ObjectDefinition($identifier, $definition));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_callable($definition)) {
|
||||||
|
return new FactoryDefinition($identifier, $definition, []);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
查看`ApplicationFactory`类,存在`__invoke`方法,返回的是一个`FactoryDefinition`对象。
|
||||||
|
![](image <https://oss.xiaokeaii.top/2024/applicationFactory.png>)
|
||||||
|
|
||||||
|
```php
|
||||||
|
$definition = $this->getDefinition($name);
|
||||||
|
```
|
||||||
|
|
||||||
|
所以这行返回的是一个`FactoryDefinition`对象。打印结果如下,
|
||||||
|
![](image <https://oss.xiaokeaii.top/2024/工厂定义.png> )
|
||||||
|
|
||||||
|
#### resolveDefinition方法
|
||||||
|
|
||||||
|
继续分析,查看`resolveDefinition`方法,
|
||||||
|
> 文件位置: /vendor/hyperf/di/src/Container.php
|
||||||
|
|
||||||
|
```php
|
||||||
|
protected function resolveDefinition(DefinitionInterface $definition, array $parameters = [])
|
||||||
|
{
|
||||||
|
return $this->definitionResolver->resolve($definition, $parameters);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
上面可以看到,这里调用了解析调度器`ResolverDispatcher`的`resolve`方法。
|
||||||
|
|
||||||
|
##### resolve方法
|
||||||
|
>
|
||||||
|
> 文件位置:/vendor/hyperf/di/src/Resolver/ResolverDispatcher.php
|
||||||
|
|
||||||
|
```php
|
||||||
|
public function resolve(DefinitionInterface $definition, array $parameters = [])
|
||||||
|
{
|
||||||
|
if ($definition instanceof SelfResolvingDefinitionInterface) {
|
||||||
|
|
||||||
|
return $definition->resolve($this->container);
|
||||||
|
}
|
||||||
|
$guard = DepthGuard::getInstance();
|
||||||
|
|
||||||
|
return $guard->call(
|
||||||
|
$definition->getName(),
|
||||||
|
fn () => $this->getDefinitionResolver($definition)->resolve($definition, $parameters)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
这里`FactoryDefinition`不是`SelfResolvingDefinitionInterface`接口的实现类,所以不走`if`。
|
||||||
|
`$guard`是`DepthGuard`类的实例,调用`call`方法,
|
||||||
|
|
||||||
|
###### call方法
|
||||||
|
>
|
||||||
|
> 文件位置:/vendor/hyperf/di/src/Resolver/DepthGuard.php
|
||||||
|
|
||||||
|
```php
|
||||||
|
public function call(string $name, callable $callable)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$this->increment();
|
||||||
|
return $callable();
|
||||||
|
} catch (CircularDependencyException $exception) {
|
||||||
|
$exception->addDefinitionName($name);
|
||||||
|
throw $exception;
|
||||||
|
} finally {
|
||||||
|
$this->decrement();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
这里最终执行传入的闭包,回到上面,执行闭包。
|
||||||
|
查看闭包执行源码,
|
||||||
|
> ./vendor/hyperf/di/src/Resolver/ResolverDispatcher.php
|
||||||
|
>
|
||||||
|
##### getDefinitionResolver方法
|
||||||
|
|
||||||
|
```php
|
||||||
|
private function getDefinitionResolver(DefinitionInterface $definition): ResolverInterface
|
||||||
|
{
|
||||||
|
return match (true) {
|
||||||
|
$definition instanceof ObjectDefinition => $this->objectResolver ??= new ObjectResolver($this->container, $this),
|
||||||
|
$definition instanceof FactoryDefinition => $this->factoryResolver ??= new FactoryResolver($this->container, $this),
|
||||||
|
default => throw new RuntimeException('No definition resolver was configured for definition of type ' . get_class($definition)),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
从代码可知,这里会根据`DefinitionInterface`的实现类,将对应解析器赋值给成员变量。
|
||||||
|
这里传进来的是`FactoryDefinition`类,所以会执行第二条。
|
||||||
|
紧接着调用`FactoryResolver`类的`resolve`方法。
|
||||||
|
|
||||||
|
###### resolve方法
|
||||||
|
>
|
||||||
|
> 文件位置:/vendor/hyperf/di/src/Resolver/FactoryResolver.php
|
||||||
|
|
||||||
|
```php
|
||||||
|
public function resolve(DefinitionInterface $definition, array $parameters = [])
|
||||||
|
{
|
||||||
|
$callable = null;
|
||||||
|
try {
|
||||||
|
$callable = $definition->getFactory();
|
||||||
|
if (! method_exists($callable, '__invoke')) {
|
||||||
|
throw new NotCallableException();
|
||||||
|
}
|
||||||
|
if (is_string($callable)) {
|
||||||
|
$callable = $this->container->get($callable);
|
||||||
|
}
|
||||||
|
return $callable($this->container, $parameters);
|
||||||
|
} catch (NotCallableException $e) {
|
||||||
|
// Custom error message to help debugging
|
||||||
|
if (is_string($callable) && class_exists($callable) && method_exists($callable, '__invoke')) {
|
||||||
|
throw new InvalidDefinitionException(sprintf('Entry "%s" cannot be resolved: factory %s. Invokable classes cannot be automatically resolved if autowiring is disabled on the container, you need to enable autowiring or define the entry manually.', $definition->getName(), $e->getMessage()));
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new InvalidDefinitionException(sprintf('Entry "%s" cannot be resolved: factory %s', $definition->getName(), $e->getMessage()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
分析该方法,`$callable`是工厂的类名,如果传递过来的是字符串,则通过容器解析出对应的类,方法同理,不再赘述。
|
||||||
|
最终调用该工厂类的`__invoke`方法返回解析结果。
|
3
src/hyperf/附录2 注解命令获取.md
Normal file
3
src/hyperf/附录2 注解命令获取.md
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
---
|
||||||
|
title: 附录2 注解命令获取
|
||||||
|
---
|
65
src/hyperf/附录3 命令注册Application.md
Normal file
65
src/hyperf/附录3 命令注册Application.md
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
---
|
||||||
|
title: 附录3 命令注册Application
|
||||||
|
---
|
||||||
|
|
||||||
|
### 注册命令
|
||||||
|
|
||||||
|
查看`Application`类的`add`方法,
|
||||||
|
|
||||||
|
```php
|
||||||
|
public function add(Command $command)
|
||||||
|
{
|
||||||
|
$this->init();
|
||||||
|
|
||||||
|
$command->setApplication($this);
|
||||||
|
|
||||||
|
if (!$command->isEnabled()) {
|
||||||
|
$command->setApplication(null);
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$command instanceof LazyCommand) {
|
||||||
|
// Will throw if the command is not correctly initialized.
|
||||||
|
$command->getDefinition();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$command->getName()) {
|
||||||
|
throw new LogicException(sprintf('The command defined in "%s" cannot have an empty name.', get_debug_type($command)));
|
||||||
|
}
|
||||||
|
// 重点看这行,将命令的名称以及对应实现添加到命令属性中
|
||||||
|
$this->commands[$command->getName()] = $command;
|
||||||
|
|
||||||
|
foreach ($command->getAliases() as $alias) {
|
||||||
|
$this->commands[$alias] = $command;
|
||||||
|
}
|
||||||
|
return $command;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
打印配置的命令数组,打开第一个`/vendor/hyperf/server/src/Command/StartServer.php`命令类,
|
||||||
|
![](image <https://oss.xiaokeaii.top/2024/start.png>)
|
||||||
|
> 我们可以发现,在父类的构造方法中,会将`name`赋值给该命令类的成员变量,之后通过`getName`方法获取命令的名称
|
||||||
|
|
||||||
|
```php
|
||||||
|
public function __construct(private ContainerInterface $container)
|
||||||
|
{
|
||||||
|
parent::__construct('start');
|
||||||
|
$this->setDescription('Start hyperf servers.');
|
||||||
|
}
|
||||||
|
// StartServer的父类的构造方法
|
||||||
|
public function __construct(?string $name = null)
|
||||||
|
{
|
||||||
|
$this->definition = new InputDefinition();
|
||||||
|
//...
|
||||||
|
if (null !== $name) {
|
||||||
|
$this->setName($name);
|
||||||
|
}
|
||||||
|
//...
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getName(): ?string
|
||||||
|
{
|
||||||
|
return $this->name;
|
||||||
|
}
|
||||||
|
```
|
408
src/hyperf/附录4 Application_Run.md
Normal file
408
src/hyperf/附录4 Application_Run.md
Normal file
@ -0,0 +1,408 @@
|
|||||||
|
---
|
||||||
|
title: 附录4 Application_Run
|
||||||
|
---
|
||||||
|
```php
|
||||||
|
(function () {
|
||||||
|
Hyperf\Di\ClassLoader::init();
|
||||||
|
/** @var Psr\Container\ContainerInterface $container */
|
||||||
|
$container = require BASE_PATH . '/config/container.php';
|
||||||
|
|
||||||
|
$application = $container->get(Hyperf\Contract\ApplicationInterface::class);
|
||||||
|
$application->run(); // [!code focus]
|
||||||
|
})();
|
||||||
|
```
|
||||||
|
|
||||||
|
从上面分析可知,`$application`是一个`Symfony\Component\Console\Application`对象,调用`run`方法。
|
||||||
|
先看源码,
|
||||||
|
|
||||||
|
```php
|
||||||
|
public function run(?InputInterface $input = null, ?OutputInterface $output = null): int
|
||||||
|
{
|
||||||
|
// 设置终端的高度和宽度
|
||||||
|
if (\function_exists('putenv')) {
|
||||||
|
@putenv('LINES='.$this->terminal->getHeight());
|
||||||
|
@putenv('COLUMNS='.$this->terminal->getWidth());
|
||||||
|
}
|
||||||
|
// 初始化输入和输出对象,如果没有提供输入和输出对象,则创建默认
|
||||||
|
$input ??= new ArgvInput();
|
||||||
|
$output ??= new ConsoleOutput();
|
||||||
|
// 渲染异常的闭包函数
|
||||||
|
$renderException = function (\Throwable $e) use ($output) {
|
||||||
|
if ($output instanceof ConsoleOutputInterface) {
|
||||||
|
$this->renderThrowable($e, $output->getErrorOutput());
|
||||||
|
} else {
|
||||||
|
$this->renderThrowable($e, $output);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if ($phpHandler = set_exception_handler($renderException)) {
|
||||||
|
restore_exception_handler();
|
||||||
|
if (!\is_array($phpHandler) || !$phpHandler[0] instanceof ErrorHandler) {
|
||||||
|
$errorHandler = true;
|
||||||
|
} elseif ($errorHandler = $phpHandler[0]->setExceptionHandler($renderException)) {
|
||||||
|
$phpHandler[0]->setExceptionHandler($errorHandler);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 根据输入参数和环境变量配置输入和输出对象
|
||||||
|
$this->configureIO($input, $output);
|
||||||
|
|
||||||
|
try {
|
||||||
|
$exitCode = $this->doRun($input, $output);
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
if ($e instanceof \Exception && !$this->catchExceptions) {
|
||||||
|
throw $e;
|
||||||
|
}
|
||||||
|
if (!$e instanceof \Exception && !$this->catchErrors) {
|
||||||
|
throw $e;
|
||||||
|
}
|
||||||
|
|
||||||
|
$renderException($e);
|
||||||
|
|
||||||
|
$exitCode = $e->getCode();
|
||||||
|
if (is_numeric($exitCode)) {
|
||||||
|
$exitCode = (int) $exitCode;
|
||||||
|
if ($exitCode <= 0) {
|
||||||
|
$exitCode = 1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$exitCode = 1;
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
// if the exception handler changed, keep it
|
||||||
|
// otherwise, unregister $renderException
|
||||||
|
if (!$phpHandler) {
|
||||||
|
if (set_exception_handler($renderException) === $renderException) {
|
||||||
|
restore_exception_handler();
|
||||||
|
}
|
||||||
|
restore_exception_handler();
|
||||||
|
} elseif (!$errorHandler) {
|
||||||
|
$finalHandler = $phpHandler[0]->setExceptionHandler(null);
|
||||||
|
if ($finalHandler !== $renderException) {
|
||||||
|
$phpHandler[0]->setExceptionHandler($finalHandler);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->autoExit) {
|
||||||
|
if ($exitCode > 255) {
|
||||||
|
$exitCode = 255;
|
||||||
|
}
|
||||||
|
|
||||||
|
exit($exitCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $exitCode;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### doRun方法
|
||||||
|
>
|
||||||
|
> 文件位置:/vendor/symfony/console/Application.php
|
||||||
|
|
||||||
|
```php
|
||||||
|
public function doRun(InputInterface $input, OutputInterface $output)
|
||||||
|
{
|
||||||
|
// 输出版本信息
|
||||||
|
if (true === $input->hasParameterOption(['--version', '-V'], true)) {
|
||||||
|
$output->writeln($this->getLongVersion());
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Makes ArgvInput::getFirstArgument() able to distinguish an option from an argument.
|
||||||
|
$input->bind($this->getDefinition());
|
||||||
|
} catch (ExceptionInterface) {
|
||||||
|
// Errors must be ignored, full binding/validation happens later when the command is known.
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取命令名称,项目启动代码是 php bin/hyperf.php start,
|
||||||
|
// 所以命令名称就是 start
|
||||||
|
$name = $this->getCommandName($input);
|
||||||
|
// 如果命令名称是--help,则显示帮助信息
|
||||||
|
if (true === $input->hasParameterOption(['--help', '-h'], true)) {
|
||||||
|
if (!$name) {
|
||||||
|
$name = 'help';
|
||||||
|
$input = new ArrayInput(['command_name' => $this->defaultCommand]);
|
||||||
|
} else {
|
||||||
|
$this->wantHelps = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 如果命令名称不存在,则显示默认信息
|
||||||
|
if (!$name) {
|
||||||
|
$name = $this->defaultCommand;
|
||||||
|
$definition = $this->getDefinition();
|
||||||
|
$definition->setArguments(array_merge(
|
||||||
|
$definition->getArguments(),
|
||||||
|
[
|
||||||
|
'command' => new InputArgument('command', InputArgument::OPTIONAL, $definition->getArgument('command')->getDescription(), $name),
|
||||||
|
]
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$this->runningCommand = null;
|
||||||
|
// 从应用中找到对应的命令
|
||||||
|
$command = $this->find($name);
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
// 找不到的时候的异常处理
|
||||||
|
if (($e instanceof CommandNotFoundException && !$e instanceof NamespaceNotFoundException) && 1 === \count($alternatives = $e->getAlternatives()) && $input->isInteractive()) {
|
||||||
|
$alternative = $alternatives[0];
|
||||||
|
|
||||||
|
$style = new SymfonyStyle($input, $output);
|
||||||
|
$output->writeln('');
|
||||||
|
$formattedBlock = (new FormatterHelper())->formatBlock(sprintf('Command "%s" is not defined.', $name), 'error', true);
|
||||||
|
$output->writeln($formattedBlock);
|
||||||
|
if (!$style->confirm(sprintf('Do you want to run "%s" instead? ', $alternative), false)) {
|
||||||
|
if (null !== $this->dispatcher) {
|
||||||
|
$event = new ConsoleErrorEvent($input, $output, $e);
|
||||||
|
$this->dispatcher->dispatch($event, ConsoleEvents::ERROR);
|
||||||
|
|
||||||
|
return $event->getExitCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
$command = $this->find($alternative);
|
||||||
|
} else {
|
||||||
|
if (null !== $this->dispatcher) {
|
||||||
|
$event = new ConsoleErrorEvent($input, $output, $e);
|
||||||
|
$this->dispatcher->dispatch($event, ConsoleEvents::ERROR);
|
||||||
|
|
||||||
|
if (0 === $event->getExitCode()) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
$e = $event->getError();
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
if ($e instanceof CommandNotFoundException && $namespace = $this->findNamespace($name)) {
|
||||||
|
$helper = new DescriptorHelper();
|
||||||
|
$helper->describe($output instanceof ConsoleOutputInterface ? $output->getErrorOutput() : $output, $this, [
|
||||||
|
'format' => 'txt',
|
||||||
|
'raw_text' => false,
|
||||||
|
'namespace' => $namespace,
|
||||||
|
'short' => false,
|
||||||
|
]);
|
||||||
|
|
||||||
|
return isset($event) ? $event->getExitCode() : 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw $e;
|
||||||
|
} catch (NamespaceNotFoundException) {
|
||||||
|
throw $e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 如果commend继承LazyCommand类,则属于懒加载命令
|
||||||
|
// 延迟实例化命令对象,以提高应用程序启动速度
|
||||||
|
if ($command instanceof LazyCommand) {
|
||||||
|
$command = $command->getCommand();
|
||||||
|
}
|
||||||
|
// 将运行的命令赋值给runningCommand属性
|
||||||
|
$this->runningCommand = $command;
|
||||||
|
// 执行命令
|
||||||
|
$exitCode = $this->doRunCommand($command, $input, $output);
|
||||||
|
$this->runningCommand = null;
|
||||||
|
|
||||||
|
return $exitCode;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
##### doRunCommand方法
|
||||||
|
|
||||||
|
这里正式进行命令的执行操作; 我们的启动命令是`start`,我们就以`start`命令为例,该命令对应的类是`StartServer`。
|
||||||
|
|
||||||
|
> 文件位置:/vendor/symfony/console/Application.php
|
||||||
|
|
||||||
|
```php
|
||||||
|
protected function doRunCommand(Command $command, InputInterface $input, OutputInterface $output)
|
||||||
|
{
|
||||||
|
// 循环命令的帮助器集合,初始化时未配置,默认是有4个
|
||||||
|
// return new HelperSet([
|
||||||
|
// new FormatterHelper(),
|
||||||
|
// new DebugFormatterHelper(),
|
||||||
|
// new ProcessHelper(),
|
||||||
|
// new QuestionHelper(),
|
||||||
|
// ]);
|
||||||
|
foreach ($command->getHelperSet() as $helper) {
|
||||||
|
if ($helper instanceof InputAwareInterface) {
|
||||||
|
$helper->setInput($input);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 获取当前命令是否实现了`SignalableCommandInterface`接口,如果是,获取订阅的信号列表
|
||||||
|
// $commandSignals = $command instanceof SignalableCommandInterface ? $command->getSubscribedSignals() : [];
|
||||||
|
// 检查是否存在需要处理的信号或者事件,$commandSignals初始化时为空,不处理信号
|
||||||
|
// if ($commandSignals || $this->dispatcher && $this->signalsToDispatchEvent) {
|
||||||
|
// if (!$this->signalRegistry) {
|
||||||
|
// throw new RuntimeException('Unable to subscribe to signal events. Make sure that the "pcntl" extension is installed and that "pcntl_*" functions are not disabled by your php.ini\'s "disable_functions" directive.');
|
||||||
|
// }
|
||||||
|
|
||||||
|
// if (Terminal::hasSttyAvailable()) {
|
||||||
|
// $sttyMode = shell_exec('stty -g');
|
||||||
|
|
||||||
|
// foreach ([\SIGINT, \SIGTERM] as $signal) {
|
||||||
|
// $this->signalRegistry->register($signal, static fn () => shell_exec('stty '.$sttyMode));
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// if ($this->dispatcher) {
|
||||||
|
// // We register application signals, so that we can dispatch the event
|
||||||
|
// foreach ($this->signalsToDispatchEvent as $signal) {
|
||||||
|
// $event = new ConsoleSignalEvent($command, $input, $output, $signal);
|
||||||
|
|
||||||
|
// $this->signalRegistry->register($signal, function ($signal) use ($event, $command, $commandSignals) {
|
||||||
|
// $this->dispatcher->dispatch($event, ConsoleEvents::SIGNAL);
|
||||||
|
// $exitCode = $event->getExitCode();
|
||||||
|
|
||||||
|
// // If the command is signalable, we call the handleSignal() method
|
||||||
|
// if (\in_array($signal, $commandSignals, true)) {
|
||||||
|
// $exitCode = $command->handleSignal($signal, $exitCode);
|
||||||
|
// // BC layer for Symfony <= 5
|
||||||
|
// if (null === $exitCode) {
|
||||||
|
// trigger_deprecation('symfony/console', '6.3', 'Not returning an exit code from "%s::handleSignal()" is deprecated, return "false" to keep the command running or "0" to exit successfully.', get_debug_type($command));
|
||||||
|
// $exitCode = 0;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// if (false !== $exitCode) {
|
||||||
|
// $event = new ConsoleTerminateEvent($command, $event->getInput(), $event->getOutput(), $exitCode, $signal);
|
||||||
|
// $this->dispatcher->dispatch($event, ConsoleEvents::TERMINATE);
|
||||||
|
|
||||||
|
// exit($event->getExitCode());
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // then we register command signals, but not if already handled after the dispatcher
|
||||||
|
// $commandSignals = array_diff($commandSignals, $this->signalsToDispatchEvent);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// foreach ($commandSignals as $signal) {
|
||||||
|
// $this->signalRegistry->register($signal, function (int $signal) use ($command): void {
|
||||||
|
// $exitCode = $command->handleSignal($signal);
|
||||||
|
// // BC layer for Symfony <= 5
|
||||||
|
// if (null === $exitCode) {
|
||||||
|
// trigger_deprecation('symfony/console', '6.3', 'Not returning an exit code from "%s::handleSignal()" is deprecated, return "false" to keep the command running or "0" to exit successfully.', get_debug_type($command));
|
||||||
|
// $exitCode = 0;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// if (false !== $exitCode) {
|
||||||
|
// exit($exitCode);
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// 进入该方法
|
||||||
|
if (null === $this->dispatcher) {
|
||||||
|
return $command->run($input, $output);
|
||||||
|
}
|
||||||
|
|
||||||
|
// // bind before the console.command event, so the listeners have access to input options/arguments
|
||||||
|
// try {
|
||||||
|
// $command->mergeApplicationDefinition();
|
||||||
|
// $input->bind($command->getDefinition());
|
||||||
|
// } catch (ExceptionInterface) {
|
||||||
|
// // ignore invalid options/arguments for now, to allow the event listeners to customize the InputDefinition
|
||||||
|
// }
|
||||||
|
|
||||||
|
// $event = new ConsoleCommandEvent($command, $input, $output);
|
||||||
|
// $e = null;
|
||||||
|
|
||||||
|
// try {
|
||||||
|
// $this->dispatcher->dispatch($event, ConsoleEvents::COMMAND);
|
||||||
|
|
||||||
|
// if ($event->commandShouldRun()) {
|
||||||
|
// $exitCode = $command->run($input, $output);
|
||||||
|
// } else {
|
||||||
|
// $exitCode = ConsoleCommandEvent::RETURN_CODE_DISABLED;
|
||||||
|
// }
|
||||||
|
// } catch (\Throwable $e) {
|
||||||
|
// $event = new ConsoleErrorEvent($input, $output, $e, $command);
|
||||||
|
// $this->dispatcher->dispatch($event, ConsoleEvents::ERROR);
|
||||||
|
// $e = $event->getError();
|
||||||
|
|
||||||
|
// if (0 === $exitCode = $event->getExitCode()) {
|
||||||
|
// $e = null;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// $event = new ConsoleTerminateEvent($command, $input, $output, $exitCode);
|
||||||
|
// $this->dispatcher->dispatch($event, ConsoleEvents::TERMINATE);
|
||||||
|
|
||||||
|
// if (null !== $e) {
|
||||||
|
// throw $e;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// return $event->getExitCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
||||||
|
查看`StartServer`中,没有`run`方法,查看父类`Command`,
|
||||||
|
> 文件位置: /vendor/symfony/console/Command/Command.php
|
||||||
|
|
||||||
|
```php
|
||||||
|
public function run(InputInterface $input, OutputInterface $output): int
|
||||||
|
{
|
||||||
|
// add the application arguments and options
|
||||||
|
$this->mergeApplicationDefinition();
|
||||||
|
|
||||||
|
// bind the input against the command specific arguments/options
|
||||||
|
try {
|
||||||
|
$input->bind($this->getDefinition());
|
||||||
|
} catch (ExceptionInterface $e) {
|
||||||
|
if (!$this->ignoreValidationErrors) {
|
||||||
|
throw $e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->initialize($input, $output);
|
||||||
|
|
||||||
|
// if (null !== $this->processTitle) {
|
||||||
|
// if (\function_exists('cli_set_process_title')) {
|
||||||
|
// if (!@cli_set_process_title($this->processTitle)) {
|
||||||
|
// if ('Darwin' === \PHP_OS) {
|
||||||
|
// $output->writeln('<comment>Running "cli_set_process_title" as an unprivileged user is not supported on MacOS.</comment>', OutputInterface::VERBOSITY_VERY_VERBOSE);
|
||||||
|
// } else {
|
||||||
|
// cli_set_process_title($this->processTitle);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// } elseif (\function_exists('setproctitle')) {
|
||||||
|
// setproctitle($this->processTitle);
|
||||||
|
// } elseif (OutputInterface::VERBOSITY_VERY_VERBOSE === $output->getVerbosity()) {
|
||||||
|
// $output->writeln('<comment>Install the proctitle PECL to be able to change the process title.</comment>');
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// if ($input->isInteractive()) {
|
||||||
|
// $this->interact($input, $output);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // The command name argument is often omitted when a command is executed directly with its run() method.
|
||||||
|
// // It would fail the validation if we didn't make sure the command argument is present,
|
||||||
|
// // since it's required by the application.
|
||||||
|
// if ($input->hasArgument('command') && null === $input->getArgument('command')) {
|
||||||
|
// $input->setArgument('command', $this->getName());
|
||||||
|
// }
|
||||||
|
|
||||||
|
$input->validate();
|
||||||
|
|
||||||
|
if ($this->code) {
|
||||||
|
$statusCode = ($this->code)($input, $output);
|
||||||
|
} else {
|
||||||
|
// 最终会执行execute方法
|
||||||
|
$statusCode = $this->execute($input, $output);
|
||||||
|
|
||||||
|
if (!\is_int($statusCode)) {
|
||||||
|
throw new \TypeError(sprintf('Return value of "%s::execute()" must be of the type int, "%s" returned.', static::class, get_debug_type($statusCode)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return is_numeric($statusCode) ? (int) $statusCode : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
分析上面代码可知,`run`方法最终会调用`execute`方法,继续往下看。
|
Loading…
Reference in New Issue
Block a user