Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

## 1.3.0 October 14, 2024

- Enh #352: Support parameters name binding (@xepozz)
- Enh #353: Add shortcut for tag reference #333 (@xepozz)
- Enh #356: Improve usage `NotFoundException` for cases with definitions (@vjik)
- Enh #364: Minor refactoring to improve performance of container (@samdark)
Expand Down
33 changes: 33 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -385,6 +385,39 @@ $config = ContainerConfig::create()
$container = new Container($config);
```

## Name binding

Name binding is a way to bind a name to a definition. It is used to resolve a definition not by its class name but by a name.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Parameter name? Just a "name" is vague in this context.


Set definitions with a specific name. It may be typed or untyped reference like:
1. `'$serviceName' => $definition`
2. `Service::class . ' $serviceName' => $definition`

```php
return [
'$fileCache' => FileCache::class, // implements CacheInterface
'$redisCache' => RedisCache::class, // implements CacheInterface
CacheInterface::class . ' $memCache' => MemCache::class, // also implements CacheInterface
]
```

So now you can resolve a definition by parameter name:

```php
class MyService
{
public function __construct(
CacheInterface $memCache, // typed reference
$fileCache, // untyped reference
CacheInterface $redisCache, // typed reference to untyped definition
) {
// ...
}
}
```

```php
$container->get(MyService::class); // returns an instance of MyService
### Getting tagged services

You can get tagged services from the container in the following way:
Expand Down
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
"php": "8.1 - 8.5",
"ext-mbstring": "*",
"psr/container": "^1.1 || ^2.0",
"yiisoft/definitions": "^3.0",
"yiisoft/definitions": "dev-parameter-name-binding",
"yiisoft/friendly-exception": "^1.1.0"
},
"require-dev": {
Expand Down
14 changes: 14 additions & 0 deletions tests/Support/ArgumentNameBinding.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<?php

declare(strict_types=1);

namespace Yiisoft\Di\Tests\Support;

final class ArgumentNameBinding
{
public function __construct(
public EngineInterface $markOne,
public EngineInterface $markTwo,
) {
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,12 @@

final class UnionTypeInConstructorFirstTypeInParamResolvable
{
public function __construct(private readonly EngineMarkOne|EngineInterface $engine) {}

Check failure on line 9 in tests/Support/UnionTypeInConstructorFirstTypeInParamResolvable.php

View workflow job for this annotation

GitHub Actions / rector / PHP 8.1

Syntax error, unexpected T_STRING, expecting T_VARIABLE, Syntax error, unexpected '{', Syntax error, unexpected '}', expecting EOF
{
}

public function getEngine(): EngineMarkOne|EngineInterface
{
return $this->engine;
}
}
39 changes: 39 additions & 0 deletions tests/Unit/ContainerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
use Yiisoft\Di\StateResetter;
use Yiisoft\Di\ServiceProviderInterface;
use Yiisoft\Di\Tests\Support\A;
use Yiisoft\Di\Tests\Support\ArgumentNameBinding;
use Yiisoft\Di\Tests\Support\B;
use Yiisoft\Di\Tests\Support\Car;
use Yiisoft\Di\Tests\Support\CarFactory;
Expand Down Expand Up @@ -1966,7 +1967,45 @@
new Container($config);
}

public function testArgumentNameBindingTyped(): void
{
$config = ContainerConfig::create()
->withDefinitions([
EngineInterface::class . ' $markOne' => EngineMarkOne::class,
EngineInterface::class . ' $markTwo' => EngineMarkTwo::class,
]);
$container = new Container($config);

$class = $container->get(ArgumentNameBinding::class);
$this->assertInstanceOf(EngineMarkOne::class, $class->markOne);
$this->assertInstanceOf(EngineMarkTwo::class, $class->markTwo);
}

public function testArgumentNameBindingUntyped(): void
{
$config = ContainerConfig::create()
->withDefinitions([
'$markOne' => EngineMarkOne::class,
'$markTwo' => EngineMarkTwo::class,
]);
$container = new Container($config);

$class = $container->get(ArgumentNameBinding::class);
$this->assertInstanceOf(EngineMarkOne::class, $class->markOne);
$this->assertInstanceOf(EngineMarkTwo::class, $class->markTwo);
}

public function testArgumentNameBindingUnionTypes(): void
{
$config = ContainerConfig::create()
->withDefinitions([
'$engine' => EngineMarkOne::class,
]);
$container = new Container($config);

$class = $container->get(UnionTypeInConstructorFirstTypeInParamResolvable::class);
$this->assertInstanceOf(EngineMarkOne::class, $class->getEngine());
public static function dataNotFoundExceptionMessageWithDefinitions(): array

Check failure on line 2008 in tests/Unit/ContainerTest.php

View workflow job for this annotation

GitHub Actions / rector / PHP 8.1

Syntax error, unexpected T_PUBLIC, Syntax error, unexpected ':', Syntax error, unexpected T_PUBLIC, expecting T_TRAIT or T_INTERFACE or T_ENUM, Syntax error, unexpected T_PUBLIC, Syntax error, unexpected T_PUBLIC, Syntax error, unexpected T_PUBLIC, Syntax error, unexpected T_PUBLIC, Syntax error, unexpected EOF
{
return [
'without-definition' => [[]],
Expand Down
Loading