diff --git a/src/Resolve.php b/src/Resolve.php index c16c5d9..219b2fb 100644 --- a/src/Resolve.php +++ b/src/Resolve.php @@ -6,6 +6,7 @@ use ReflectionClass; use ReflectionException; use ReflectionFunction; +use ReflectionNamedType; use ReflectionObject; use ReflectionParameter; @@ -74,59 +75,71 @@ function(ReflectionParameter $reflectionParameter) use ($container, $parameters) return $parameters[$parameter_name]; } - $parameter_type = $reflectionParameter->getType(); + $reflectionType = $reflectionParameter->getType(); - if( $parameter_type instanceof \ReflectionNamedType === false ) { - throw new ParameterResolutionException("Cannot resolve union or intersection types"); + if( empty($reflectionType) ){ + throw new ParameterResolutionException("Cannot resolve parameter with no type."); } - /** - * Check container and parameters for a match by type. - */ - if( !$parameter_type->isBuiltin() ) { + if( $reflectionType instanceof \ReflectionIntersectionType ){ + throw new ParameterResolutionException("Cannot resolve intersection types."); + } + elseif( $reflectionType instanceof \ReflectionNamedType ){ + $reflectionType = [$reflectionType]; + } + elseif( $reflectionType instanceof \ReflectionUnionType ){ + $reflectionType = $reflectionType->getTypes(); + } - if( $container && $container->has($parameter_type->getName()) ){ - return $container->get($parameter_type->getName()); - } + foreach( $reflectionType as $parameter_type ){ + /** + * Check container and parameters for a match by type. + */ + if( !$parameter_type->isBuiltin() ) { - // Try to find in the parameters supplied - $match = \array_filter( - $parameters, - function($parameter) use ($parameter_type): bool { - $parameter_type_name = $parameter_type->getName(); - return $parameter instanceof $parameter_type_name; + if( $container && $container->has($parameter_type->getName()) ){ + return $container->get($parameter_type->getName()); } - ); - if( $match ){ - return $match[ - \array_keys($match)[0] - ]; - } + // Try to find in the parameters supplied + $match = \array_filter( + $parameters, + function($parameter) use ($parameter_type): bool { + $parameter_type_name = $parameter_type->getName(); + return $parameter instanceof $parameter_type_name; + } + ); - try { + if( $match ){ + return $match[ + \array_keys($match)[0] + ]; + } - return $this->make( - $parameter_type->getName(), - $container, - $parameters - ); + try { + + return $this->make( + $parameter_type->getName(), + $container, + $parameters + ); + } + catch( \Exception $exception ){} } - catch( \Exception $exception ){} - } - /** - * If a default value is defined, use that, including a null value. - */ - if( $reflectionParameter->isDefaultValueAvailable() ){ - return $reflectionParameter->getDefaultValue(); - } - elseif( $reflectionParameter->allowsNull() ){ - return null; - } + /** + * If a default value is defined, use that, including a null value. + */ + if( $reflectionParameter->isDefaultValueAvailable() ){ + return $reflectionParameter->getDefaultValue(); + } + elseif( $reflectionParameter->allowsNull() ){ + return null; + } - if( !empty($exception) ){ - throw $exception; + if( !empty($exception) ){ + throw $exception; + } } throw new ParameterResolutionException("Cannot resolve parameter \"{$parameter_name}\"."); diff --git a/tests/ResolveTest.php b/tests/ResolveTest.php index 0b426c9..2b58153 100644 --- a/tests/ResolveTest.php +++ b/tests/ResolveTest.php @@ -562,7 +562,7 @@ public function test_resolve_reflection_parameters_with_making_class_with_constr ); } - public function test_resolve_reflection_parameters_with_non_reflection_named_type_throws_parameter_resolution_exception(): void + public function test_resolve_reflection_parameters_with_union_type(): void { $resolve = new class { use Resolve; @@ -572,7 +572,37 @@ public function test_resolve_reflection_parameters_with_non_reflection_named_typ $reflectionMethod = $reflectionClass->getMethod("resolveReflectionParameters"); $reflectionMethod->setAccessible(true); - $callable = function(DateTime|DateTimeImmutable $dateTime): void { + $callable = function(DateTime|DateTimeImmutable $dateTime): string { + return "The date is now: " . $dateTime->format("c"); + }; + + $dateTime = new DateTimeImmutable("2020-01-28T12:00:01-08:00"); + + $reflectionFunction = new ReflectionFunction($callable); + $result = $reflectionMethod->invoke( + $resolve, + $reflectionFunction->getParameters(), + null, + ["dateTime" => $dateTime] + ); + + $this->assertSame( + $dateTime, + $result[0] + ); + } + + public function test_resolve_reflection_parameters_with_intersection_type_throws_parameter_resolution_exception(): void + { + $resolve = new class { + use Resolve; + }; + + $reflectionClass = new ReflectionClass($resolve); + $reflectionMethod = $reflectionClass->getMethod("resolveReflectionParameters"); + $reflectionMethod->setAccessible(true); + + $callable = function(DateTime&DateTimeImmutable $dateTime): void { echo "The date is now: " . $dateTime; };