Skip to content

初始化容器类

本节分析容器类的实例化过程,

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

这是容器类初始化的代码,

php
use Hyperf\Context\ApplicationContext;
use Hyperf\Di\Container;
use Hyperf\Di\Definition\DefinitionSourceFactory;

$container = new Container((new DefinitionSourceFactory())()); 

return ApplicationContext::setContainer($container);

提示

首先,可以看出,先是实例化了DefinitionSourceFactory类,然后使用方法的调用方式调用类,会触发该类的__invoke方法,最后返回的内容作为Container类的构造函数的参数,然后返回实例化后的容器类。

生成包含依赖关系和配置的定义源

查看DefinitionSourceFactory工厂类做了哪些工作,

php
declare(strict_types=1);
namespace Hyperf\Di\Definition;

use Hyperf\Config\ProviderConfig;
use Hyperf\Di\Exception\Exception;

class DefinitionSourceFactory
{
    public function __invoke(): DefinitionSource
    {
        if (! defined('BASE_PATH')) {
            throw new Exception('BASE_PATH is not defined.');
        }

        // 该方法上面一节分析过,获取所有的服务提供者返回的配置信息数组
        $configFromProviders = [];
        if (class_exists(ProviderConfig::class)) {
            $configFromProviders = :ProviderConfig:load();
        }

        $serverDependencies = $configFromProviders['dependencies'] ?? [];
        $dependenciesPath = BASE_PATH . '/config/autoload/dependencies.php';
        if (file_exists($dependenciesPath)) {
            $definitions = include $dependenciesPath;
            $serverDependencies = array_replace($serverDependencies, $definitions ?? []);
        }
        // 返回DefinitionSource对象
        return new DefinitionSource($serverDependencies);
    }
}

只有一个方法,也是会被调用的__invoke方法,获取依赖信息,并作为参数传递给DefinitionSource用作实例化参数。

$serverDependencies数组具体内容如下,

点我查看
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
)

可以看出,基本上是接口绑定对应的实现类。

将抽象接口或类绑定到其对应的实现类或实例

DefinitionSource类是管理容器中的绑定关系,即将抽象接口或类绑定到其对应的实现类或实例,来看源码。

php
namespace Hyperf\Di\Definition;

use Hyperf\Di\ReflectionManager;
use ReflectionFunctionAbstract;
use ReflectionNamedType;

use function class_exists;
use function interface_exists;
use function is_callable;
use function is_string;
use function method_exists;

class DefinitionSource implements DefinitionSourceInterface
{
    protected array $source; 

    public function __construct(array $source) 
    {
        // 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;
    }
    /**
     * 绑定的内容可以是数组、类名、闭包
     * @param array|callable|string $definition
     */
    protected function normalizeDefinition(string $identifier, $definition): ?DefinitionInterface 
    {
        if ($definition instanceof PriorityDefinition) {
            $definition = $definition->getDefinition();
        }

        if (is_string($definition) && class_exists($definition)) {
            // 如果对应实现类存在__invoke方法,则包装为FactoryDefinition
            if (method_exists($definition, '__invoke')) {
                return new FactoryDefinition($identifier, $definition, []);
            }
            // 普通实现则调用autowire自动装配方法
            return $this->autowire($identifier, new ObjectDefinition($identifier, $definition));
        }
        //如果是闭包,也包装为FactoryDefinition类
        if (is_callable($definition)) {
            return new FactoryDefinition($identifier, $definition, []);
        }

        return null;
    }
    /**
     * 根据类名自动完成构造函数的依赖注入
     */
    protected function autowire(string $name, ObjectDefinition $definition = null): ?ObjectDefinition
    {
        $className = $definition ? $definition->getClassName() : $name;
        if (! class_exists($className) && ! interface_exists($className)) {
            return $definition;
        }

        $definition = $definition ?: new ObjectDefinition($name);

        // 获取类反射,根据类的构造函数,自动注入依赖
        $class = ReflectionManager::reflectClass($className);
        $constructor = $class->getConstructor();
        if ($constructor && $constructor->isPublic()) {
            $constructorInjection = new MethodInjection('__construct', $this->getParametersDefinition($constructor));
            $definition->completeConstructorInjection($constructorInjection);
        }

        return $definition;
    }
}

提示

normalizeSource方法会将绑定的内容进行标准化,标准化后的内容是DefinitionInterface接口的实现类。(意思就是将绑定的keyvalue转换成DefinitionInterface接口的实现类)

最终,将绑定和对应的实现类保存到$this->source属性中,返回自身实例。

实际上,这里(new DefinitionSourceFactory())()执行过后返回的是一个DefinitionSource对象,该对象中保存了所有的绑定关系。

Container实例化

容器参数上面已经初始化完成,接下来进行容器的实例化。

php
$container = new Container((new DefinitionSourceFactory())());

参数是DefinitionSource对象

查看Container类的构造函数源码,

php
public function __construct(protected Definition\DefinitionSourceInterface $definitionSource)
{
    $this->definitionResolver = new ResolverDispatcher($this);
    // 将自身实例放到已解析绑定的数组中
    $this->resolvedEntries = [
        self::class => $this,
        PsrContainerInterface::class => $this,
        HyperfContainerInterface::class => $this,
    ];
}

构造函数所做的事情:

  1. 将传入的$definitionSource对象放到$this->definitionSource属性中。
  2. 创建ResolverDispatcher解析器,调度不同类型的解析器来处理容器中的定义,它会根据定义的类型(如类、工厂函数等)来选择适当的解析器进行解析
点我查看
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) 
    {
    }

    /**
     * 解析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 = []) 
    {
        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
    {
        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)),
        };
    }
}
  1. 注册容器本身的实例
点我查看
php
$this->resolvedEntries = [
     self::class => $this,
     PsrContainerInterface::class => $this,
     HyperfContainerInterface::class => $this,
 ];

到此,容器实例化完成。

ApplicationContext 类

php
$container = new Container((new DefinitionSourceFactory())());

return ApplicationContext::setContainer($container); 

最后,将容器实例保存到ApplicationContext类的属性中。 后续在代码中获取容器类可以使用ApplicationContext::getContainer()方法获取容器实例。

总结

  1. 首先创建一个DefinitionSourceFactory工厂实例,并且触发该工厂实例的__invoke方法
  2. __invoke方法中,首先加载配置文件包括类映射和依赖配置
  3. config目录下dependencies.php文件中的依赖配置进行合并
  4. 创建DefinitionSource对象,传入依赖配置信息,负责管理容器中的绑定关系和依赖注入的定义
  5. 实例化容器对象,将DefinitionSource对象传入
  6. 构造函数中实例化ResolverDispatcher调度器作为容器类的属性,并注册容器本身的实例