intraworlds/service-container
Composer 安装命令:
composer require intraworlds/service-container
包简介
Lightweight yet powerful implementation of dependancy injection container with autowiring
README 文档
README
Lightweight yet powerful implementation of dependency injection container with autowiring.
Installation
Use Composer to install the package:
composer require intraworlds/service-container
Config
The container is implementing standard PSR-11 interface. You can use it with autowiring out-of-the-box. However, sometimes you want to configure things which needs parameters (eg. DB connection).
// zero configuration required $container = new ServiceContainer; $container->get(ClassWithManyDependencies::class); // bind factory of a value object #[Bind(self::load(...))] final class Config { function __construct(private array $values) static function load(Filesystem $fs) : self } // by method $container->bind(Config::class, Config::load(...)); // delay actual factory execution (eg. connection to DB) with lazy objects // inline factories in attributes are possible since PHP 8.5 #[Lazy, Bind(fn(Config $config) => new Aws\S3\S3Client(['region' => $config->get('S3_REGION')]))] final class S3 { public function __construct(private Aws\S3\S3Client $client) } // by methods $container->bind(S3::class, fn(Config $config) => new Aws\S3\S3Client(['region' => $config->get('S3_REGION')])); $container->lazy(S3::class); // use alias to bind without factory #[Alias(MemoryCache::class)] interface Cache // by method $container->alias(Cache::class, MemoryCache::class);
Composite types
A parameter typed as a union or intersection (eg. Cache|NullCache, Countable&Traversable)
is not autowired by trying each member. The container resolves it under the type's string
key, so you must register it explicitly — otherwise a CannotAutowireCompositType is thrown.
// a constructor param typed `Cache|NullCache` must be bound under that exact string $container->bind('Cache|NullCache', fn() => new NullCache);
Usage
It can be useful to manipulate with Service Container directly.
// get singleton using configured factories or auto-wiring $container->get(S3::class) === $container->get(S3::class); // make fresh instances $container->make(Uri::class) !== $container->get(Uri::class); // service is always available if it's possible to create it $container->has(Config::class) === true; // return service only if it was already initialized before, NULL otherwise $container->instance(Transaction::class); // same as `get()` but fails gracefully (to NULL) $container->try('NonExisting') === null; // register an already existing instance as a singleton $container->set(Clock::class, new FrozenClock($now)); // remove a singleton and return it (NULL if it wasn't set) $container->unset(Clock::class); // obtain (and memoize) the resolved factory for an ID $container->factory(S3::class); // instance of IW\ServiceContainer\ServiceFactory
Examples
Auto wiring arbitrary callable
Internal CallableFactory is useful for resolving any dependencies of a callable. Especially it's useful for init template method. See following example.
abstract class Parent { function __construct(private Dependency $dependency, ServiceContainer $container) { if (method_exists($this, 'init')) { (new CallableFactory($this->init(...)))($container); } } } class Child extends Parent { function init(AnotherDependency $another) { // ... } }
Manual Wiring
Sometimes you want to configure container manually. Let's consider following example on Command Pattern
interface OrderCommand { function execute(); } class OrderInvoker { function __construct(private OrderCommand ...$commands) {} function execute() : void { array_walk($this->commands, fn($command) => $command->execute()); } }
With IW\ServiceContainer you have several options how to resolve OrderInvoker's dependencies.
// an alias but that's no good for multiple commands $container->alias('OrderInvoker', 'ReserveItems'); // external factory $container->bind('OrderInvoker', function (IW\ServiceContainer $container) { return new OrderInvoker($container->get('ReserveItems'), $container->get('SendInvoice')); }); // internal factory $container->bind('OrderInvoker', OrderInvoker::create(...)); class OrderInvoker { static function create(ReserveItems $reserveItems, SendInvoice $sendInvoice) : OrderInvoker { return new OrderInvoker($reserveItems, $sendInvoice); } } // wiring factory $container->wire('OrderInvoker', 'ReserveItems', 'SendInvoice'); // ...same but with attribute #[Wire('OrderInvoker', 'ReserveItems', 'SendInvoice')] class OrderInvoker { }
Arguably all approaches have their advantages. internal factory approach is good for static analysis. wiring factory is useful for common application pattern and when dependencies may vary.
Errors
All exceptions extend IW\ServiceContainer\Exception, which implements PSR-11's
ContainerExceptionInterface; ServiceNotFound additionally implements
NotFoundExceptionInterface. When a failure is wrapped (eg. a broken dependency deep in a
resolution chain), Exception::getOrigin() returns the first original exception raised
outside the container, which is handy for pinpointing the root cause.
License
All contents of this package are licensed under the MIT license.
intraworlds/service-container 适用场景与选型建议
intraworlds/service-container 是一款 基于 PHP 开发的 Composer 扩展包,目前已累计 76.14k 次下载、GitHub Stars 达 0, 最近一次更新时间为 2018 年 11 月 06 日, 在 PHP 生态内属于活跃度较高的组件。
我们在过去多个企业项目中使用过 intraworlds/service-container 或与其功能相近的方案,如果你在选型或落地过程中遇到问题,例如 版本兼容、二次改造、私有化封装、与内部系统对接、生产 BUG 排查,欢迎联系我们协助评估。
基于 intraworlds/service-container 在你已有业务上做功能扩展、字段裁剪、UI 适配、与内部账号 / 权限 / 日志系统的深度对接。
线上偶发问题、内存泄漏、慢查询、并发异常等排查修复;针对高流量场景做缓存、队列、索引层面的调优。
承接完整的项目从需求 → 设计 → 开发 → 上线 → 长期运维;也可按月提供技术保姆服务。
统计信息
- 总下载量: 76.14k
- 月度下载量: 0
- 日度下载量: 0
- 收藏数: 0
- 点击次数: 35
- 依赖项目数: 0
- 推荐数: 0
其他信息
- 授权协议: MIT
- 更新时间: 2018-11-06