resolver-interop / interface
Interoperable autowiring resolver interfaces for PHP.
Requires
- php: >=8.4
- ioc-interop/interface: 1.x@dev
Requires (Dev)
- pds/composer-script-names: ^1.0
- pds/skeleton: ^1.0
- phpstan/phpstan: ^2.0
- pmjones/php-styler: 0.x@dev
- star-interop/stardoc: 1.x-dev
This package is not auto-updated.
Last update: 2026-05-24 15:07:19 UTC
README
Resolver-Interop provides an interoperable package of standard interfaces for autowiring resolver functionality. It reflects, refines, and reconciles the common practices identified within several pre-existing projects.
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in BCP 14 (RFC 2119, RFC 8174).
Interfaces
This package defines the following interfaces:
-
ClassResolver affords resolving a class to a new instance, and indicating whether a class may be resolved at all.
-
ReflectionParametersResolver affords resolving an array of ReflectionParameter instances into an array of arguments.
-
ReflectionParameterResolver affords resolving a ReflectionParameter to an argument value.
-
ReflectionTypeResolver affords resolving a ReflectionType to a
stringname, ornullif it cannot be resolved. -
ReflectionMethodsResolver affords instantiating and invoking ReflectionMethodResolver attributes on object methods.
-
ReflectionMethodResolver affords method injection when implemented on a method-targeted Attribute.
-
ReflectionPropertiesResolver affords instantiating and invoking ReflectionPropertyResolver attributes on object properties.
-
ReflectionPropertyResolver affords property injection when implemented on a property-targeted Attribute.
-
CallResolver affords resolving a callable's parameters and invoking it, returning the call's result.
-
Resolvable affords an implementing object the ability to resolve itself to a value.
-
ResolverThrowable extends Throwable to mark an Exception as resolver-related.
ClassResolver
ClassResolver affords resolving a class to a new instance, and indicating whether a class may be resolved at all.
ClassResolver Methods
-
public function resolveClass( IocInterop\Interface\IocContainer $ioc, class-string<T> $class, mixed[] $arguments = [], ) : T;
-
Resolves the
$classto return a new instance. -
Directives:
-
Implementations MUST resolve the
$classconstructor parameters using logic identical to that specified by ReflectionParametersResolver. -
Implementations MAY support property injection using logic identical to that specified by ReflectionPropertiesResolver.
-
Implementations MAY support method injection using logic identical to that specified by ReflectionMethodsResolver.
-
Implementations MAY support other forms of injection not specified herein.
-
Implementations MUST throw ResolverThrowable if the
$classcannot be resolved.
-
-
-
public function mayResolveClass(string $class) : bool;
-
May the resolver attempt to resolve
$class? -
Notes:
- The logic for this method is expressly unspecified.
Implementations may check
class_existsandReflectionClass::isInstantiable(), or apply stricter rules; e.g., requiring a registered service-name alias, rejecting abstract bases that lack a concrete binding, or excluding PHP-internal classes. Consumers should treat atrueresult as "the implementation is willing to tryresolveClass()", not as a guarantee that resolution will succeed.
- The logic for this method is expressly unspecified.
Implementations may check
-
ReflectionParametersResolver
ReflectionParametersResolver affords resolving an array of ReflectionParameter instances into an array of arguments.
ReflectionParametersResolver Methods
-
public function resolveParameters( IocInterop\Interface\IocContainer $ioc, ReflectionParameter[] $parameters, mixed[] $arguments = [], ) : mixed[];
-
Resolves the
$parametersinto the$arguments. -
Directives:
-
Implementations MUST NOT attempt to resolve a ReflectionParameter whose name or position already exists in the
$argumentskeys. -
When resolving a ReflectionParameter to an argument, implementations MUST do so using logic identical to that specified by ReflectionParameterResolver.
-
Implementations MUST retain each resolved ReflectionParameter by name in the
$arguments. -
Implementations MUST
resolve()every Resolvable at the top level of the$argumentsarray.
-
-
Notes:
-
Mixed name and position keys for the same parameter in the
$argumentspass through unchanged. Named and positional keys referring to the same parameters are preseved in the returned array as-is. -
Extra and out-of-range keys in
$argumentspass through unchanged. Keys that do not correspond to any parameter name or position, and positional keys whose integer index exceeds the parameter count, are preserved in the returned array as-is. -
Resolved parameters are retained by name. Pre-filled positional arguments retain their integer keys; newly-resolved parameters are keyed on their parameter name, not their position.
-
Resolve all
$arguments. Callers might pass one or more Resolvable as an argument; the implementation has to resolve them before returning.
-
-
ReflectionParameterResolver
ReflectionParameterResolver affords resolving a ReflectionParameter to an argument value.
This interface is also suitable for implementation on an Attribute to resolve a custom argument on a parameter.
-
Directives:
- An Attribute implementing this interface MUST NOT be declared
with
Attribute::IS_REPEATABLE.
- An Attribute implementing this interface MUST NOT be declared
with
ReflectionParameterResolver Methods
-
public function resolveParameter( IocInterop\Interface\IocContainer $ioc, ReflectionParameter $parameter, ) : mixed;
-
Resolves the ReflectionParameter to an argument value.
-
Directives:
-
Implementations MUST resolve the
$parameterin this order:-
If the
$parameterhas one or more Attribute that implements ReflectionParameterResolver, implementations MUST resolve the$parameterusing only the first such Attribute. -
Otherwise, if the
$parametertype is resolvable using logic identical to ReflectionTypeResolver and$ioc->hasService()returnstruefor that resolved type, implementations MUST resolve the$parameterto that service via$ioc->getService(). -
Otherwise, implementations MAY attempt to resolve the
$parameterusing implementation-specific logic; such logic is not defined herein. -
Otherwise, if the
$parameterhas a default value, implementations MUST resolve the$parameterto that value.
-
-
Implementations MUST throw ResolverThrowable if the
$parametercannot be resolved.
-
-
Notes:
- Variadic parameters resolve to a single value. Implementations
resolve a variadic
$parameteronce (via attribute, type, or default) and return that value as the variadic argument. Spreading across multiple variadic slots is not specified by this interface.
- Variadic parameters resolve to a single value. Implementations
resolve a variadic
-
ReflectionTypeResolver
ReflectionTypeResolver affords resolving a ReflectionType to a
string name, or null if it cannot be resolved.
ReflectionTypeResolver Methods
-
public function resolveType( IocInterop\Interface\IocContainer $ioc, ?ReflectionType $type, ) : ?string;
-
Resolves a ReflectionType to a
stringname, ornullif it cannot be resolved. -
Directives:
-
If
$typeisnull, implementations MUST returnnull. -
Otherwise, if
$typeis a ReflectionNamedType, implementations MUST return the type name as produced by itsgetName()method. -
Otherwise, the logic for determining the return type name is implementation-defined.
-
-
Notes:
- Compound and other type handling is left to the implementation.
For example, ReflectionUnionType and
ReflectionIntersectionType handling may vary between
implementations: one might iterate the branches and return the
first whose name corresponds to an
$iocservice name; another might return the compound stringification (e.g."Foo|Bar") and let the container lookup handle it; yet another might returnnullout of hand.
- Compound and other type handling is left to the implementation.
For example, ReflectionUnionType and
ReflectionIntersectionType handling may vary between
implementations: one might iterate the branches and return the
first whose name corresponds to an
-
ReflectionMethodsResolver
ReflectionMethodsResolver affords instantiating and invoking ReflectionMethodResolver attributes on object methods.
ReflectionMethodsResolver Methods
-
public function resolveMethods( IocInterop\Interface\IocContainer $ioc, ReflectionMethod[] $methods, object $object, ) : void;
-
Invokes the attributed
$methodson the$object. -
Directives:
-
For each ReflectionMethod in
$methodsthat carries one or more Attribute implementing ReflectionMethodResolver, implementations MUST invoke only the first such Attribute. -
Implementations MUST NOT invoke un-attributed methods.
-
Implementations MUST throw ResolverThrowable if resolution fails.
-
-
ReflectionMethodResolver
ReflectionMethodResolver affords method injection when implemented on a method-targeted Attribute.
-
Directives:
- An Attribute implementing this interface MUST NOT be declared
with
Attribute::IS_REPEATABLE.
- An Attribute implementing this interface MUST NOT be declared
with
ReflectionMethodResolver Methods
-
public function resolveMethod( IocInterop\Interface\IocContainer $ioc, ReflectionMethod $method, object $object, ) : void;
-
Invokes the ReflectionMethod on the
$object. -
Directives:
-
Implementations MUST support parameter injection using logic identical to that specified by ReflectionParametersResolver.
-
Implementations MUST invoke
$methodon$objectwith the resolved arguments. -
Implementations MUST throw ResolverThrowable if resolution fails.
-
-
ReflectionPropertiesResolver
ReflectionPropertiesResolver affords instantiating and invoking ReflectionPropertyResolver attributes on object properties.
ReflectionPropertiesResolver Methods
-
public function resolveProperties( IocInterop\Interface\IocContainer $ioc, ReflectionProperty[] $properties, object $object, ) : void;
-
Resolves the attributed
$propertieson the$object. -
Directives:
-
For each ReflectionProperty in
$propertiesthat carries one or more Attribute implementing ReflectionPropertyResolver, implementations MUST resolve the property using only the first such Attribute. -
Implementations MUST leave un-attributed properties unchanged.
-
Implementations MUST throw ResolverThrowable if any attempted resolution fails.
-
-
ReflectionPropertyResolver
ReflectionPropertyResolver affords property injection when implemented on a property-targeted Attribute.
-
Directives:
- An Attribute implementing this interface MUST NOT be declared
with
Attribute::IS_REPEATABLE.
- An Attribute implementing this interface MUST NOT be declared
with
ReflectionPropertyResolver Methods
-
public function resolveProperty( IocInterop\Interface\IocContainer $ioc, ReflectionProperty $property, object $object, ) : void;
-
Sets the ReflectionProperty on an object.
-
Directives:
-
Implementations MUST resolve the
$propertyin this order:-
Implementations MAY attempt to resolve the
$propertyusing implementation-specific logic; such logic is not defined herein. -
Otherwise, implementations MUST resolve the
$propertyto the IocContainer service whose name matches the property type as produced by ReflectionTypeResolver, via$ioc->getService().
-
-
Implementations MUST throw ResolverThrowable if resolution of
$propertyis attempted and fails.
-
-
CallResolver
CallResolver affords resolving a callable's parameters and invoking it, returning the call's result.
CallResolver Methods
-
public function resolveCall( IocInterop\Interface\IocContainer $ioc, callable $callable, mixed[] $arguments = [], ) : mixed;
-
Resolves the
$callableto return its result. -
Directives:
-
Implementations MUST resolve the
$callable's parameters using logic identical to that specified by ReflectionParametersResolver'sresolveParameters(), including the$argumentspre-fill and Resolvable-unwrap semantics specified there. -
Implementations MUST invoke the
$callablewith the resolved$argumentsand MUST return the result of that invocation. -
Implementations MUST throw ResolverThrowable if the
$callablecannot be resolved.
-
-
Resolvable
Resolvable affords an implementing object the ability to resolve itself to a value.
-
Notes:
Resolvabledefers container calls until the moment of resolution. Wrapping a container call in aResolvablelets the implmenting object be pass around without forcing the container interation at construction time.
Resolvable Methods
-
public function resolve(IocInterop\Interface\IocContainer $ioc) : mixed;
-
Resolves the implementing object to a value.
-
Directives:
-
Implementations MUST return a value that is neither itself a Resolvable nor contains any Resolvable instances.
-
Implementations MUST throw ResolverThrowable if the object cannot be resolved.
-
-
Notes:
- Resolve recursively as needed. Some implementations may return arrays or objects; the implementation might need to check their contents for other Resolvable instances so that the return value is fully and deeply resolved.
-
ResolverThrowable
ResolverThrowable extends Throwable to mark an Exception as resolver-related.
It adds no class members.
Implementations
-
Directives:
- Implementations MAY define additional class members not defined in these interfaces.
-
Notes:
- Reference implementations may be found at https://github.com/resolver-interop/impl.
Q & A
Why are there so many interfaces?
The researched projects typically afford autowiring through a
single container class with several methods (get(), make(),
call(), and so on), each performing a distinct resolution task.
Resolver-Interop opts to split those operations into separate interfaces. Doing so allows consumers to depend only on the specific methods they need, and implementors to combine them as they see fit.
Why are setter-injection and property-injection supported?
Constructor injection is the documented default across all the researched projects. Setter-injection is generally supported, whereas property-injection is far less common.
Resolver-Interop summarizes this guidance evident from the projects:
-
constructor injection is preferred above all;
-
but sometimes setter-injection is unavoidable, especially in legacy or refactoring scenarios;
-
and while property-injection is to be shunned prejudicially, having it available as an absolute last resort can be useful.
Thus, while Resolver-Interop does not forbid post-construction injection, it attempts to make explicit the appropriate scope for these alternative forms of injection.