Skip to content

Commit 041c52d

Browse files
author
Phil Bennett
committed
Update unstable docs
1 parent a1d26be commit 041c52d

File tree

5 files changed

+191
-30
lines changed

5 files changed

+191
-30
lines changed
Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
---
2+
layout: post
3+
title: Attribute Resolution
4+
sections:
5+
Introduction: introduction
6+
Usage: usage
7+
Extending Attributes: extending-attributes
8+
Benefits: benefits
9+
---
10+
## Introduction
11+
12+
> Note: Attribute resolution is turned off by default but can be turned on by registering the `ReflectionContainer` as a container delegate. Read below and see the [documentation on delegate containers](/5.x/delegate-containers/).
13+
14+
Attribute resolution allows you to use PHP attributes to control how dependencies are resolved for your services. This provides a powerful and flexible alternative to auto wiring, enabling you to inject values, services, or even custom logic directly into your constructors or methods using attributes.
15+
16+
## Usage
17+
18+
The container provides built-in attributes for common resolution scenarios:
19+
20+
- `#[Inject('service.id')]` — Injects a value or service from the container by its ID.
21+
- `#[Resolve('resolver.id', 'path.to.value')]` — Resolves a value from a service or array in the container, traversing the given path.
22+
- Method calls are supported in the path, allowing you to resolve complex values or configurations.
23+
- e.g. `#[Resolve('config', 'getDbConfig.host')]`
24+
25+
### Using `Inject`
26+
27+
~~~php
28+
<?php
29+
30+
declare(strict_types=1);
31+
32+
namespace Acme;
33+
34+
use League\Container\Attribute\Inject;
35+
36+
class Bar {
37+
public function hello(): string
38+
{
39+
return 'hello';
40+
}
41+
}
42+
43+
class Foo
44+
{
45+
public function __construct(
46+
#[Inject('bar')] Bar $bar
47+
) {
48+
$this->bar = $bar;
49+
}
50+
}
51+
52+
$container = new League\Container\Container();
53+
$container->add('bar', new Bar());
54+
$container->delegate(new League\Container\ReflectionContainer());
55+
56+
$foo = $container->get(Foo::class);
57+
echo $foo->bar->hello(); // 'hello'
58+
~~~
59+
60+
### Using `Resolve`
61+
62+
~~~php
63+
<?php
64+
65+
use League\Container\Attribute\Resolve;
66+
67+
class Bar {}
68+
69+
class Config {
70+
public array $settings = [
71+
'db' => [
72+
'host' => 'localhost',
73+
'user' => 'root',
74+
]
75+
];
76+
}
77+
78+
class Baz
79+
{
80+
public function __construct(
81+
#[Resolve('config', 'settings.db.host')] public string $dbHost
82+
) {
83+
}
84+
}
85+
86+
$container = new League\Container\Container();
87+
$container->add('config', new Config());
88+
$container->delegate(new League\Container\ReflectionContainer());
89+
90+
$baz = $container->get(Baz::class);
91+
// $baz->dbHost === 'localhost'
92+
~~~
93+
94+
## Extending Attributes
95+
96+
You can create your own attributes to implement custom resolution logic. To access the container within your attribute, implement `ContainerAwareInterface` and use the `ContainerAwareTrait`. This gives you access to `$this->getContainer()`.
97+
98+
For example, to inject an environment variable:
99+
100+
~~~php
101+
<?php
102+
103+
use Attribute;
104+
use League\Container\Attribute\AttributeInterface;
105+
use League\Container\ContainerAwareInterface;
106+
use League\Container\ContainerAwareTrait;
107+
108+
#[Attribute(Attribute::TARGET_PARAMETER)]
109+
class Env implements AttributeInterface, ContainerAwareInterface
110+
{
111+
use ContainerAwareTrait;
112+
113+
public function __construct(private string $name) {}
114+
115+
public function resolve(): string
116+
{
117+
// You can access the container if needed via $this->getContainer()
118+
return getenv($this->name) ?: '';
119+
}
120+
}
121+
122+
class NeedsSecret
123+
~~~
124+
125+
## Benefits
126+
127+
Attribute resolution offers several advantages over auto wiring:
128+
129+
- **Fine-grained control:** Specify exactly how each dependency should be resolved, including primitives, services, or custom logic.
130+
- **Extensibility:** Create your own attributes to integrate with configuration, environment, or any other source. Attributes can access the container for advanced scenarios.
131+
- **Clarity:** Resolution logic is explicit and self-documenting in your code, making dependencies easier to understand and maintain.
132+
- **Beyond constructor injection:** Unlike auto wiring, attribute resolution is not limited to objects or constructor arguments—you can resolve scalars, arrays, or any value your attribute logic supports.
133+
134+
While auto wiring is convenient for simple object graphs and constructor injection, attribute resolution is ideal for more complex scenarios where you need precise control over how dependencies are provided.

