ghostwriter / container
Provides an extensible Dependency Injection Service Container for Automated Object Composition, Interception, and Lifetime Management.
Fund package maintenance!
ghostwriter
Installs: 4 578 050
Dependents: 20
Suggesters: 0
Security: 0
Stars: 0
Watchers: 1
Forks: 0
Open Issues: 0
pkg:composer/ghostwriter/container
Requires
- php: ~8.4.0 || ~8.5.0
- psr/container: ^2.0.2
Requires (Dev)
- ext-xdebug: *
- ghostwriter/coding-standard: dev-main
- mockery/mockery: ^1.6.12
- phpunit/phpunit: ^12.4.3
- symfony/var-dumper: ^7.3.5
Provides
- 6.0.x-dev
- 6.0.1
- 6.0.0
- 5.0.x-dev
- 5.0.1
- 5.0.0
- 4.1.x-dev
- 4.0.x-dev
- 4.0.5
- 4.0.4
- 4.0.3
- 4.0.2
- 4.0.1
- 4.0.0
- 3.0.3
- 3.0.2
- 3.0.1
- 3.0.0
- 2.0.1
- 2.0.0
- 1.6.0
- 1.5.0
- 1.4.0
- 1.3.0
- 1.2.0
- 1.1.1
- 1.1.0
- 1.0.0
- 0.7.0
- 0.6.0
- 0.5.0
- 0.4.0
- 0.3.2
- 0.3.1
- 0.3.0
- 0.2.2
- 0.2.1
- 0.2.0
- 0.1.1
- 0.1.0
- dev-security
- dev-github/settings
- dev-composer/configuration
- dev-main
This package is auto-updated.
Last update: 2025-11-18 06:00:52 UTC
README
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
Automatic Service Definition Registration
Automatically register a service definition class using Composer's extra config in your composer.json file.
Important
A service definition class MUST implement Ghostwriter\Container\Interface\Service\DefinitionInterface [class].
It should look like the following:
{
"extra": {
"ghostwriter": {
"container": {
"definition": "App\\Service\\Definition"
}
}
}
}
Service Definition
Registering a service definition on the container.
interface TaskInterface {} interface TaskCollectionInterface { public function add(TaskInterface $task): void; public function count(): int; } final readonly class MainTask implements TaskInterface { public function __construct( private string $name ) {} } final readonly class FirstTask implements TaskInterface { public function __construct( private string $name ) {} } final class TaskCollection implements TaskCollectionInterface { private array $tasks = []; public function add(TaskInterface $task): void { $this->tasks[] = $task; } public function count(): int { return count($this->tasks); } } final class TaskCollectionFactory implements FactoryInterface { public function __invoke(ContainerInterface $container): TaskCollection { return new TaskCollection(); } } final class TaskCollectionExtension implements ExtensionInterface { /** @param TaskCollection $service */ public function __invoke(ContainerInterface $container, object $service): void { $service->add(new FirstTask('Task 1')); $mainTask = $container->build(TaskInterface::class, ['name' => 'Main Task']); assert($mainTask instanceof MainTask); // true $service->add($mainTask); } } final readonly class TasksServiceDefinition implements DefinitionInterface { public function __invoke(ContainerInterface $container) { $container->alias(MainTask::class, TaskInterface::class); $container->alias(TaskCollection::class, TaskCollectionInterface::class); $container->extend(TaskCollection::class, TaskCollectionExtension::class); $container->factory(TaskCollection::class, TaskCollectionFactory::class); } } $container = Container::getInstance(); $container->define(TasksDefinition::class); $service = $container->get(TaskCollectionInterface::class); assert($service instanceof TaskCollection); // true assert($service->count() === 2); // 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 */ public function __invoke(ContainerInterface $container, object $service): void { $service->setEnterpriseUrl( $container->get(GitHubClient::GITHUB_HOST) ); } } $container->alias(GitHubClientInterface::class, GitHubClient::class); $container->extend(GitHubClientInterface::class, 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
Credits
License
The BSD-4-Clause. Please see License File for more information.