Documentation menu
On this page
Components · v1.x
Container
The Container component is the dependency injection container of NeoPHP.
It autowires constructors, shares services by default, reads the #[Autowire] and #[Inject] attributes and is filled by feature providers and config/services.yaml.
Autowiring
Every class can be injected: the container reads the constructor and gives each parameter the service of its type. Controllers, middlewares, commands, listeners and view helpers are built this way.
<?php
declare(strict_types=1);
namespace App\Controller;
use App\Service\MailerInterface;
use NeoPHP\Component\Controller\Contract\AbstractController;
class NewsletterController extends AbstractController
{
public function __construct(protected MailerInterface $mailer)
{
}
}
A service is shared: the same instance is given everywhere during the request. #[Autowire(shared: false)] on the class, or shared: false in services.yaml, creates a new instance each time.
#[Autowire]
NeoPHP\Component\Container\Attribute\Autowire, on a constructor parameter, says what to inject when the type is not enough:
<?php
declare(strict_types=1);
namespace App\Service;
use NeoPHP\Component\Container\Attribute\Autowire;
class SmtpMailer implements MailerInterface
{
public function __construct(
#[Autowire(service: 'mailer.transport')] protected TransportInterface $transport,
#[Autowire(config: 'framework.app.name')] protected string $appName,
#[Autowire(env: 'MAILER_DSN')] protected string $dsn,
#[Autowire(param: 'kernel.debug')] protected bool $debug,
#[Autowire('%kernel.root_path%/var/mails')] protected string $spool,
) {
}
}
| Argument | Injected value |
|---|---|
value (first argument) |
a value; placeholders (%env(...)%, %kernel.*%, %config.key%) are resolved |
service |
the service with this id |
config |
a configuration value (framework.app.name) |
env |
an environment variable |
param |
a kernel parameter (kernel.debug, kernel.root_path...) |
shared |
on the class only: false creates a new instance each time |
A missing service, configuration key or environment variable throws a ContainerException, unless the parameter is nullable (it then receives null).
#[Autowire] is read on constructor parameters and callables run with call(), not on the parameters of a controller action: there, only the type-hint is used (see the Controller documentation).
#[Inject]
NeoPHP\Component\Container\Attribute\Inject, on a property, injects the value after the constructor. Without argument, the type of the property is used. It accepts service, config, env, param and value.
<?php
declare(strict_types=1);
namespace App\Service;
use NeoPHP\Component\Container\Attribute\Inject;
use NeoPHP\Component\Logger\Contract\LoggerInterface;
class ReportService
{
#[Inject]
protected LoggerInterface $logger;
#[Inject(config: 'framework.app.name')]
protected string $appName;
}
services.yaml
Application services are declared in config/services.yaml (read by the Service component):
services:
_defaults:
shared: true
App\:
resource: ../src/
exclude:
- ../src/Kernel.php
App\Service\SmtpMailer:
arguments:
$host: '%env(MAIL_HOST)%'
$logger: '@NeoPHP\Component\Logger\Contract\LoggerInterface'
calls:
- [setFrom, ['noreply@example.com']]
mailer: '@App\Service\SmtpMailer'
App\Service\NotifierInterface: '@App\Service\SmsNotifier'
app.api_client:
class: App\Service\ApiClient
factory: ['@App\Service\ApiClientFactory', 'create']
arguments:
$baseUrl: 'https://api.example.com'
shared: false
| Entry | Description |
|---|---|
_defaults.shared |
default value of shared for the file |
Namespace\: { resource, exclude, shared } |
registers every class of a directory (exclude: files, directories or * patterns, relative to the file) |
id: ~ |
registers a class with its default values |
id: '@other' / id: { alias: other } |
alias of another service |
class |
class of the service (default: the id) |
arguments |
arguments by name ($host) or by position; the others are autowired |
calls |
methods called after the construction: [method, [arguments]] |
factory |
['@service', 'method'], ['Class', 'method'] or 'Class::method' |
shared |
false creates a new instance each time |
In arguments, @id is a service, @?id a service or null when it does not exist, @@text the string @text, and %...% the configuration placeholders.
When one class of the file implements an interface, the interface is bound to it automatically. When several classes implement it, resolving the interface throws a ServiceException that asks for an alias. An interface already bound by the framework is never replaced.
services.yaml is compiled into var/cache/service/services.{env}.php, rebuilt in debug when the file or a class of a resource changes. In production, run php bin/neo cache:clear on every deployment. php bin/neo service:list and php bin/neo debug:container list the services.
Container API
Inject NeoPHP\Component\Container\Contract\ContainerInterface (implemented by ContainerManager). The configuration is registered under the id config.
| Method | Description |
|---|---|
get(string $id): mixed |
returns a service (built and autowired when needed) |
has(string $id): bool |
whether the id is bound, aliased or an existing class |
bind(string $id, mixed $concrete = null, bool $shared = false): static |
binds an id to a class, a closure fn (ContainerInterface $c) or a value |
singleton(string $id, mixed $concrete = null): static |
bind() with shared: true |
instance(string $id, mixed $value): static |
registers an existing value |
alias(string $alias, string $id): static |
makes $alias point to $id |
bound(string $id): bool |
whether the id is bound or registered |
resolved(string $id): bool |
whether a shared instance already exists |
make(string $id, array $parameters = []): mixed |
builds a new instance, with named parameters |
instantiate(string $class, array $parameters = []): object |
builds a class with autowiring and #[Inject] |
inject(object $object): object |
fills the #[Inject] properties of an object |
call(callable|array|string $callable, array $parameters = []): mixed |
calls a callable with autowired arguments ('Class::method', [$object, 'method']...) |
getDefinitions(): array / getAliases(): array |
registered definitions and aliases |
AbstractContainer also exposes resolveArguments(ReflectionFunctionAbstract $function, array $parameters = []): array.
$container->singleton(ClockInterface::class, SystemClock::class);
$container->bind('app.report', static fn (ContainerInterface $c): Report => new Report($c->get(LoggerInterface::class)));
$container->alias('clock', ClockInterface::class);
$report = $container->make(Report::class, ['title' => 'Monthly']);
$total = $container->call([$calculator, 'total'], ['year' => 2026]);
Providers
Each feature registers its services with a provider implementing ProviderInterface (register() then boot()). AbstractProvider gives an empty boot().
<?php
declare(strict_types=1);
namespace App\Provider;
use App\Service\SystemClock;
use App\Service\ClockInterface;
use NeoPHP\Component\Container\Contract\AbstractProvider;
use NeoPHP\Component\Container\Contract\ContainerInterface;
class ClockProvider extends AbstractProvider
{
public function register(ContainerInterface $container): void
{
$container->singleton(ClockInterface::class, SystemClock::class);
}
}
Controller trait
NeoPHP\Component\Container\Helper\Controller\ContainerController adds setContainer(ContainerInterface $container), get(string $id) and has(string $id) to a controller. It is required by every other controller trait (see the Controller documentation).
Exceptions
| Exception | Thrown when |
|---|---|
NeoPHP\Component\Container\Exception\ContainerException |
a class cannot be built, a parameter cannot be resolved, an alias points to itself |
NeoPHP\Component\Container\Exception\NotFoundException |
an id is not found (NotFoundException::forId($id)); extends ContainerException |
Changelog
- v1.14.0 —
getDefinitions()andgetAliases()on the container. - v1.8.0 —
#[Autowire]on parameters and classes,#[Inject]on properties,config/services.yaml, shared services by default, interfaces bound to their single implementation,service:listcommand. - v1.4.0 —
ContainerControllertrait for controllers. - v1.0.0 — Dependency injection container with autowiring and providers.