ghostwriter/container
Composer 安装命令:
composer require ghostwriter/container
包简介
Provides an extensible Dependency Injection Service Container for Automated Object Composition, Interception, and Lifetime Management.
关键字:
README 文档
README
Provides an extensible Dependency Injection Service Container for Automated Object Composition, Interception, and Lifetime Management.
It supports autowiring, singleton-style service retrieval, contextual bindings, service factories, post-construction extensions, provider-based registration, and PSR container interoperability.
Why use it?
- Auto-discover providers from Composer metadata
- Autowire concrete classes through reflection
- Cache shared services with
get() - Create fresh instances with
build() - Create services through factories
- Decorate services with extensions
- Override constructor or callable arguments by name or position
- PSR-compatible wrapper
- Register aliases for interfaces and abstractions
- Swap implementations contextually with
bind()
Installation
Install the package with Composer:
composer require ghostwriter/container
Usage
get() resolves a service once and returns the same instance on subsequent calls.
<?php declare(strict_types=1); use Ghostwriter\Container\Container; final readonly class Dependency { } 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); assert($service->dependency() instanceof Dependency); assert($service === $container->get(Service::class));
Core concepts
get() vs build()
get(Foo::class)returns the same resolved instance each time.build(Foo::class)creates a new instance every time.
$shared = $container->get(Service::class); $sameShared = $container->get(Service::class); assert($shared === $sameShared); $fresh = $container->build(Service::class); assert($fresh instanceof Service); assert($fresh !== $shared);
Constructor argument overrides
You can override constructor parameters by name or by position when building a service.
final readonly class Report { public function __construct( private string $title, private int $pageCount = 1, ) {} } $report = $container->build(Report::class, [ 'title' => 'Architecture Notes', 'pageCount' => 42, ]); $otherReport = $container->build(Report::class, [ 0 => 'Release Notes', 1 => 5, ]);
Invoking callables with call()
call() resolves object dependencies for closures, invokable classes, callable arrays, static method strings, and function names.
use Ghostwriter\Container\Container; $message = $container->call( static function (Dependency $dependency, string $name): string { return $name . ' is ready'; }, ['name' => 'container'] ); assert($message === 'container is ready');
Checking availability with has()
has() answers whether the container can resolve a service. It does not instantiate the service, run factories, or execute extensions.
assert($container->has(Service::class) === true);
Aliases
Use alias() to map an interface or alternative service id to a concrete implementation.
interface ClientInterface { } final readonly class RestClient implements ClientInterface { } $container->alias(ClientInterface::class, RestClient::class); $client = $container->get(ClientInterface::class); assert($client instanceof RestClient);
Contextual bindings
Use bind() when one abstraction should resolve differently depending on which concrete class is being built.
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 client(): ClientInterface { return $this->client; } } $container->alias(ClientInterface::class, RestClient::class); $container->bind(GitHub::class, ClientInterface::class, GraphQLClient::class); $gitHub = $container->get(GitHub::class); assert($gitHub->client() instanceof GraphQLClient); assert($container->get(ClientInterface::class) instanceof RestClient);
Factories
Register a factory when a service needs custom construction logic.
use Ghostwriter\Container\Interface\ContainerInterface; use Ghostwriter\Container\Interface\Service\FactoryInterface; final readonly class Dependency { } final readonly class Service { public function __construct( private Dependency $dependency, ) {} public function dependency(): Dependency { return $this->dependency; } } /** @implements FactoryInterface<Service> */ final readonly class ServiceFactory implements FactoryInterface { public function __invoke(ContainerInterface $container): object { return new Service($container->get(Dependency::class)); } } $container->factory(Service::class, ServiceFactory::class); $service = $container->get(Service::class); assert($service instanceof Service); assert($service->dependency() instanceof Dependency);
Extensions
Register an extension to mutate or decorate a service after it has been created.
use Ghostwriter\Container\Interface\ContainerInterface; use Ghostwriter\Container\Interface\Service\ExtensionInterface; final class GitHubClient { public function __construct( private ?string $enterpriseUrl = null, ) {} public function setEnterpriseUrl(string $enterpriseUrl): void { $this->enterpriseUrl = $enterpriseUrl; } public function enterpriseUrl(): ?string { return $this->enterpriseUrl; } } /** @implements ExtensionInterface<GitHubClient> */ final readonly class GitHubClientExtension implements ExtensionInterface { public function __invoke(ContainerInterface $container, object $service): void { $service->setEnterpriseUrl('https://github.example.com'); } } $container->extend(GitHubClient::class, GitHubClientExtension::class); $client = $container->get(GitHubClient::class); assert($client->enterpriseUrl() === 'https://github.example.com');
Service providers
Providers group related aliases, factories, extensions, and prebuilt instances.
Provider classes must implement Ghostwriter\Container\Interface\Service\ProviderInterface.
use Ghostwriter\Container\Interface\ContainerInterface; use Ghostwriter\Container\Interface\BuilderInterface; use Ghostwriter\Container\Interface\Service\ExtensionInterface; use Ghostwriter\Container\Interface\Service\FactoryInterface; use Ghostwriter\Container\Interface\Service\ProviderInterface; 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 { /** @var list<TaskInterface> */ private array $tasks = []; public function add(TaskInterface $task): void { $this->tasks[] = $task; } public function count(): int { return count($this->tasks); } } /** @implements FactoryInterface<TaskCollection> */ final readonly class TaskCollectionFactory implements FactoryInterface { public function __invoke(ContainerInterface $container): object { return new TaskCollection(); } } /** @implements ExtensionInterface<TaskCollection> */ final readonly class TaskCollectionExtension implements ExtensionInterface { public function __invoke(ContainerInterface $container, object $service): void { $service->add(new FirstTask('Task 1')); $service->add($container->get(TaskInterface::class)); } } final readonly class TasksProvider implements ProviderInterface { public function boot(ContainerInterface $container): void { // no-op } public function register(BuilderInterface $builder): void { $builder->alias(TaskInterface::class, MainTask::class); $builder->alias(TaskCollectionInterface::class, TaskCollection::class); $builder->factory(TaskCollection::class, TaskCollectionFactory::class); $builder->extend(TaskCollection::class, TaskCollectionExtension::class); $builder->set(MainTask::class, new MainTask('Main Task')); } } $provider = $container->get(TasksProvider::class); $provider->register($container); $provider->boot($container); $tasks = $container->get(TaskCollectionInterface::class); assert($tasks instanceof TaskCollection); assert($tasks->count() === 2);
Automatic provider registration from Composer
The container can discover provider classes from Composer package metadata. Add the provider class under extra.ghostwriter.container.provider in your package's composer.json.
{
"extra": {
"ghostwriter": {
"container": {
"provider": [
"Vendor\\Package\\Container\\PackageProvider",
"Vendor\\Package\\Container\\FeatureProvider"
]
}
}
}
}
When the container is reset or first initialized, it reads Composer metadata, registers discovered providers, and boots them.
PSR container interoperability
The package also provides a PSR-compatible wrapper class: Ghostwriter\Container\PsrContainer.
use Ghostwriter\Container\Container; use Ghostwriter\Container\PsrContainer; $container = Container::getInstance(); $psrContainer = $container->get(\Psr\Container\ContainerInterface::class); // or //$psrContainer = new PsrContainer($container); assert($psrContainer->has(Service::class) === true); assert($psrContainer->get(Service::class) instanceof Service);
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-3-Clause. Please see License File for more information.
ghostwriter/container 适用场景与选型建议
ghostwriter/container 是一款 基于 PHP 开发的 Composer 扩展包,目前已累计 6.72M 次下载、GitHub Stars 达 1, 最近一次更新时间为 2022 年 04 月 25 日, 在 PHP 生态内属于活跃度较高的组件。
它主要适用于以下技术方向: 「container」 「ghostwriter」 等业务场景。在实际项目中,围绕这些方向常见需要落地的问题包括:接口对接、性能调优、并发安全、与既有框架(Laravel / ThinkPHP / Yii / Webman 等)的兼容适配,以及生产环境的日志埋点与稳定性保障。
我们在过去多个企业项目中使用过 ghostwriter/container 或与其功能相近的方案,如果你在选型或落地过程中遇到问题,例如 版本兼容、二次改造、私有化封装、与内部系统对接、生产 BUG 排查,欢迎联系我们协助评估。
基于 ghostwriter/container 在你已有业务上做功能扩展、字段裁剪、UI 适配、与内部账号 / 权限 / 日志系统的深度对接。
线上偶发问题、内存泄漏、慢查询、并发异常等排查修复;针对高流量场景做缓存、队列、索引层面的调优。
承接完整的项目从需求 → 设计 → 开发 → 上线 → 长期运维;也可按月提供技术保姆服务。
与 ghostwriter/container 相关的其它包
同方向 / 同关键字的高下载量 PHP Composer 包推荐,方便对比选型:
Provides Environment Variables derived from `$_ENV` and `$_SERVER` super-globals
Additional assertions for PHPUnit
Provides a framework for testing Psalm plugins
HTTP Client and Server abstraction for PHP.
PHP code formatter
A libraries.io API Client for PHP
统计信息
- 总下载量: 6.72M
- 月度下载量: 0
- 日度下载量: 0
- 收藏数: 1
- 点击次数: 37
- 依赖项目数: 28
- 推荐数: 0
其他信息
- 授权协议: BSD-3-Clause
- 更新时间: 2022-04-25