+ * use FireHub\Container\Container;
+ *
+ * $container = new Container;
+ *
+ * $scope = $container->createScope();
+ *
+ *
+ * @since 1.0.0
+ */
+ public function createScope ():ScopeBoundary {
+
+ return new Scope($this->resolver);
+
+ }
+
+ /**
+ * ### Registers a service definition
+ *
+ * Associates a service identifier with its definition.
+ *
+ * Registration is only permitted while the container is not frozen.
+ *
+ *
+ * use FireHub\Container\Container;
+ *
+ * $container = new Container;
+ *
+ * $container->register(Test::class, new Cls(Test::class));
+ *
+ *
+ * @since 1.0.0
+ *
+ * @uses \FireHub\Container\Container::assertMutable() To check if the container is frozen.
+ * @uses \FireHub\Container\Registry::register() To register a service definition.
+ *
+ * @template TService of object
+ *
+ * @param class-string+ * Service identifier. + *
+ * @param \FireHub\Container\Definition $definition+ * Service definition. + *
+ * + * @throws \FireHub\Container\Exception\ContainerFrozenException If the container is frozen. + * @throws \FireHub\Container\Exception\DuplicateServiceException If the identifier is already registered. + * + * @return $this Container instance. + */ + public function register (string $id, Definition $definition):self { + + $this->assertMutable(); + + $this->registry->register($id, $definition); + + return $this; + + } + + /** + * ### Registers a contextual dependency binding + * + * Associates a specific consumer class with an implementation to be used when resolving the specified dependency. + * + * Contextual bindings apply only to the exact consumer class and do not affect global service registrations. + * + * The target service retains its configured lifetime. + * @since 1.0.0 + * + * @uses \FireHub\Container\Container::assertMutable() + * @uses \FireHub\Container\Internal\ContextualBindingRegistry::register() + * + * @param class-string $consumer+ * Consumer implementation class. + *
+ * @param class-string $dependency+ * Required dependency contract. + *
+ * @param class-string $implementation+ * Target service identifier. + *
+ * + * @throws \FireHub\Container\Exception\ContainerFrozenException If the container is frozen. + * @throws \FireHub\Container\Exception\DuplicateContextualBindingException If the binding already exists. + * + * @return $this Container instance. + */ + public function bindContextual (string $consumer, string $dependency, string $implementation):self { + + $this->assertMutable(); + + $this->contextual->register( + $consumer, + $dependency, + $implementation + ); + + return $this; + + } + + /** + * {@inheritDoc} + * + *
+ * use FireHub\Container\Container;
+ *
+ * $container = new Container;
+ *
+ * $container->bind(Test::class, Test::class);
+ *
+ *
+ * @since 1.0.0
+ *
+ * @uses \FireHub\Container\Container::register() To register a service definition.
+ *
+ * @throws \FireHub\Container\Exception\ContainerFrozenException If the container is frozen.
+ * @throws \FireHub\Container\Exception\DuplicateServiceException If the identifier is already registered.
+ */
+ public function bind (string $id, string $class, Lifetime $lifetime = Lifetime::TRANSIENT):self {
+
+ return $this->register(
+ $id,
+ new Cls($class, $lifetime)
+ );
+
+ }
+
+ /**
+ * ### Registers a singleton service
+ *
+ * Registers a class-based service instantiated once per container.
+ *
+ * When no implementation is provided, the identifier itself is used as the implementation class.
+ *
+ *
+ * use FireHub\Container\Container;
+ *
+ * $container = new Container;
+ *
+ * $container->singleton(Test::class);
+ *
+ * $first = $container->get(Test::class);
+ * $second = $container->get(Test::class);
+ *
+ * // $first === $second
+ *
+ *
+ * @since 1.0.0
+ *
+ * @uses \FireHub\Container\Container::bind() To register a class-based service.
+ *
+ * @template TService of object
+ *
+ * @param class-string+ * Service identifier. + *
+ * @param null|class-string+ * Implementation class. + *
+ * + * @throws \FireHub\Container\Exception\ContainerFrozenException If the container is frozen. + * @throws \FireHub\Container\Exception\DuplicateServiceException If the identifier is already registered. + * + * @return $this Container instance. + */ + public function singleton (string $id, ?string $class = null):self { + + return $this->bind( + $id, + $class ?? $id, + Lifetime::SINGLETON + ); + + } + + /** + * ### Registers a scoped service + * + * Registers a class-based service instantiated once per resolution scope. + * + * Each independent scope receives its own service instance. + * + *
+ * use FireHub\Container\Container;
+ *
+ * $container = new Container;
+ *
+ * $container->scoped(Test::class);
+ *
+ * $firstScope = $container->createScope();
+ * $secondScope = $container->createScope();
+ *
+ * $first = $firstScope->get(Test::class);
+ * $second = $secondScope->get(Test::class);
+ *
+ * // $first !== $second
+ *
+ * $firstScope->close();
+ * $secondScope->close();
+ *
+ *
+ * @since 1.0.0
+ *
+ * @uses \FireHub\Container\Container::bind() To register a class-based service.
+ *
+ * @template TService of object
+ *
+ * @param class-string+ * Service identifier. + *
+ * @param null|class-string+ * Implementation class. + *
+ * + * @throws \FireHub\Container\Exception\ContainerFrozenException If the container is frozen. + * @throws \FireHub\Container\Exception\DuplicateServiceException If the identifier is already registered. + * + * @return $this Container instance. + */ + public function scoped (string $id, ?string $class = null):self { + + return $this->bind( + $id, + $class ?? $id, + Lifetime::SCOPED + ); + + } + + /** + * ### Registers a transient service + * + * Registers a class-based service instantiated on each resolution. + * + *
+ * use FireHub\Container\Container;
+ *
+ * $container = new Container;
+ *
+ * $container->transient(Test::class);
+ *
+ * $first = $container->get(Test::class);
+ * $second = $container->get(Test::class);
+ *
+ * // $first !== $second
+ *
+ * @since 1.0.0
+ *
+ * @uses \FireHub\Container\Container::bind() To register a class-based service.
+ *
+ * @template TService of object
+ *
+ * @param class-string $id
+ * Service identifier.
+ *
+ * @param null|class-string $class [optional]
+ * Implementation class.
+ *
+ *
+ * @throws \FireHub\Container\Exception\ContainerFrozenException If the container is frozen.
+ * @throws \FireHub\Container\Exception\DuplicateServiceException If the identifier is already registered.
+ *
+ * @return $this Container instance.
+ */
+ public function transient (string $id, ?string $class = null):self {
+
+ return $this->bind(
+ $id,
+ $class ?? $id
+ );
+
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ *
+ * use FireHub\Container\Container;
+ *
+ * $container = new Container;
+ *
+ * $container->factory(
+ * Test::class,
+ * static fn ($resolver):Test => new Test
+ * );
+ *
+ * $service = $container->get(Test::class);
+ *
+ *
+ *
+ * use FireHub\Container\Container;
+ *
+ * $container = new Container;
+ *
+ * $container->singleton(Logger::class);
+ *
+ * $container->factory(
+ * Test::class,
+ * static fn ($resolver):Test => new Test(
+ * $resolver->get(Logger::class)
+ * )
+ * );
+ *
+ *
+ * @since 1.0.0
+ *
+ * @uses \FireHub\Container\Container::register() To register a service definition.
+ *
+ * @throws \FireHub\Container\Exception\ContainerFrozenException If the container is frozen.
+ * @throws \FireHub\Container\Exception\DuplicateServiceException If the identifier is already registered.
+ */
+ public function factory (string $id, Closure $factory, Lifetime $lifetime = Lifetime::TRANSIENT):self {
+
+ return $this->register(
+ $id,
+ new Factory($factory, $lifetime)
+ );
+
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ *
+ * use FireHub\Container\Container;
+ *
+ * $container = new Container;
+ *
+ * $instance = new Test;
+ *
+ * $container->instance(Test::class, $instance);
+ *
+ * $service = $container->get(Test::class);
+ *
+ * // $service === $instance
+ *
+ *
+ * @since 1.0.0
+ *
+ * @uses \FireHub\Container\Container::register() To register a service definition.
+ *
+ * @throws \FireHub\Container\Exception\ContainerFrozenException If the container is frozen.
+ * @throws \FireHub\Container\Exception\DuplicateServiceException If the identifier is already registered.
+ */
+ public function instance (string $id, object $instance):self {
+
+ return $this->register(
+ $id,
+ new Instance($instance)
+ );
+
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ *
+ * use FireHub\Container\Container;
+ *
+ * $container = new Container;
+ *
+ * $container->singleton(Test::class);
+ * $container->alias(TestInterface::class, Test::class);
+ *
+ * $service = $container->get(TestInterface::class);
+ *
+ *
+ * @since 1.0.0
+ *
+ * @uses \FireHub\Container\Container::register() To register a service definition.
+ *
+ * @throws \FireHub\Container\Exception\ContainerFrozenException If the container is frozen.
+ * @throws \FireHub\Container\Exception\DuplicateServiceException If the identifier is already registered.
+ */
+ public function alias (string $id, string $target):self {
+
+ return $this->register(
+ $id,
+ new Alias($target)
+ );
+
+ }
+
+ /**
+ * ### Registers explicit constructor parameter bindings
+ *
+ * Associates an implementation class with explicitly configured constructor argument values.
+ *
+ * Explicit bindings take precedence over automatic dependency resolution and constructor default values.
+ *
+ * Bindings are associated with the implementation class rather than a service identifier, allowing them to work
+ * with both registered and implicitly constructed services.
+ *
+ *
+ * use FireHub\Container\Container;
+ *
+ * $container = new Container;
+ *
+ * $container->bindParameters(
+ * Test::class,
+ * [
+ * 'name' => 'FireHub',
+ * 'enabled' => true
+ * ]
+ * );
+ *
+ * $service = $container->get(Test::class);
+ *
+ *
+ * @since 1.0.0
+ *
+ * @uses \FireHub\Container\Container::assertMutable() To ensure the container accepts configuration changes.
+ * @uses \FireHub\Container\Internal\ParameterBindingRegistry::register() To register parameter bindings.
+ *
+ * @param class-string $class
+ * Implementation class.
+ *
+ * @param array $parameters
+ * Constructor parameter names mapped to explicit values.
+ *
+ *
+ * @throws \FireHub\Container\Exception\ContainerFrozenException If the container is frozen.
+ *
+ * @return $this Container instance.
+ */
+ public function bindParameters (string $class, array $parameters):self {
+
+ $this->assertMutable();
+
+ $this->parameters->register($class, $parameters);
+
+ return $this;
+
+ }
+
+ /**
+ * ### Resolves a registered service
+ *
+ * Resolves the requested service using the configured service definitions.
+ *
+ * Singleton services are shared across the container. Transient services are constructed on each resolution.
+ *
+ * Scoped services cannot be resolved without an active scope.
+ *
+ *
+ * use FireHub\Container\Container;
+ *
+ * $container = new Container;
+ *
+ * $container->singleton(Test::class);
+ *
+ * $service = $container->get(Test::class);
+ *
+ *
+ * @since 1.0.0
+ *
+ * @template TService of object
+ *
+ * @param class-string $id
+ * Service identifier.
+ *
+ *
+ * @throws \FireHub\Container\Exception\ServiceNotFoundException If the service identifier is not registered.
+ * @throws \FireHub\Container\Exception\ServiceTypeMismatchException If the resolved service is not compatible
+ * with its registered identifier.
+ * @throws \FireHub\Container\Exception\UnsupportedDefinitionException If the service definition is not supported.
+ * @throws \FireHub\Container\Exception\ScopeRequiredException If the service requires a scope but none is provided.
+ * @throws \FireHub\Container\Exception\ScopeClosedException If the scope is closed.
+ * @throws \FireHub\Container\Exception\CircularDependencyException If a circular dependency is detected.
+ * @throws \FireHub\Container\Exception\AmbiguousDependencyException If multiple candidates are eligible.
+ *
+ * @return TService Resolved service.
+ */
+ public function get (string $id):object {
+
+ return $this->resolver->get($id);
+
+ }
+
+ /**
+ * ### Checks whether a service is registered
+ *
+ * Determines whether the registry contains a definition for the specified service identifier.
+ *
+ * This operation does not instantiate the service.
+ *
+ *
+ * use FireHub\Container\Container;
+ *
+ * $container = new Container;
+ *
+ * $container->singleton(Test::class);
+ *
+ * $registered = $container->has(Test::class);
+ *
+ * // true
+ *
+ *
+ * @since 1.0.0
+ *
+ * @param class-string $id
+ * Service identifier.
+ *
+ *
+ * @return bool True if registered, false otherwise.
+ */
+ public function has (string $id):bool {
+
+ return $this->registry->has($id);
+
+ }
+
+ /**
+ * ### Freezes the container
+ *
+ * Prevents any further service registrations.
+ *
+ * Existing service definitions remain available for resolution.
+ *
+ * Calling this method multiple times has no additional effect.
+ *
+ *
+ * use FireHub\Container\Container;
+ *
+ * $container = new Container;
+ *
+ * $container->singleton(Test::class);
+ *
+ * $container->freeze();
+ *
+ * // Existing services remain available.
+ * $service = $container->get(Test::class);
+ *
+ * // Further registrations are prohibited.
+ * // $container->singleton(AnotherTest::class);
+ *
+ *
+ * @since 1.0.0
+ *
+ * @return void
+ */
+ public function freeze ():void {
+
+ $this->frozen = true;
+
+ }
+
+ /**
+ * ### Checks whether the container is frozen
+ *
+ *
+ * use FireHub\Container\Container;
+ *
+ * $container = new Container;
+ *
+ * $container->isFrozen(); // false
+ *
+ * $container->freeze();
+ *
+ * $container->isFrozen(); // true
+ *
+ *
+ * @since 1.0.0
+ *
+ * @return bool True if frozen, false otherwise.
+ */
+ public function isFrozen ():bool {
+
+ return $this->frozen;
+
+ }
+
+ /**
+ * ### Ensures the container accepts registrations
+ *
+ * Prevents modification of service definitions after the container has been frozen.
+ * @since 1.0.0
+ *
+ * @throws \FireHub\Container\Exception\ContainerFrozenException If the container is frozen.
+ *
+ * @return void
+ */
+ private function assertMutable ():void {
+
+ if ($this->frozen)
+ throw new ContainerFrozenException;
+
+ }
+
+}
\ No newline at end of file
diff --git a/src/Definition.php b/src/Definition.php
new file mode 100644
index 0000000..27cedb2
--- /dev/null
+++ b/src/Definition.php
@@ -0,0 +1,22 @@
+
+ * @copyright 2026-present The FireHub Project - All rights reserved
+ * @license https://opensource.org/license/Apache-2-0 Apache License, Version 2.0
+ *
+ * @php-version >=7.0
+ * @package Container
+ */
+
+namespace FireHub\Container;
+
+/**
+ * ### Defines a service definition
+ *
+ * Describes the lifetime of a registered service without prescribing how its instance is created or resolved.
+ * @since 1.0.0
+ */
+interface Definition {}
\ No newline at end of file
diff --git a/src/Definition/Alias.php b/src/Definition/Alias.php
new file mode 100644
index 0000000..687b0fa
--- /dev/null
+++ b/src/Definition/Alias.php
@@ -0,0 +1,42 @@
+
+ * @copyright 2026-present The FireHub Project - All rights reserved
+ * @license https://opensource.org/license/Apache-2-0 Apache License, Version 2.0
+ *
+ * @php-version >=8.2
+ * @package Container
+ */
+
+namespace FireHub\Container\Definition;
+
+use FireHub\Container\Definition;
+
+/**
+ * ### Defines a service alias
+ *
+ * Redirects service resolution to another registered service identifier.
+ *
+ * Aliases do not own service instances or maintain independent lifetimes.
+ * @since 1.0.0
+ */
+final readonly class Alias implements Definition {
+
+ /**
+ * ### Constructor
+ * @since 1.0.0
+ *
+ * @param class-string $target
+ * Target service identifier.
+ *
+ *
+ * @return void
+ */
+ public function __construct (
+ public string $target
+ ) {}
+
+}
\ No newline at end of file
diff --git a/src/Definition/Cls.php b/src/Definition/Cls.php
new file mode 100644
index 0000000..aae8c07
--- /dev/null
+++ b/src/Definition/Cls.php
@@ -0,0 +1,59 @@
+
+ * @copyright 2026-present The FireHub Project - All rights reserved
+ * @license https://opensource.org/license/Apache-2-0 Apache License, Version 2.0
+ *
+ * @php-version >=8.2
+ * @package Container
+ */
+
+namespace FireHub\Container\Definition;
+
+use FireHub\Core\Meta\Enum\Container\Lifetime;
+
+/**
+ * ### Defines a class-based service
+ *
+ * Describes a service whose instance is constructed from a concrete class.
+ *
+ * The container may resolve constructor dependencies automatically.
+ * @since 1.0.0
+ *
+ * @template TService of object
+ */
+final readonly class Cls implements Service {
+
+ /**
+ * ### Constructor
+ * @since 1.0.0
+ *
+ * @param class-string $class
+ * Concrete implementation class.
+ *
+ * @param \FireHub\Core\Meta\Enum\Container\Lifetime $lifetime
+ * Service lifetime.
+ *
+ *
+ * @return void
+ */
+ public function __construct (
+ public string $class,
+ private Lifetime $lifetime = Lifetime::TRANSIENT
+ ) {}
+
+ /**
+ * @inheritDoc
+ *
+ * @since 1.0.0
+ */
+ public function lifetime ():Lifetime {
+
+ return $this->lifetime;
+
+ }
+
+}
\ No newline at end of file
diff --git a/src/Definition/Factory.php b/src/Definition/Factory.php
new file mode 100644
index 0000000..feb090a
--- /dev/null
+++ b/src/Definition/Factory.php
@@ -0,0 +1,59 @@
+
+ * @copyright 2026-present The FireHub Project - All rights reserved
+ * @license https://opensource.org/license/Apache-2-0 Apache License, Version 2.0
+ *
+ * @php-version >=8.2
+ * @package Container
+ */
+
+namespace FireHub\Container\Definition;
+
+use FireHub\Core\Meta\Enum\Container\Lifetime;
+use Closure;
+
+/**
+ * ### Defines a factory-based service
+ *
+ * Describes a service created by invoking a factory function.
+ *
+ * The factory receives the active dependency resolver, allowing dependencies to be resolved within the appropriate
+ * execution scope.
+ * @since 1.0.0
+ */
+final readonly class Factory implements Service {
+
+ /**
+ * ### Constructor
+ * @since 1.0.0
+ *
+ * @param Closure(\FireHub\Core\Boundary\Resolver):object $factory
+ * Service factory.
+ *
+ * @param \FireHub\Core\Meta\Enum\Container\Lifetime $lifetime
+ * Service lifetime.
+ *
+ *
+ * @return void
+ */
+ public function __construct (
+ public Closure $factory,
+ private Lifetime $lifetime = Lifetime::TRANSIENT
+ ) {}
+
+ /**
+ * @inheritDoc
+ *
+ * @since 1.0.0
+ */
+ public function lifetime ():Lifetime {
+
+ return $this->lifetime;
+
+ }
+
+}
\ No newline at end of file
diff --git a/src/Definition/Instance.php b/src/Definition/Instance.php
new file mode 100644
index 0000000..ea48c31
--- /dev/null
+++ b/src/Definition/Instance.php
@@ -0,0 +1,51 @@
+
+ * @copyright 2026-present The FireHub Project - All rights reserved
+ * @license https://opensource.org/license/Apache-2-0 Apache License, Version 2.0
+ *
+ * @php-version >=8.2
+ * @package Container
+ */
+
+namespace FireHub\Container\Definition;
+
+use FireHub\Core\Meta\Enum\Container\Lifetime;
+
+/**
+ * ### Defines an existing service instance
+ *
+ * Represents an already constructed object registered as a singleton service.
+ * @since 1.0.0
+ */
+final readonly class Instance implements Service {
+
+ /**
+ * ### Constructor
+ * @since 1.0.0
+ *
+ * @param object $instance
+ * Registered service instance.
+ *
+ *
+ * @return void
+ */
+ public function __construct (
+ public object $instance
+ ) {}
+
+ /**
+ * @inheritDoc
+ *
+ * @since 1.0.0
+ */
+ public function lifetime ():Lifetime {
+
+ return Lifetime::SINGLETON;
+
+ }
+
+}
\ No newline at end of file
diff --git a/src/Definition/Service.php b/src/Definition/Service.php
new file mode 100644
index 0000000..5c53b16
--- /dev/null
+++ b/src/Definition/Service.php
@@ -0,0 +1,42 @@
+
+ * @copyright 2026-present The FireHub Project - All rights reserved
+ * @license https://opensource.org/license/Apache-2-0 Apache License, Version 2.0
+ *
+ * @php-version >=7.4
+ * @package Container
+ */
+
+namespace FireHub\Container\Definition;
+
+use FireHub\Core\Meta\Enum\Container\Lifetime;
+use FireHub\Container\Definition;
+
+/**
+ * ### Defines a service definition with a managed lifetime
+ *
+ * Represents a registered service definition that specifies how long its resolved instance should be retained
+ * and reused by the dependency injection container.
+ *
+ * Service definitions provide lifetime metadata without prescribing how service instances are constructed,
+ * cached, or resolved.
+ * @since 1.0.0
+ */
+interface Service extends Definition {
+
+ /**
+ * ### Gets the service lifetime
+ *
+ * Returns the lifetime associated with this service definition, determining whether resolved instances are
+ * shared across the container, isolated within individual scopes, or created for each resolution request.
+ * @since 1.0.0
+ *
+ * @return \FireHub\Core\Meta\Enum\Container\Lifetime Configured service lifetime.
+ */
+ public function lifetime ():Lifetime;
+
+}
\ No newline at end of file
diff --git a/src/Exception/AmbiguousDependencyException.php b/src/Exception/AmbiguousDependencyException.php
new file mode 100644
index 0000000..24a9093
--- /dev/null
+++ b/src/Exception/AmbiguousDependencyException.php
@@ -0,0 +1,29 @@
+
+ * @copyright 2026-present The FireHub Project - All rights reserved
+ * @license https://opensource.org/license/Apache-2-0 Apache License, Version 2.0
+ *
+ * @php-version >=8.1
+ * @package Container
+ */
+
+namespace FireHub\Container\Exception;
+
+use FireHub\Core\Exception\RuntimeException;
+
+/**
+ * ### Thrown when multiple services match a dependency
+ *
+ * Indicates that automatic dependency resolution cannot select a unique
+ * candidate from multiple eligible service identifiers.
+ * @since 1.0.0
+ */
+final class AmbiguousDependencyException extends RuntimeException {
+
+ protected const string DEFAULT_MESSAGE = 'Multiple services match the requested dependency.';
+
+}
\ No newline at end of file
diff --git a/src/Exception/CircularDependencyException.php b/src/Exception/CircularDependencyException.php
new file mode 100644
index 0000000..183e044
--- /dev/null
+++ b/src/Exception/CircularDependencyException.php
@@ -0,0 +1,26 @@
+
+ * @copyright 2026-present The FireHub Project - All rights reserved
+ * @license https://opensource.org/license/Apache-2-0 Apache License, Version 2.0
+ *
+ * @php-version >=8.1
+ * @package Container
+ */
+
+namespace FireHub\Container\Exception;
+
+use FireHub\Core\Exception\Runtime\System\InvariantException;
+
+/**
+ * ### Thrown when a circular dependency is detected
+ * @since 1.0.0
+ */
+final class CircularDependencyException extends InvariantException {
+
+ protected const string DEFAULT_MESSAGE = 'Circular dependency detected';
+
+}
\ No newline at end of file
diff --git a/src/Exception/ContainerFrozenException.php b/src/Exception/ContainerFrozenException.php
new file mode 100644
index 0000000..703317e
--- /dev/null
+++ b/src/Exception/ContainerFrozenException.php
@@ -0,0 +1,26 @@
+
+ * @copyright 2026-present The FireHub Project - All rights reserved
+ * @license https://opensource.org/license/Apache-2-0 Apache License, Version 2.0
+ *
+ * @php-version >=8.1
+ * @package Container
+ */
+
+namespace FireHub\Container\Exception;
+
+use FireHub\Core\Exception\Runtime\System\InvariantException;
+
+/**
+ * ### Thrown when a container is attempted to be modified after it has been frozen
+ * @since 1.0.0
+ */
+final class ContainerFrozenException extends InvariantException {
+
+ protected const string DEFAULT_MESSAGE = 'Cannot register services in a frozen container';
+
+}
\ No newline at end of file
diff --git a/src/Exception/DuplicateContextualBindingException.php b/src/Exception/DuplicateContextualBindingException.php
new file mode 100644
index 0000000..0309a6d
--- /dev/null
+++ b/src/Exception/DuplicateContextualBindingException.php
@@ -0,0 +1,29 @@
+
+ * @copyright 2026-present The FireHub Project - All rights reserved
+ * @license https://opensource.org/license/Apache-2-0 Apache License, Version 2.0
+ *
+ * @php-version >=8.1
+ * @package Container
+ */
+
+namespace FireHub\Container\Exception;
+
+use FireHub\Core\Exception\Runtime\System\InvariantException;
+
+/**
+ * ### Thrown when a contextual dependency binding is already registered
+ *
+ * Indicates that a contextual dependency registration would violate the registry invariant requiring each
+ * consumer and dependency combination to have exactly one associated implementation.
+ * @since 1.0.0
+ */
+final class DuplicateContextualBindingException extends InvariantException {
+
+ protected const string DEFAULT_MESSAGE = 'A contextual binding for the specified consumer and dependency is already registered';
+
+}
\ No newline at end of file
diff --git a/src/Exception/DuplicateServiceException.php b/src/Exception/DuplicateServiceException.php
new file mode 100644
index 0000000..282a8eb
--- /dev/null
+++ b/src/Exception/DuplicateServiceException.php
@@ -0,0 +1,29 @@
+
+ * @copyright 2026-present The FireHub Project - All rights reserved
+ * @license https://opensource.org/license/Apache-2-0 Apache License, Version 2.0
+ *
+ * @php-version >=8.1
+ * @package Container
+ */
+
+namespace FireHub\Container\Exception;
+
+use FireHub\Core\Exception\Runtime\System\InvariantException;
+
+/**
+ * ### Thrown when a service identifier is already registered
+ *
+ * Indicates that a service registration would violate the registry invariant requiring each service identifier
+ * to have exactly one associated definition.
+ * @since 1.0.0
+ */
+final class DuplicateServiceException extends InvariantException {
+
+ protected const string DEFAULT_MESSAGE = 'A service with the specified identifier is already registered';
+
+}
\ No newline at end of file
diff --git a/src/Exception/ScopeActiveException.php b/src/Exception/ScopeActiveException.php
new file mode 100644
index 0000000..9ed842c
--- /dev/null
+++ b/src/Exception/ScopeActiveException.php
@@ -0,0 +1,29 @@
+
+ * @copyright 2026-present The FireHub Project - All rights reserved
+ * @license https://opensource.org/license/Apache-2-0 Apache License, Version 2.0
+ *
+ * @php-version >=8.1
+ * @package Container
+ */
+
+namespace FireHub\Container\Exception;
+
+use FireHub\Core\Exception\RuntimeException;
+
+/**
+ * ### Thrown when a scope operation conflicts with active execution
+ *
+ * Indicates that the scope cannot be closed or executed because another
+ * resolution or execution operation is currently active.
+ * @since 1.0.0
+ */
+final class ScopeActiveException extends RuntimeException {
+
+ protected const string DEFAULT_MESSAGE = 'The dependency injection scope is currently active.';
+
+}
\ No newline at end of file
diff --git a/src/Exception/ScopeClosedException.php b/src/Exception/ScopeClosedException.php
new file mode 100644
index 0000000..95482c7
--- /dev/null
+++ b/src/Exception/ScopeClosedException.php
@@ -0,0 +1,29 @@
+
+ * @copyright 2026-present The FireHub Project - All rights reserved
+ * @license https://opensource.org/license/Apache-2-0 Apache License, Version 2.0
+ *
+ * @php-version >=8.1
+ * @package Container
+ */
+
+namespace FireHub\Container\Exception;
+
+use FireHub\Core\Exception\RuntimeException;
+
+/**
+ * ### Thrown when accessing a closed dependency injection scope
+ *
+ * Indicates that an operation was attempted on a scope that has already been closed and is no longer available for
+ * service resolution.
+ * @since 1.0.0
+ */
+final class ScopeClosedException extends RuntimeException {
+
+ protected const string DEFAULT_MESSAGE = 'Cannot access a closed dependency injection scope.';
+
+}
\ No newline at end of file
diff --git a/src/Exception/ScopeRequiredException.php b/src/Exception/ScopeRequiredException.php
new file mode 100644
index 0000000..083c50e
--- /dev/null
+++ b/src/Exception/ScopeRequiredException.php
@@ -0,0 +1,29 @@
+
+ * @copyright 2026-present The FireHub Project - All rights reserved
+ * @license https://opensource.org/license/Apache-2-0 Apache License, Version 2.0
+ *
+ * @php-version >=8.1
+ * @package Container
+ */
+
+namespace FireHub\Container\Exception;
+
+use FireHub\Core\Exception\Runtime\System\InvariantException;
+
+/**
+ * ### Thrown when a scoped service is resolved without an active scope
+ *
+ * Indicates that a service configured with scoped lifetime was requested from a resolution context that does
+ * not provide scoped instance storage.
+ * @since 1.0.0
+ */
+final class ScopeRequiredException extends InvariantException {
+
+ protected const string DEFAULT_MESSAGE = 'Scoped service requires an active scope';
+
+}
\ No newline at end of file
diff --git a/src/Exception/ServiceInstantiationException.php b/src/Exception/ServiceInstantiationException.php
new file mode 100644
index 0000000..bd23fe3
--- /dev/null
+++ b/src/Exception/ServiceInstantiationException.php
@@ -0,0 +1,29 @@
+
+ * @copyright 2026-present The FireHub Project - All rights reserved
+ * @license https://opensource.org/license/Apache-2-0 Apache License, Version 2.0
+ *
+ * @php-version >=8.1
+ * @package Container
+ */
+
+namespace FireHub\Container\Exception;
+
+use FireHub\Core\Exception\RuntimeException;
+
+/**
+ * ### Thrown when a service cannot be instantiated
+ *
+ * Indicates that the dependency resolver failed to construct a service instance from its registered class
+ * definition.
+ * @since 1.0.0
+ */
+final class ServiceInstantiationException extends RuntimeException {
+
+ protected const string DEFAULT_MESSAGE = 'Failed to instantiate service';
+
+}
\ No newline at end of file
diff --git a/src/Exception/ServiceNotFoundException.php b/src/Exception/ServiceNotFoundException.php
new file mode 100644
index 0000000..3f9d4c4
--- /dev/null
+++ b/src/Exception/ServiceNotFoundException.php
@@ -0,0 +1,28 @@
+
+ * @copyright 2026-present The FireHub Project - All rights reserved
+ * @license https://opensource.org/license/Apache-2-0 Apache License, Version 2.0
+ *
+ * @php-version >=8.1
+ * @package Container
+ */
+
+namespace FireHub\Container\Exception;
+
+use FireHub\Core\Exception\Runtime\System\InvariantException;
+
+/**
+ * ### Thrown when a service definition cannot be found
+ *
+ * Indicates that the requested service identifier has no corresponding registration in the container registry.
+ * @since 1.0.0
+ */
+final class ServiceNotFoundException extends InvariantException {
+
+ protected const string DEFAULT_MESSAGE = 'No service definition found for the specified identifier';
+
+}
\ No newline at end of file
diff --git a/src/Exception/ServiceTypeMismatchException.php b/src/Exception/ServiceTypeMismatchException.php
new file mode 100644
index 0000000..1dbc31b
--- /dev/null
+++ b/src/Exception/ServiceTypeMismatchException.php
@@ -0,0 +1,29 @@
+
+ * @copyright 2026-present The FireHub Project - All rights reserved
+ * @license https://opensource.org/license/Apache-2-0 Apache License, Version 2.0
+ *
+ * @php-version >=8.1
+ * @package Container
+ */
+
+namespace FireHub\Container\Exception;
+
+use FireHub\Core\Exception\Runtime\System\InvariantException;
+
+/**
+ * ### Thrown when a resolved service does not match its registered identifier
+ *
+ * Indicates that a service definition produced an object that is not compatible with the class or interface
+ * associated with its registration.
+ * @since 1.0.0
+ */
+final class ServiceTypeMismatchException extends InvariantException {
+
+ protected const string DEFAULT_MESSAGE = 'Resolved service is not compatible with its registered identifier';
+
+}
\ No newline at end of file
diff --git a/src/Exception/UnsupportedDefinitionException.php b/src/Exception/UnsupportedDefinitionException.php
new file mode 100644
index 0000000..c40dbfa
--- /dev/null
+++ b/src/Exception/UnsupportedDefinitionException.php
@@ -0,0 +1,29 @@
+
+ * @copyright 2026-present The FireHub Project - All rights reserved
+ * @license https://opensource.org/license/Apache-2-0 Apache License, Version 2.0
+ *
+ * @php-version >=8.1
+ * @package Container
+ */
+
+namespace FireHub\Container\Exception;
+
+use FireHub\Core\Exception\Runtime\System\InvariantException;
+
+/**
+ * ### Thrown when an unsupported service definition is encountered
+ *
+ * Indicates that the container cannot process a registered service definition because its type is not supported
+ * by the dependency resolver.
+ * @since 1.0.0
+ */
+final class UnsupportedDefinitionException extends InvariantException {
+
+ protected const string DEFAULT_MESSAGE = 'Unsupported service definition';
+
+}
\ No newline at end of file
diff --git a/src/Internal/Autowirer.php b/src/Internal/Autowirer.php
new file mode 100644
index 0000000..14bf5d0
--- /dev/null
+++ b/src/Internal/Autowirer.php
@@ -0,0 +1,332 @@
+
+ * @copyright 2026-present The FireHub Project - All rights reserved
+ * @license https://opensource.org/license/Apache-2-0 Apache License, Version 2.0
+ *
+ * @php-version >=8.5
+ * @package Container
+ */
+
+namespace FireHub\Container\Internal;
+
+use FireHub\Container\Exception\ServiceInstantiationException;
+use Closure, ReflectionIntersectionType, ReflectionUnionType;
+
+/**
+ * ### Constructs services using compiled dependency plans
+ *
+ * Executes cached dependency construction plans to instantiate services and resolve their constructor dependencies.
+ *
+ * Static parameter analysis is performed by the dependency plan cache, while service availability, contextual
+ * bindings, and candidate selection are evaluated dynamically within the active resolution context.
+ *
+ * Explicit parameter bindings take precedence over contextual bindings and automatic dependency resolution.
+ * @since 1.0.0
+ *
+ * @internal
+ */
+final readonly class Autowirer {
+
+ /**
+ * ### Constructor
+ * @since 1.0.0
+ *
+ * @param Closure(class-string, \FireHub\Container\Internal\ResolutionContext):object $resolve
+ * Context-aware service resolver.
+ *
+ * @param Closure(class-string):bool $has
+ * Explicit service registration checker.
+ *
+ * @param \FireHub\Container\Internal\TypeMatcher $matcher
+ * Dependency type matcher.
+ *
+ * @param \FireHub\Container\Internal\CandidateSelector $selector
+ * Dependency candidate selector.
+ *
+ * @param \FireHub\Container\Internal\DependencyPlanCache $plans
+ * Shared dependency plan cache.
+ *
+ * @param \FireHub\Container\Internal\ParameterBindingRegistry $bindings
+ * Shared parameter binding registry.
+ *
+ * @param \FireHub\Container\Internal\ContextualCandidateSelector $contextual_selector
+ * Shared contextual dependency selector.
+ *
+ *
+ * @return void
+ */
+ public function __construct (
+ private Closure $resolve,
+ private Closure $has,
+ private TypeMatcher $matcher,
+ private CandidateSelector $selector,
+ private DependencyPlanCache $plans,
+ private ParameterBindingRegistry $bindings,
+ private ContextualCandidateSelector $contextual_selector
+ ) {}
+
+ /**
+ * ### Constructs a service using its compiled dependency plan
+ *
+ * Resolves constructor dependencies dynamically while reusing previously compiled parameter information.
+ * @since 1.0.0
+ *
+ * @uses \FireHub\Container\Internal\DependencyPlanCache::get() To retrieve the compiled construction plan.
+ * @uses \FireHub\Container\Internal\ConstructorMetadataCache::get() To get constructor metadata.
+ *
+ * @param class-string $class
+ * Concrete service class.
+ *
+ * @param \FireHub\Container\Internal\ResolutionContext $context
+ * Active dependency resolution context.
+ *
+ *
+ * @throws \FireHub\Container\Exception\ServiceInstantiationException If the parameter is not optional and cannot
+ * be resolved.
+ * @throws \FireHub\Container\Exception\ServiceNotFoundException If the service is not registered.
+ * @throws \FireHub\Container\Exception\AmbiguousDependencyException If multiple candidates are eligible.
+ *
+ * @return object Constructed service instance.
+ */
+ public function construct (string $class, ResolutionContext $context):object {
+
+ $plan = $this->plans->get($class);
+
+ $metadata = $plan->metadata;
+
+ if (!$metadata->instantiable)
+ throw new ServiceInstantiationException;
+
+ if (!$metadata->hasConstructor)
+ return $metadata->reflection->newInstance();
+
+ $arguments = [];
+
+ foreach ($plan->parameters as $parameter)
+ $arguments[] = $this->resolveParameter(
+ $class,
+ $parameter,
+ $context
+ );
+
+ return $metadata->reflection->newInstanceArgs($arguments);
+
+ }
+
+ /**
+ * ### Resolves a compiled constructor parameter
+ *
+ * Resolves constructor arguments according to the following precedence:
+ *
+ * 1. Explicit parameter binding.
+ * 2. Contextual dependency binding.
+ * 3. Registered or implicitly constructible dependency.
+ * 4. Constructor default value.
+ *
+ * Contextual bindings apply only to named dependency types and the exact consumer implementation class.
+ * @since 1.0.0
+ *
+ * @uses \FireHub\Container\Internal\ParameterBindingRegistry::has() To check explicit parameter bindings.
+ * @uses \FireHub\Container\Internal\ParameterBindingRegistry::get() To retrieve explicitly bound values.
+ * @uses \FireHub\Container\Internal\ContextualBindingRegistry::find() To find contextual dependency bindings.
+ * @uses \FireHub\Container\Internal\Autowirer::selectDependency() To select a dependency identifier.
+ * @uses \FireHub\Container\Internal\Autowirer::resolveDependency() To resolve selected dependencies.
+ * @uses \FireHub\Container\Internal\Autowirer::unresolvedParameter() To create resolution exceptions.
+ *
+ * @param class-string $class
+ * Concrete service class.
+ *
+ * @param \FireHub\Container\Internal\ParameterPlan $plan
+ * Compiled constructor parameter plan.
+ *
+ * @param \FireHub\Container\Internal\ResolutionContext $context
+ * Active resolution context.
+ *
+ *
+ * @throws \FireHub\Container\Exception\ServiceInstantiationException If the dependency cannot be resolved.
+ * @throws \FireHub\Container\Exception\AmbiguousDependencyException If multiple candidates are eligible.
+ *
+ * @return mixed Resolved argument.
+ */
+ private function resolveParameter (string $class, ParameterPlan $plan, ResolutionContext $context):mixed {
+
+ $name = $plan->parameter->getName();
+
+ if ($this->bindings->has($class, $name))
+ return $this->bindings->get($class, $name);
+
+ $id = $this->contextual_selector->select($class, $plan);
+
+ if ($id !== null)
+ return $this->resolveDependency($id, $plan, $context, true);
+
+ $id = $this->selectDependency($plan);
+
+ if ($id !== null && (
+ ($this->has)($id)
+ || $this->matcher->isConstructible($id)
+ )
+ ) return $this->resolveDependency($id, $plan, $context);
+
+ if ($plan->hasDefault)
+ return $plan->default;
+
+ throw $this->unresolvedParameter($plan);
+
+ }
+
+ /**
+ * ### Selects a dependency identifier
+ *
+ * Determines the service identifier required by a constructor parameter.
+ *
+ * Named dependency types use their precompiled identifiers. Union and intersection dependency types are
+ * evaluated dynamically against the currently registered service implementations.
+ * @since 1.0.0
+ *
+ * @uses \FireHub\Container\Internal\CandidateSelector::union() To select a union dependency.
+ * @uses \FireHub\Container\Internal\CandidateSelector::intersection() To select an intersection dependency.
+ *
+ * @param \FireHub\Container\Internal\ParameterPlan $plan
+ * Compiled constructor parameter plan.
+ *
+ *
+ * @throws \FireHub\Container\Exception\AmbiguousDependencyException If multiple candidates are eligible.
+ * @throws \FireHub\Container\Exception\AmbiguousDependencyException If multiple candidates are eligible.
+ * @throws \FireHub\Container\Exception\ServiceInstantiationException If the union contains an unsupported
+ * intersection member.
+ *
+ * @return null|class-string Selected dependency identifier.
+ */
+ private function selectDependency (ParameterPlan $plan):?string {
+
+ return match (true) {
+ $plan->composite instanceof ReflectionUnionType =>
+ $this->selector->union(
+ $plan->parameter,
+ $plan->composite
+ ),
+ $plan->composite instanceof ReflectionIntersectionType =>
+ $this->selector->intersection(
+ $plan->parameter,
+ $plan->composite
+ ),
+ default => $plan->id
+ };
+
+ }
+
+ /**
+ * ### Resolves a selected dependency
+ *
+ * Resolves the selected service identifier within the active resolution context.
+ *
+ * For union and intersection dependency types, validates that the resolved instance satisfies the complete
+ * declared parameter type.
+ * @since 1.0.0
+ *
+ * @uses \FireHub\Container\Resolver::resolve() To resolve the selected dependency.
+ * @uses \FireHub\Container\Internal\CandidateSelector::matchesType() To validate composite dependency types.
+ *
+ * @param class-string $id
+ * Selected dependency identifier.
+ *
+ * @param \FireHub\Container\Internal\ParameterPlan $plan
+ * Compiled constructor parameter plan.
+ *
+ * @param \FireHub\Container\Internal\ResolutionContext $context
+ * Active resolution context.
+ *
+ * @param bool $contextual [optional]
+ * Whether the dependency was selected through contextual binding.
+ *
+ *
+ * @throws \FireHub\Container\Exception\ServiceInstantiationException If the resolved dependency does not satisfy
+ * its declared composite type.
+ *
+ * @return object Resolved dependency.
+ */
+ private function resolveDependency (string $id, ParameterPlan $plan, ResolutionContext $context, bool $contextual = false):object {
+
+ $instance = ($this->resolve)($id, $context);
+
+ if (
+ $plan->composite !== null
+ && !$this->selector->matchesType(
+ $instance::class,
+ $plan->parameter,
+ $plan->composite
+ )
+ ) throw new ServiceInstantiationException(
+ context: [
+ 'class' => $plan->parameter->getDeclaringClass()?->getName(),
+ 'parameter' => $plan->parameter->getName(),
+ 'type' => (string)$plan->composite,
+ 'instance' => $instance::class,
+ ]
+ );
+
+ if (
+ $contextual
+ && $plan->composite === null
+ && $plan->id !== null
+ ) {
+
+ $expected = $plan->id;
+
+ if (!$instance instanceof $expected)
+ throw new ServiceInstantiationException(
+ context: [
+ 'class' => $plan->parameter->getDeclaringClass()?->getName(),
+ 'parameter' => $plan->parameter->getName(),
+ 'type' => $expected,
+ 'implementation' => $id,
+ 'instance' => $instance::class,
+ ]
+ );
+
+ }
+
+ return $instance;
+
+ }
+
+ /**
+ * ### Creates an unresolved parameter exception
+ *
+ * Creates an exception containing diagnostic information about a constructor parameter that could not be
+ * resolved through explicit bindings, contextual bindings, registered services, implicit construction, or
+ * default values.
+ * @since 1.0.0
+ *
+ * @param \FireHub\Container\Internal\ParameterPlan $plan
+ * Compiled constructor parameter plan.
+ *
+ *
+ * @return \FireHub\Container\Exception\ServiceInstantiationException Parameter resolution exception.
+ */
+ private function unresolvedParameter (ParameterPlan $plan):ServiceInstantiationException {
+
+ $parameter = $plan->parameter;
+
+ $type = $parameter->getType();
+
+ return new ServiceInstantiationException(
+ context: [
+ 'class' => $parameter->getDeclaringClass()?->getName(),
+ 'parameter' => $parameter->getName(),
+ 'position' => $parameter->getPosition(),
+ 'type' => $type?->__toString(),
+ 'nullable' => $type?->allowsNull(),
+ 'optional' => $parameter->isOptional(),
+ 'has_default' => $plan->hasDefault
+ ]
+ );
+
+ }
+
+}
\ No newline at end of file
diff --git a/src/Internal/CandidateSelector.php b/src/Internal/CandidateSelector.php
new file mode 100644
index 0000000..a700f11
--- /dev/null
+++ b/src/Internal/CandidateSelector.php
@@ -0,0 +1,289 @@
+
+ * @copyright 2026-present The FireHub Project - All rights reserved
+ * @license https://opensource.org/license/Apache-2-0 Apache License, Version 2.0
+ *
+ * @php-version >=8.2
+ * @package Container
+ */
+
+namespace FireHub\Container\Internal;
+
+use FireHub\Container\Exception\ {
+ AmbiguousDependencyException, ServiceInstantiationException
+};
+use FireHub\Runtime;
+use Closure, ReflectionIntersectionType, ReflectionNamedType,
+ ReflectionParameter, ReflectionType, ReflectionUnionType;
+
+/**
+ * ### Selects dependency injection candidates
+ *
+ * Evaluates available service candidates for union and intersection constructor dependency types.
+ *
+ * Explicit registrations take precedence over implicitly constructible classes when resolving union dependencies.
+ *
+ * Intersection dependencies are matched against statically known registered implementation types.
+ *
+ * Candidate selection does not instantiate services.
+ * @since 1.0.0
+ *
+ * @internal
+ */
+final readonly class CandidateSelector {
+
+ /**
+ * ### Constructor
+ * @since 1.0.0
+ *
+ * @param \FireHub\Container\Internal\TypeMatcher $matcher
+ * Dependency type matcher-
+ *
+ * @param Closure(class-string):bool $has
+ * Explicit service registration checker.
+ *
+ * @param Closure():(iterable) $candidates
+ * Registered service identifiers mapped to implementation classes.
+ *
+ */
+ public function __construct (
+ private TypeMatcher $matcher,
+ private Closure $has,
+ private Closure $candidates
+ ) {}
+
+ /**
+ * ### Selects a union or DNF dependency
+ *
+ * Selects a unique eligible service from the declared union alternatives.
+ *
+ * Registered candidates take precedence over implicitly constructible alternatives.
+ * @since 1.0.0
+ *
+ * @uses \FireHub\Container\Internal\CandidateSelector::matchesType() To check if a service implementation
+ * satisfies a dependency type.
+ * @uses \FireHub\Container\Internal\CandidateSelector::ambiguous() To report multiple candidates.
+ * @uses \FireHub\Container\Internal\TypeMatcher::classId() Resolves a parameter class identifier.
+ * @uses \FireHub\Container\Internal\TypeMatcher::isConstructible() Checks if a class is implicitly constructible.
+ * @uses \FireHub\Runtime\Arr\Inspection::count() To check if the union contains multiple candidates.
+ * @uses \FireHub\Runtime\Arr\Access::keys() To get the union member identifiers.
+ * @uses \FireHub\Runtime\Arr\Access::firstKey() To get the first union member identifier.
+ *
+ * @param ReflectionParameter $parameter
+ * Constructor parameter.
+ *
+ * @param ReflectionUnionType $type
+ * Union dependency type.
+ *
+ *
+ * @throws \FireHub\Container\Exception\AmbiguousDependencyException If multiple candidates are eligible.
+ * @throws \FireHub\Container\Exception\ServiceInstantiationException If the union contains an unsupported
+ * intersection member.
+ *
+ * @return null|class-string Selected service identifier.
+ */
+ public function union (ReflectionParameter $parameter, ReflectionUnionType $type):?string {
+
+ /** @var array $registered */
+ $registered = [];
+
+ /** @var array $implicit */
+ $implicit = [];
+
+ foreach (($this->candidates)() as $id => $implementation) {
+
+ if ($this->matchesType($implementation, $parameter, $type))
+ $registered[$id] = true;
+
+ }
+
+ foreach ($type->getTypes() as $member) {
+
+ if (!$member instanceof ReflectionNamedType)
+ continue;
+
+ $id = $this->matcher->classId($parameter, $member);
+
+ if ($id === null)
+ continue;
+
+ if (($this->has)($id)) {
+
+ $registered[$id] = true;
+
+ continue;
+
+ }
+
+ if ($this->matcher->isConstructible($id))
+ $implicit[$id] = true;
+
+ }
+
+ $selected = $registered !== []
+ ? $registered
+ : $implicit;
+
+ if (Runtime\Arr\Inspection::count($selected) > 1)
+ $this->ambiguous(
+ $parameter,
+ $type,
+ Runtime\Arr\Access::keys($selected)
+ );
+
+ return Runtime\Arr\Access::firstKey($selected);
+
+ }
+
+ /**
+ * ### Selects an intersection dependency
+ *
+ * Selects a registered service whose implementation satisfies every contract declared by the intersection type.
+ *
+ * Factories without statically known implementation types are excluded from candidate discovery.
+ * @since 1.0.0
+ *
+ * @uses \FireHub\Container\Internal\CandidateSelector::ambiguous() To report multiple candidates.
+ * @uses \FireHub\Container\Internal\CandidateSelector::matchesType() To check if a service implementation
+ * satisfies a dependency type.
+ * @uses \FireHub\Runtime\Arr\Inspection::count() To check if the union contains multiple candidates.
+ * @uses \FireHub\Runtime\Arr\Access::keys() To get the union member identifiers.
+ * @uses \FireHub\Runtime\Arr\Access::firstKey() To get the first union member identifier.
+ *
+ * @param ReflectionParameter $parameter
+ * Constructor parameter.
+ *
+ * @param ReflectionIntersectionType $type
+ * Intersection dependency type.
+ *
+ *
+ * @throws \FireHub\Container\Exception\AmbiguousDependencyException If multiple candidates satisfy the dependency.
+ *
+ * @return null|class-string Selected service identifier.
+ */
+ public function intersection (ReflectionParameter $parameter, ReflectionIntersectionType $type):?string {
+
+ /** @var array $matches */
+ $matches = [];
+
+ foreach (($this->candidates)() as $id => $implementation) {
+
+ if ($this->matchesType($implementation, $parameter, $type))
+ $matches[$id] = true;
+
+ }
+
+ if (Runtime\Arr\Inspection::count($matches) > 1)
+ $this->ambiguous(
+ $parameter,
+ $type,
+ Runtime\Arr\Access::keys($matches)
+ );
+
+ return Runtime\Arr\Access::firstKey($matches);
+
+ }
+
+ /**
+ * ### Checks whether an implementation satisfies a dependency type
+ *
+ * Evaluates named, intersection, and union dependency types recursively.
+ *
+ * Intersection types require all members to match, while union types require at least one matching member.
+ * @since 1.0.0
+ *
+ * @uses \FireHub\Container\Internal\TypeMatcher::classId() Resolves a parameter class identifier.
+ * @uses \FireHub\Container\Internal\TypeMatcher::matches() To check if a service implementation satisfies a
+ * contract.
+ *
+ * @param class-string $implementation
+ * Concrete implementation class.
+ *
+ * @param ReflectionParameter $parameter
+ * Constructor parameter.
+ *
+ * @param ReflectionType $type
+ * Dependency type.
+ *
+ *
+ * @return bool True if the implementation satisfies the dependency type.
+ */
+ public function matchesType (string $implementation, ReflectionParameter $parameter, ReflectionType $type):bool {
+
+ if ($type instanceof ReflectionNamedType) {
+
+ $contract = $this->matcher->classId($parameter, $type);
+
+ return $contract !== null
+ && $this->matcher->matches($implementation, $contract);
+
+ }
+
+ if ($type instanceof ReflectionIntersectionType) {
+
+ foreach ($type->getTypes() as $member) {
+
+ if (!$this->matchesType($implementation, $parameter, $member))
+ return false;
+
+ }
+
+ return true;
+
+ }
+
+ if ($type instanceof ReflectionUnionType) {
+
+ foreach ($type->getTypes() as $member) {
+
+ if ($this->matchesType($implementation, $parameter, $member))
+ return true;
+
+ }
+
+ return false;
+
+ }
+
+ return false;
+
+ }
+
+ /**
+ * ### Throws an ambiguous dependency exception
+ *
+ * Reports multiple eligible candidates for a constructor parameter.
+ * @since 1.0.0
+ *
+ * @param ReflectionParameter $parameter
+ * Constructor parameter.
+ *
+ * @param ReflectionUnionType|ReflectionIntersectionType $type
+ * Requested dependency type.
+ *
+ * @param list $candidates
+ * Matching service identifiers.
+ *
+ *
+ * @throws \FireHub\Container\Exception\AmbiguousDependencyException Always.
+ *
+ * @return never
+ */
+ private function ambiguous (ReflectionParameter $parameter, ReflectionUnionType|ReflectionIntersectionType $type, array $candidates):never {
+
+ throw new AmbiguousDependencyException(
+ context: [
+ 'class' => $parameter->getDeclaringClass()?->getName(),
+ 'parameter' => $parameter->getName(),
+ 'type' => (string)$type,
+ 'candidates' => $candidates
+ ]
+ );
+
+ }
+
+}
\ No newline at end of file
diff --git a/src/Internal/ConstructorMetadata.php b/src/Internal/ConstructorMetadata.php
new file mode 100644
index 0000000..bee5caf
--- /dev/null
+++ b/src/Internal/ConstructorMetadata.php
@@ -0,0 +1,57 @@
+
+ * @copyright 2026-present The FireHub Project - All rights reserved
+ * @license https://opensource.org/license/Apache-2-0 Apache License, Version 2.0
+ *
+ * @php-version >=8.2
+ * @package Container
+ */
+
+namespace FireHub\Container\Internal;
+
+use ReflectionClass, ReflectionParameter;
+
+/**
+ * ### Represents cached constructor metadata
+ *
+ * Provides immutable reflection metadata for a service implementation.
+ *
+ * Stores the reflected class, its insatiability, and constructor parameters without resolving dependencies or
+ * creating service instances.
+ * @since 1.0.0
+ *
+ * @internal
+ */
+final readonly class ConstructorMetadata {
+
+ /**
+ * ### Constructor
+ * @since 1.0.0
+ *
+ * @param ReflectionClass