承接 luizfilipezs/container 相关项目开发

从需求分析到上线部署,全程专人跟进,保证项目质量与交付效率

邮箱:yvsm@zunyunkeji.com | QQ:316430983 | 微信:yvsm316

luizfilipezs/container

最新稳定版本:1.0.3

Composer 安装命令:

composer require luizfilipezs/container

包简介

Dependency injection container

README 文档

README

This library implements a dependency injection system.

Minimum requirements

  • PHP 8.4
  • Composer

Installation

Inside your project folder, run:

composer require luizfilipezs/container

Usage

Getting a definition

$container = new Container();
$container->set(MyInterface::class, MyClass::class);
$myObject = $container->get(MyInterface::class);

The above example creates a new instance of MyClass, typed as MyInterface.

Setting a definition

Class string

$container->set(UserServiceInterface::class, UserService::class);

Class instance

$container->set(UserServiceInterface::class, new UserService());

Closure

$container->set(UserServiceInterface::class, fn() => new UserService());

Checking for a definition

if ($container->has(UserServiceInterface::class)) {

Removing a definition

$container->remove(UserServiceInterface::class);

Setting a singleton

Singleton classes are automatically recognized via #[Singleton] attribute.

use Luizfilipezs\Container\Attributes\Singleton;

#[Singleton]
class UserService
{
  public string $foo = 'bar';
}

$userService1 = $container->get(UserService::class);
$userService2 = $container->get(UserService::class);

$userService1->foo = 'baz';
echo $userService2->foo; // 'baz'

If you set a singleton class as definition for an interface, both the interface and the class will be set with the actual instance of the class as soon as it is created:

$container->set(UserServiceInterface::class, UserService::class);

$userServiceViaInterface = $container->get(UserServiceInterface::class);
$userServiceViaInterface->setFoo('baz');

$userServiceViaClass = $container->get(UserService::class);
$userServiceViaClass->getFoo(); // 'baz'

Setting a class with lazy constructor

Lazy constructor was natively implemented in PHP 8.4. It allows an object to be created without its __construct method getting called until an attribute is used.

use Luizfilipezs\Container\Attributes\Lazy;

#[Lazy]
class UserService
{
    public function __contruct(private readonly UserRepositoryInterface $userRepository)
    {
        echo 'Constructor was called.';
    }

    public function getAll(): array
    {
        return $this->userRepository->findAll();
    }
}

$userService = $container->get(UserService::class);
$users = $userService->getAll(); // 'Constructor was called.'

It is also possible to disable initialization on reading specific properties:

use Luizfilipezs\Container\Attributes\{Lazy, LazyInitializationSkipped};

#[Lazy]
class MyClass
{
    #[LazyInitializationSkipped]
    public string $skippedProp = 'foo';
    public string $normalProp = 'bar';

    public function __construct()
    {
        echo 'Constructor was called.';
    }
}

$myInstance = $container->get(MyClass::class);

$myInstance->skippedProp;
$myInstance->normalProp; // 'Constructor was called.'

Capturing lazy construction

To know when a lazy __construct gets called you can call Container::eventHandler:

use Luizfilipezs\Container\Enums\ContainerEvent;

$container->eventHandler->on(
    event: ContainerEvent::LAZY_CLASS_CONSTRUCTED,
    callback: static function (string $className, object $instance) {
        echo "{$className}::__construct was called.";
    },
);

$instance = $container->get(MyClass::class);
$instance->foo; // 'MyClass::__construct was called.'

Setting non-class definitions

You can set a definition for any value, allowing it to get automatically injected even if it is not a class.

use Luizfilipezs\Container\Attributes\Inject;

enum ApiConstant: string
{
  case API_KEY = 'API_KEY';
  case API_SECRET = 'API_SECRET';
}

$container->setValue(ApiConstant::API_KEY, 'my_api_key');
$container->setValue(ApiConstant::API_SECRET, 'my_api_secret');

class ApiService
{
  public function __construct(
    #[Inject(ApiConstant::API_KEY)] string $apiKey,
    #[Inject(ApiConstant::API_SECRET)] string $apiSecret,
  ) {}
}

// call __construct with: 'my_api_key', 'my_api_secret'
$apiService = $container->get(ApiService::class);

Any type of value can be set, but it will be strictly compared to the parameter type:

$container->setValue('SOME_INT', 123);

class MyClass
{
  public function __contruct(#[Inject('SOME_INT')] float $value) {}
}

$object = $container->get(MyClass::class);
// ContainerException: Container cannot inject "SOME_INT". It is not the same
// type as the parameter. Expected float, got int.

Value definition methods

$container->setValue('key', 'value');
$value = $container->getValue('key'); // 'value'
$exists = $container->hasValue('key'); // true
$container->removeValue('key');

Advanced options

Container constructor has three parameters:

  • strict (defaults to false): if true, only definitions set explicitly (via set()) will be provided.
  • skipNullableClassParams (defaults to true): if true, nullable constructor parameters typed as a class or an interface will always be set to null, except if the parameter has the Inject attribute bound to it.
  • skipNullableValueParams (defaults to true): if true, nullable constructor parameters typed as a primitive type will always be set to null, except if the parameter has the Inject attribute bound to it.

Example with strict:

$container = new Container(strict: true);

// ContainerException, because there is no explicit definition for "SomeClass"
$instance = $container->get(SomeClass::class);

Examples with skipNullableClassParams

If true:

$container = new Container(skipNullableClassParams: true);
$instance = $container->get(SomeClass::class);

$instance->nullableDependency; // null

If false:

$container = new Container(skipNullableClassParams: false);
$instance = $container->get(SomeClass::class);

$instance->nullableDependency; // object

Examples with skipNullableValueParams

If true:

$container = new Container(skipNullableClassParams: true);
$instance = $container->get(SomeClass::class);

$instance->nullableString; // null

If false:

$container = new Container(skipNullableClassParams: false);
$instance = $container->get(SomeClass::class);

$instance->nullableString; // error, because string cannot be injected

In both examples above, if the nullable parameter was bound to the Inject attribute, the value would be injected anyway, because it forces injection.

Contributing

Forking

At the top of the Github repository page, click the Fork button. Then clone the forked repository to your machine.

Installing dependencies

npm install # install Prettier package
composer update # install composer dependencies

Testing

Run:

./vendor/bin/phpunit tests

When making changes to the codebase, remember to create tests that cover all scenarios.

统计信息

  • 总下载量: 4
  • 月度下载量: 0
  • 日度下载量: 0
  • 收藏数: 0
  • 点击次数: 0
  • 依赖项目数: 0
  • 推荐数: 0

GitHub 信息

  • Stars: 0
  • Watchers: 1
  • Forks: 0
  • 开发语言: PHP

其他信息

  • 授权协议: MIT
  • 更新时间: 2025-03-24