spiral / framework

High-Performance PHP Framework
https://spiral.dev
MIT License
1.75k stars 84 forks source link

PHP Attributes for Bootloader Methods #1064

Open butschster opened 6 months ago

butschster commented 6 months ago

Spiral provides an efficient way to bootstrap applications, allowing developers to register container bindings and configure applications effectively. However, this process can be further enhanced by introducing PHP attributes for the bootloader methods.

Motivation

Currently, Spiral utilizes methods such as defineBindings, defineSingletons, init, and boot for container bindings and application configuration. While this approach is functional, PHP attributes can make the process more intuitive and less verbose, improving readability and maintainability.

Proposed PHP Attributes

  1. InitMethod: Used to mark methods that are involved in the initialization process.
  2. BootMethod: Used to mark methods that are part of the bootstrapping sequence.
  3. SingletonMethod: Used to define singleton services within the application.
  4. BindMethod: Used for binding services in the container.

Examples of Usage

1. InitMethod Attribute

Current approach

public function init(EnvironmentInterface $environment, SomeService $service): void 
{
    $envs = [];
    foreach ($environment->getAll() as $key => $value) {
        if (\str_starts_with($key, 'SCANNER_ENV_')) {
            $key = \substr($key, \strlen('SCANNER_ENV_'));
            /** @psalm-suppress InvalidLiteralArgument */
            $envs[$key] = (\is_string($value) && \str_starts_with('$', $value))
                ? $environment->get(\substr($value, 1))
                : $value;
        }
    }

    $this->config->setDefaults(ScannerEnvConfig::CONFIG, $envs);

    $service->boot();
}

Purpose: This attribute is used to mark methods that are involved in the initialization process of the application.

Example:

#[InitMethod]
public function initConfiguration(SomeService $service): void 
{
    // Gather environment variables specific to a module or feature
    $envs = [];
    foreach ($environment->getAll() as $key => $value) {
        if (\str_starts_with($key, 'MY_APP_PREFIX_')) {
            $key = \substr($key, \strlen('MY_APP_PREFIX_'));
            $envs[$key] = $value;
        }
    }

    // Set defaults or configure components based on these variables
    $this->config->setDefaults(MyAppConfig::CONFIG, $envs);
}

#[InitMethod]
public function bootService(EnvironmentInterface $environment): void 
{
    $service->boot();
}

2. BootMethod Attribute

Current approach

public function boot(): void
{
    // ... initialization logic ...
}

Purpose: This attribute designates methods that are part of the application's bootstrapping process.

Example:

#[BootMethod]
public function prepareServices(SomeService $service): void 
{
    // Perform actions necessary to prepare the service for use
    $service->initialize();
    $service->loadData();
    $service->boot();
}

#[BootMethod]
public function someService(): void 
{
    // Perform actions necessary to prepare the service for use ...
}

3. SingletonMethod Attribute

Purpose: Used to define singleton services within the application, ensuring only one instance exists.

Example:

#[SingletonMethod(alias: CacheService::class)]
public function initCacheService(ConfigInterface $config): CacheService 
{
    $cacheConfig = $config->get('cache');
    return new CacheService($cacheConfig);
}

4. BindMethod Attribute

Purpose: Used for defining methods that bind services or implementations to interfaces in the dependency injection container.

Example:

#[BindMethod(LoggerInterface::class)]
public function bindLogger(): LoggerInterface 
{
   return new Logger(...);
}

In summary, these attributes (InitMethod, BootMethod, SingletonMethod, BindMethod) aim to simplify and clarify the definition of methods within the Spiral Framework's bootloader, enhancing readability and maintainability. Each attribute plays a distinct role in organizing the bootstrapping and initialization process of the application.

lifewcody commented 3 months ago

If you're going to have multiple #[BootMethod] I suggest adding a priority ex: #[BootMethod(1)]

But I very much like this idea better