ghostwriter/container

Provides an extensible Dependency Injection Service Container for Automated Object Composition, Interception, and Lifetime Management.

Fund package maintenance!
ghostwriter

Installs: 1 667 327

Dependents: 11

Suggesters: 0

Security: 0

Stars: 0

Watchers: 1

Forks: 0

Open Issues: 1

3.0.3 2024-04-10 15:11 UTC

This package is auto-updated.

Last update: 2024-04-28 22:10:39 UTC


README

Compliance Supported PHP Version GitHub Sponsors Mutation Coverage Code Coverage Type Coverage Latest Version on Packagist Downloads

Provides an extensible Dependency Injection Service Container for Automated Object Composition, Interception, and Lifetime Management.

Installation

You can install the package via composer:

composer require ghostwriter/container

Usage

Simple usage

Registering a service on the given container.

final readonly class Service
{
    public function __construct(
        private Dependency $dependency
    ) {}

    public function dependency():Dependency
    {
        return $this->dependency;
    }
}

$container = Container::getInstance();
$service = $container->get(Service::class);

assert($service instanceof Service); // true
assert($service->dependency() instanceof Dependency); // true

Service Providers

Registering a service provider on the container.

interface TaskInterface {}

final readonly class Task implements TaskInterface {}

final class Tasks
{
    private array $tasks = [];
    public function addTask(TaskInterface $task)
    {
        $this->tasks[] = $task;
    }
}

final readonly class TasksServiceProvider implements ServiceProviderInterface
{
    public function __invoke(ContainerInterface $container)
    {
        $container->alias(TaskInterface::class, Task::class);

        $container->set(Tasks::class, static function (Container $container) {
            /** @var Tasks $tasks */
            $tasks = $container->build(Tasks::class);

            foreach ($container->tagged(Task::class) as $service) {
                $tasks->addTask($service);
            }

            return $tasks;
        }, [Tasks::class, 'tasks']);
    }
}

$container->provide(TasksServiceProvider::class);

$service = $container->get(TaskInterface::class);

assert($service instanceof Task); // true

Contextual Bindings

Registering a Contextual Bindings on the container.

interface ClientInterface { }

final readonly class RestClient implements ClientInterface {
}

final readonly class GraphQLClient implements ClientInterface {
}

final readonly class GitHub
{
    public function __construct(
        private ClientInterface $client
    ) {
    }
    public function getClient(): ClientInterface
    {
        return $this->client;
    }
}

// When GitHub::class asks for ClientInterface::class, it would receive an instance of GraphQLClient::class.
$container->bind(GitHub::class, ClientInterface::class, GraphQLClient::class);

// When any other service asks for ClientInterface::class, it would receive an instance of RestClient::class.
$container->alias(ClientInterface::class, RestClient::class);

Service Extensions

Registering a service extension on the container.

/**
 * @implements ExtensionInterface<GitHubClient>
 */
final readonly class GitHubExtension implements ExtensionInterface
{
    /**
     * @param GitHubClient $service
     * @return GitHubClient
     */
    public function __invoke(ContainerInterface $container, object $service): object
    {
        $service->setEnterpriseUrl(
            $container->get(GitHubClient::GITHUB_HOST)
        );

        return $service;
    }
}

$container->alias(GitHubClientInterface::class, GitHubClient::class);
$container->extend(GitHubClientInterface::class, $container->get(GitHubExtention::class));

Service Factory

Registering a service factory on the container.

final readonly class Dependency {}
final readonly class Service
{
    public function __construct(
        private Dependency $dependency
    ){}

    public function dependency():Dependency
    {
        return $this->dependency;
    }
}
final readonly class ServiceFactory {
  public function __invoke(Container $container): Service
  {
     return new Service($container->get(Dependency::class));
  }
}

$container = Container::getInstance();

$container->factory(Service::class, ServiceFactory::class);

$service = $container->get(Service::class);

assert($service instanceof Service); // true
assert($service->dependency() instanceof Dependency); // true

Testing

composer test

Changelog

Please see CHANGELOG.md for more information what has changed recently.

Security

If you discover any security related issues, please email nathanael.esayeas@protonmail.com instead of using the issue tracker.

Sponsors

[Become a GitHub Sponsor]

Credits

License

The BSD-3-Clause. Please see License File for more information.