Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Parameters name binding #352

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
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 @@ -2,6 +2,7 @@

## 1.2.2 under development

- Enh #352: Support parameters name binding (@xepozz)
- Enh #353: Add shortcut for tag reference #333 (@xepozz)

## 1.2.1 December 23, 2022
Expand Down
35 changes: 35 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -341,6 +341,41 @@ $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
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 a definitions with a specific name. It may be typed or untyped reference like:
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
Set a definitions with a specific name. It may be typed or untyped reference like:
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 its name:
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
So now you can resolve a definition by its name:
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
```

## Resetting services state

Despite stateful services isn't a great practice, these are often inevitable. When you build long-running
Expand Down
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
"php": "^8.0",
"ext-mbstring": "*",
"psr/container": "^1.1|^2.0",
"yiisoft/definitions": "^3.0"
"yiisoft/definitions": "dev-parameter-name-binding"
},
"require-dev": {
"league/container": "^4.2",
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 @@ -9,4 +9,9 @@ final class UnionTypeInConstructorFirstTypeInParamResolvable
public function __construct(private EngineMarkOne|EngineInterface $engine)
{
}

public function getEngine(): EngineMarkOne|EngineInterface
{
return $this->engine;
}
}
43 changes: 42 additions & 1 deletion tests/Unit/ContainerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,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 @@ -145,7 +146,7 @@ public function dataHas(): array
/**
* @dataProvider dataHas
*/
public function testHas(bool $expected, $id): void
public function testHas(bool $expected, string $id): void
{
$config = ContainerConfig::create()
->withDefinitions([
Expand Down Expand Up @@ -1972,4 +1973,44 @@ public function testInvalidTags(string $message, array $tags): void
$this->expectExceptionMessageMatches($message);
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());
}
}
Loading