snicco/kernel

snicco 框架的核心

v2.0.0-beta.9 2024-09-07 14:27 UTC

README

codecov Psalm Type-Coverage Psalm level PhpMetrics - Static Analysis PHP-Versions

Kernel 组件是 Snicco 项目 的核心,它帮助启动使用插件架构的应用程序。

目录

  1. 安装
  2. 定义
    1. Kernel
    2. 引导器
    3. 环境
    4. 目录
    5. 配置文件
  3. 使用方法
    1. 创建 Kernel
    2. 启动 Kernel
    3. 生命周期钩子
    4. 使用启动的 Kernel
  4. 贡献
  5. 问题和 PR
  6. 安全性

安装

composer require snicco/kernel

定义

Kernel

Kernel 类帮助加载和缓存配置文件,在依赖注入容器中定义服务,并使用任意数量的 引导器 以受控方式启动应用程序。

引导器

引导器可以是实现 Bootstrapper 接口 的任何类。

引导器是一个负责“引导”应用程序某个统一部分的类。

“引导”可能意味着,例如:在依赖注入容器中注册定义或创建事件监听器。

引导器是配置应用程序的中心位置。

interface Bootstrapper
{
    public function shouldRun(Environment $env): bool;

    public function configure(WritableConfig $config, Kernel $kernel): void;

    public function register(Kernel $kernel): void;

    public function bootstrap(Kernel $kernel): void;
}

包可以是实现 Bundle 接口 的任何类。该 Bundle 接口扩展了 Bootstrapper 接口。

interface Bundle extends Bootstrapper
{
    public function alias(): string;
}

包和引导器的区别在于,包旨在公开分发,而引导器是特定应用程序内部的。

包了解由同一 Kernel 实例使用的其他包。

环境

Kernel 总是需要一个环境来运行。

以下环境是可能的

  • 生产
  • 预发布
  • 开发
  • 测试
  • 调试(与非生产环境组合使用)
use Snicco\Component\Kernel\ValueObject\Environment;

$environment = Environment::prod()
$environment = Environment::testing()
$environment = Environment::staging()
$environment = Environment::dev()
$environment = Environment::fromString(getenv('APP_ENV'));

目录

Kernel 总是需要一个 Directories 值对象,该对象定义了以下位置

  • 应用程序的基本目录。
  • 应用程序的配置目录。
  • 应用程序的日志目录。
  • 应用程序的缓存目录。
use Snicco\Component\Kernel\ValueObject\Directories;

$directories = new Directories(
    __DIR__, // base directory,
    __DIR__ .'/config', // config directory
    __DIR__. '/var/cache', // cache directory
    __DIR__ . '/var/log' // log directory
)

// This is equivalent to the above:
$directories = Directories::fromDefaults(__DIR__);

依赖注入容器

Kernel 需要一个 DIContainer 实例,它是一个扩展了 PSR-11 容器接口的抽象类。

目前有两个此接口的实现

您也可以提供自己的实现,并使用snicco/kernel-testing中的测试用例进行测试。

DIContainer类是一个抽象类,用于在捆绑包内部使用。

由于捆绑包是分发包,它们不能依赖于特定的依赖注入容器。然而,PSR-11容器接口仅定义了如何从容器中获取服务,而没有定义如何定义服务,这就是为什么使用DIContainer抽象的原因。

配置文件

在内核启动后,配置目录中的每个.php文件都将被用来创建一个Config实例。

您配置目录中的以下配置

// config/routing.php

return [

    'route_directories' => [
        /* */    
    ]       
        
    'features' => [
        'feature-a' => true,
    ]       
]

将按如下方式加载到配置实例中

$config->get('routing');

$config->get('routing.route_directories');

$config->get('routing.features.feature-a');

kernel.php配置文件是保留的,因为这是定义捆绑包引导加载器的地方。

// config/kernel.php

use Snicco\Component\Kernel\ValueObject\Environment;