docs/unstable/auto-wiring.md

Lines changed: 7 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ sections:
77
---
88
## Introduction
99

10-
> Note: Auto wiring is turned off by default but can be turned on by registering the `ReflectionContainer` as a container delegate. Read below and see the [documentation on delegate containers](/3.x/delegate-containers/).
10+
> Note: Auto wiring is turned off by default but can be turned on by registering the `ReflectionContainer` as a container delegate. Read below and see the [documentation on delegate containers](/5.x/delegate-containers/).
1111
1212
Container has the power to automatically resolve your objects and all of their dependencies recursively by inspecting the type hints of your constructor arguments. Unfortunately, this method of resolution has a few small limitations but is great for smaller apps. First of all, you are limited to constructor injection and secondly, all injections must be objects.
1313

@@ -24,22 +24,9 @@ namespace Acme;
2424

2525
class Foo
2626
{
27-
/**
28-
* @var \Acme\Bar
29-
*/
30-
public $bar;
31-
32-
/**
33-
* @var \Acme\Baz
34-
*/
35-
public $baz;
36-
37-
/**
38-
* Construct.
39-
*
40-
* @param \Acme\Bar $bar
41-
* @param \Acme\Baz $baz
42-
*/
27+
public Bar $bar;
28+
public Baz $baz;
29+
4330
public function __construct(Bar $bar, Baz $baz)
4431
{
4532
$this->bar = $bar;
@@ -49,16 +36,8 @@ class Foo
4936

5037
class Bar
5138
{
52-
/**
53-
* @var \Acme\Bam
54-
*/
55-
public $bam;
56-
57-
/**
58-
* Construct.
59-
*
60-
* @param \Acme\Bam $bam
61-
*/
39+
public Bam $bam;
40+
6241
public function __construct(Bam $bam)
6342
{
6443
$this->bam = $bam;
@@ -124,7 +103,7 @@ $container = new League\Container\Container();
124103

125104
// register the reflection container as a delegate to enable auto wiring
126105
$container->delegate(
127-
(new League\Container\ReflectionContainer())->cacheResolutions()
106+
new League\Container\ReflectionContainer(cacheResolutions: true)
128107
);
129108

130109
$fooOne = $container->get(Acme\Foo::class);

docs/unstable/definitions.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,7 @@ declare(strict_types=1);
193193

194194
$container = new League\Container\Container();
195195

196-
$container->share(Acme\Foo::class);
196+
$container->addShared(Acme\Foo::class);
197197
~~~
198198

199199
If you would like to make all your definitions to default to shared, you can define that on Container, meaning that the `add` method will default to setting your definitions as shared and multiple calls to `get` will return the same instance. Only definitions after this is set will default to shared.

docs/unstable/reflection-modes.md

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
---
2+
layout: post
3+
title: Auto Wiring
4+
sections:
5+
Introduction: introduction
6+
Usage: usage
7+
---
8+
## Introduction
9+
10+
The `ReflectionContainer` supports two modes, which can be enabled or disabled using the `mode` property:
11+
12+
- `ReflectionContainer::AUTO_WIRING` — Enables auto wiring (resolving dependencies by type-hint).
13+
- `ReflectionContainer::ATTRIBUTE_RESOLUTION` — Enables attribute-based resolution (using attributes like `#[Inject]` or `#[Resolve]`).
14+
15+
## Usage
16+
17+
By default, both modes are enabled. You can control them like this:
18+
19+
~~~php
20+
<?php
21+
22+
use League\Container\ReflectionContainer;
23+
24+
// Enable only auto wiring (disable attribute resolution)
25+
$container->delegate(
26+
new ReflectionContainer(
27+
cacheResolutions: false,
28+
mode: ReflectionContainer::AUTO_WIRING
29+
)
30+
);
31+
32+
// Enable only attribute resolution (disable auto wiring)
33+
$container->delegate(
34+
new ReflectionContainer(
35+
cacheResolutions: false,
36+
mode: ReflectionContainer::ATTRIBUTE_RESOLUTION
37+
)
38+
);
39+
40+
// Enable both (default)
41+
$container->delegate(
42+
new ReflectionContainer()
43+
);
44+
45+
// Change mode at runtime
46+
$reflectionContainer = new ReflectionContainer();
47+
$reflectionContainer->setMode(ReflectionContainer::AUTO_WIRING);
48+
~~~

docs/unstable/upgrade-guide.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ $container->add('string', new League\Container\Argument\RawArgument('a string'))
122122
$container->add('string', new League\Container\Argument\Literal\StringArgument('a string'));
123123
~~~
124124

125-
See [full documentation](/unstable/argument-types/) to determine the best changes for you.
125+
See [full documentation](/4.x/argument-types/) to determine the best changes for you.
126126

127127
## 2.x to 4.x
128128

0 commit comments

Comments
 (0)