Skip to content

Commit bf46c8d

Browse files
committed
Update docs
Signed-off-by: Felipe Sayão Lobato Abreu <github@mentordosnerds.com>
1 parent b6c86e9 commit bf46c8d

2 files changed

Lines changed: 109 additions & 0 deletions

File tree

docs/advanced/index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,4 @@ Advanced Topics
88
error-reporting
99
container-helper
1010
built-in-containers
11+
special-patterns

docs/advanced/special-patterns.rst

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
Special Patterns and Advanced Behaviors
2+
======================================
3+
4+
This section highlights advanced usage patterns, special behaviors, and edge cases supported by FastForward Container. Use these techniques to unlock more power and flexibility in your dependency management.
5+
6+
Singleton-like Service Resolution
7+
---------------------------------
8+
All containers (including ServiceProviderContainer and AggregateContainer) cache resolved services by default. This means each service is instantiated only once per container instance, ensuring singleton-like behavior. If you need a new instance each time, register a factory that returns a new object on every call.
9+
10+
.. code-block:: php
11+
12+
// Always returns the same instance
13+
$service1 = $container->get('foo');
14+
$service2 = $container->get('foo'); // $service1 === $service2
15+
16+
// To get a new instance each time, register a factory that does not cache
17+
$provider = new ArrayServiceProvider([
18+
'random_factory' => fn() => new InvokableFactory(RandomObject::class),
19+
]);
20+
21+
$container = container($provider);
22+
$factory = $container->get('random_factory');
23+
$obj1 = $factory($container); // New instance
24+
$obj2 = $factory($container); // New instance, different from $obj1
25+
26+
27+
Service Extensions and Decorators
28+
---------------------------------
29+
Extensions allow you to decorate or modify services after creation. You can chain multiple extensions, and each receives the previous result and the container (which may be a wrapper).
30+
31+
.. code-block:: php
32+
33+
$provider = new ArrayServiceProvider([
34+
'logger' => fn() => new Logger('app'),
35+
], [
36+
'logger' => function ($container, $logger) {
37+
// Decorate logger
38+
$logger->pushProcessor(new MyProcessor());
39+
return $logger;
40+
},
41+
]);
42+
43+
$container = container($provider);
44+
$logger = $container->get('logger');
45+
46+
Container Aliases and Self-Resolution
47+
-------------------------------------
48+
AggregateContainer registers itself under common aliases, including 'container', its class name, and the PSR-11 interface. This allows you to fetch the container itself from within a factory or extension:
49+
50+
.. code-block:: php
51+
52+
$container = container($provider);
53+
$self = $container->get('container'); // Returns the container instance
54+
$self2 = $container->get(FastForward\Container\ContainerInterface::class); // Also returns the container instance
55+
$self3 = $container->get(FastForward\Container\AggregateContainer::class); // Also returns the container instance
56+
$self4 = $container->get(Psr\Container\ContainerInterface::class); // Also returns the container instance
57+
58+
Fallback and Resolution Order
59+
-----------------------------
60+
When using AggregateContainer, services are resolved in the order containers are aggregated. The first container to provide a service wins. This enables fallback strategies:
61+
62+
.. code-block:: php
63+
64+
$containerA = new ArrayServiceProvider(['foo' => fn() => 'A']);
65+
$containerB = new ArrayServiceProvider(['foo' => fn() => 'B']);
66+
$container = container($containerA, $containerB);
67+
$foo = $container->get('foo'); // Returns 'A'
68+
69+
Factories as Services
70+
---------------------
71+
You can register any callable or FactoryInterface as a service. The container will invoke it with itself as argument:
72+
73+
.. code-block:: php
74+
75+
use FastForward\Container\Factory\InvokableFactory;
76+
$provider = new ArrayServiceProvider([
77+
'service' => new InvokableFactory(MyService::class),
78+
]);
79+
$service = container($provider)->get('service');
80+
81+
WrapperContainer for Delegation
82+
-------------------------------
83+
ServiceProviderContainer allows passing a wrapperContainer, which is injected into factories and extensions. This enables advanced delegation or testing scenarios.
84+
85+
.. code-block:: php
86+
87+
$provider = new ArrayServiceProvider([
88+
'foo' => fn() => 'bar',
89+
]);
90+
$wrapper = new ServiceProviderContainer($provider);
91+
$container = new ServiceProviderContainer($provider, $wrapper);
92+
// Now, factories/extensions receive $wrapper as the container argument
93+
94+
Error Handling and Custom Exceptions
95+
------------------------------------
96+
FastForward Container throws custom exceptions for different error scenarios:
97+
98+
- NotFoundException: Service not found
99+
- InvalidArgumentException: Invalid or unsupported argument
100+
- RuntimeException: Non-callable extension or runtime error
101+
102+
.. code-block:: php
103+
104+
try {
105+
$container->get('unknown');
106+
} catch (FastForward\Container\Exception\NotFoundException $e) {
107+
// Handle missing service
108+
}

0 commit comments

Comments
 (0)