return [

    'bundles' => [
        
        // These bundles will be used in all environments
        Environment::ALL => [
            RoutingBundle::class
        ],
        // These bundles will only be used if the kernel environment is dev.
        Environment::DEV => [
            ProfilingBundle::class
        ],      
        
    ],
    
    // Bootstrappers are always used in all environments.
    'bootstrappers' => [
        BootstrapperA::class
    ]   

]

使用方法

创建内核

use Snicco\Component\Kernel\Kernel;

$container = /* */
$env = /* */
$directories = /* */

$kernel = new Kernel(
    $container,
    $directories,
    $env
);

启动内核

内核启动时发生的情况与当前环境和配置是否已缓存有关。

$kernel = /* */

$kernel->boot();

启动“未缓存”的内核

  1. 配置目录中的所有配置文件都将从磁盘加载,以创建WritableConfig实例。
  2. 捆绑包和引导加载器从kernel.php配置文件中读取。
  3. 为所有捆绑包调用shouldRun()方法。
  4. 为所有引导加载器调用shouldRun()方法。
  5. 为所有捆绑包调用configure()方法。
  6. 为所有引导加载器调用configure()方法。
  7. WritableConfig合并到一个文件中,并写入缓存目录(如果当前环境是生产/预发布)。
  8. 为所有捆绑包调用register()方法。
  9. 为所有引导加载器调用register()方法。
  10. 为在kernel.php配置文件中定义的捆绑包调用boot()方法。
  11. 为在kernel.php配置文件中定义的引导加载器调用boot()方法。
  12. DIContainer被锁定,无法进行进一步修改。

启动“已缓存”的内核

  1. 从磁盘加载已缓存的配置文件,并创建一个ReadOnlyConfig
  2. ReadOnlyConfig读取捆绑包和引导加载器。
  3. 为所有捆绑包调用shouldRun()方法。
  4. 为所有引导加载器调用shouldRun()方法。
  5. 为所有捆绑包调用register()方法。
  6. 为所有引导加载器调用register()方法。
  7. 为所有捆绑包调用boot()方法。
  8. 为所有引导加载器调用boot()方法。
  9. DIContainer被锁定,无法进行进一步修改。
  • configure() 方法应用于扩展已加载的配置并验证特定包的配置。 只有当配置尚未缓存时,才会调用 configure() 方法。

  • register() 方法应 用于将服务定义绑定到 DIContainer

  • 应使用 boot() 方法从 DIContainer 获取服务并在必要时对其进行配置。此时容器已锁定,无法进一步修改服务定义。尝试在包或引导程序的 boot() 方法内部修改容器将抛出 ContainerIsLocked 异常。

这些方法始终首先在所有包上调用,然后是在所有引导程序上。

这允许引导程序自定义包的行为(如果需要)。

生命周期钩子

内核引导过程中有两个扩展点。

  • 从磁盘加载配置之后(只有当配置尚未缓存时)。这是在配置缓存之前修改配置的最后一个机会。
  • 在注册所有包和引导程序之后,但在它们启动之前。这是在容器锁定之前修改服务定义的最后一个机会。
use Snicco\Component\Kernel\Configuration\WritableConfig;use Snicco\Component\Kernel\Kernel;

$kernel = /* */

$kernel->afterConfigurationLoaded(function (WritableConfig $config) {
    if( $some_condition ) {
        $config->set('routing.features.feature-a', true);    
    }
});

$kernel->afterRegister(function (Kernel $kernel) {
    if($some_condition) {
        $kernel->container()->instance(LoggerInterface::class, new TestLogger());
    }
});

$kernel->boot();

使用启动的 Kernel

在容器启动后,可以安全地检索所有包提供的服务。

示例

use Nyholm\Psr7Server\ServerRequestCreator;

$kernel->boot();

$server_request_creator = $kernel->container()->make(ServerRequestCreator::class);
$http_kernel = $kernel->container()->make(HttpKernel::class);

$response = $http_kernel->handle($server_request_creator->fromGlobals());

贡献

这个存储库是 Snicco 项目 开发仓库的只读分割。

这是您如何进行贡献.

报告问题和发送拉取请求

请在 Snicco 单一仓库 中报告问题。

安全性

如果您发现安全漏洞,请遵循我们的 披露流程