Skip to content
Merged
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
56 changes: 21 additions & 35 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,58 +21,44 @@ composer require utopia-php/di
```php
require_once __DIR__.'/../vendor/autoload.php';

use Psr\Container\ContainerInterface;
use Utopia\DI\Container;
use Utopia\DI\Dependency;

$di = new Container();

$di->set(
key: 'age',
factory: new Dependency(
injections: [],
callback: fn () => 25
)
);
$di->set('age', fn (): int => 25);

$di->set(
key: 'john',
factory: new Dependency(
injections: ['age'],
callback: fn (int $age) => 'John Doe is '.$age.' years old.'
)
'john',
fn (int $age): string => 'John Doe is '.$age.' years old.',
['age']
);

$john = $di->get('john');
```

For `Dependency` factories, the `injections` array is matched to callback parameter names, so the array order does not need to mirror the callback signature.
Dependencies are resolved from the third `set()` argument and passed to the factory in that same order.

You can still register plain factories directly when you want access to the container instance.
Register factories directly and list the dependency IDs they need.

```php
$di->set(
key: 'config',
factory: fn (ContainerInterface $container) => [
'dsn' => 'mysql:host=localhost;dbname=app',
'username' => 'root',
'password' => 'secret',
]
);

$request = $di->scope();
$di->set('config', fn (): array => [
'dsn' => 'mysql:host=localhost;dbname=app',
'username' => 'root',
'password' => 'secret',
]);

$request->set(
key: 'db',
factory: fn (ContainerInterface $container) => new PDO(
$container->get('config')['dsn'],
$container->get('config')['username'],
$container->get('config')['password']
)
$di->set(
'db',
fn (array $config): PDO => new PDO(
$config['dsn'],
$config['username'],
$config['password']
),
['config']
);
```

Factories are resolved once per container instance. A child scope behaves in two distinct ways:
Factories are resolved once per container instance. A child container behaves in two distinct ways:

- If the child does not define a key, it falls back to the parent and reuses the parent's resolved value.
- If the child defines the same key locally, it resolves and caches its own value without changing the parent.
Expand All @@ -88,7 +74,7 @@ $di->set('requestId', function () use (&$counter): string {

$di->get('requestId'); // "request-1"

$child = $di->scope();
$child = new Container($di);

$child->get('requestId'); // "request-1" (falls back to the parent cache)

Expand Down
2 changes: 1 addition & 1 deletion src/DI/Container.php
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ public function __construct(
* @param callable $factory Factory callable invoked to create the instance.
* @param list<string> $dependencies List of dependency IDs required by the factory.
*/
public function set(string $id, callable $factory, array $dependencies): static
public function set(string $id, callable $factory, array $dependencies = []): static
{
$this->factories[$id] = $factory;
$this->dependencies[$id] = $dependencies;
Expand Down
8 changes: 8 additions & 0 deletions tests/ContainerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,14 @@ public function testSetAndGetDependency(): void
$this->assertSame('bar', $container->get('foo'));
}

public function testSetDefaultsDependenciesToEmptyArray(): void
{
$container = new Container();
$container->set('foo', fn (): string => 'bar');

$this->assertSame('bar', $container->get('foo'));
}

public function testSetReturnsContainer(): void
{
$container = new Container();
Expand Down
Loading