Error Reporting
FastForward Container uses custom exception classes for error handling, all under the FastForward\Container\Exception
namespace:
ContainerException: For general container errors (implements PSR-11ContainerExceptionInterface)AutowiringException: Required constructor arguments cannot be inferred (implements PSR-11ContainerExceptionInterface)NotFoundException: Thrown when a service identifier is not found (implements PSR-11NotFoundExceptionInterface)InvalidArgumentException: For invalid or unsupported argumentsRuntimeException: For runtime errors, such as non-callable extensions or non-public methods
An aggregate continues trying later sources after a delegated PSR-11 failure. If no
source succeeds, it rethrows the first construction failure instead of replacing it
with a not-found exception. If all sources are absent, it throws NotFoundException
.
Optional constructor arguments use their declared defaults only for missing entries or structurally unresolvable dependency graphs. Runtime constructor/factory errors, invalid injected types and cycles remain failures. Their original causes are retained.
For example, a missing optional logger may use its declared null
default. A logger
factory that throws during construction propagates a ContainerException
with its
cause preserved when no other source can resolve it. A dependency cycle also propagates
a ContainerException
with the cycle path. Choosing a default does not recover from
these execution failures.
Service-provider factories, aliases and extensions also detect circular resolution,
independently of native constructor autowiring. The exception cause includes the
active path, for example Circular dependency: a -> b -> a.
. Providers composed
through the same wrapper share that path within one execution context. Each PHP
Fiber has an independent active path, separate from the main execution context.
Re-entering the same provider and ID
fails promptly, while another provider may still resolve that ID through the
aggregate's normal fallback behavior.
Resolution paths are cleared after success or failure. Failed entries are not cached, so a later request can retry construction after the application's configuration or factory state has been corrected. Completed services retain the usual per-container shared-instance behavior.
Path isolation does not serialize concurrent construction or provide a single-flight lock: two fibers may begin constructing the same uncached service. Successful results still use the container's existing cache.
See Autowire for the optional-dependency outcome table and guidance on explicit factory recovery when the application intentionally tolerates a particular failure.
Example:
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\NotFoundExceptionInterface;
try {
$service = $container->get('service.id');
} catch (NotFoundExceptionInterface $e) {
// The entry is unknown.
} catch (ContainerExceptionInterface $e) {
// The entry is known, but resolution failed. Inspect the cause.
}
has()
checks whether an entry is known; it does not guarantee that get()
will succeed. A known class with uninferable arguments or a construction failure
can return true
from has()
and throw a construction exception from get()
.
An unknown entry returns false
and get()
throws NotFoundExceptionInterface
.