Skip to content

Commit 64a2cfd

Browse files
committed
Added support for nullable union types
1 parent a03bd53 commit 64a2cfd

File tree

2 files changed

+49
-8
lines changed

2 files changed

+49
-8
lines changed

src/mako/syringe/Container.php

Lines changed: 30 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,12 @@
1919
use ReflectionMethod;
2020
use ReflectionNamedType;
2121
use ReflectionParameter;
22+
use ReflectionUnionType;
2223

2324
use function array_keys;
2425
use function array_replace;
2526
use function array_values;
27+
use function count;
2628
use function is_array;
2729
use function is_int;
2830
use function vsprintf;
@@ -254,14 +256,35 @@ protected function resolveParameter(ReflectionParameter $parameter, ?ReflectionC
254256

255257
$parameterClassName = null;
256258

257-
if ($parameterType instanceof ReflectionNamedType && !$parameterType->isBuiltin()) {
258-
$parameterClassName = $parameterType->getName();
259-
}
260-
elseif ($parameterType instanceof ReflectionIntersectionType) {
261-
$parameterClassName = (string) $parameterType;
259+
if ($parameterType !== null) {
260+
if ($parameterType instanceof ReflectionNamedType) {
261+
if (!$parameterType->isBuiltin()) {
262+
$parameterClassName = $parameterType->getName();
263+
}
264+
}
265+
else {
266+
// Checking if we have a intersection type
267+
268+
if ($parameterType instanceof ReflectionIntersectionType) {
269+
$parameterClassName = (string) $parameterType;
270+
}
271+
272+
// Nullable intersection types will be detected as a union type so we'll have to dig deeper
262273

263-
if (!$this->has($parameterClassName)) {
264-
$parameterClassName = null;
274+
elseif ($parameterType instanceof ReflectionUnionType && $parameterType->allowsNull()) {
275+
$intersection = array_filter($parameterType->getTypes(), fn ($type) => $type instanceof ReflectionIntersectionType);
276+
277+
if (count($intersection) === 1) {
278+
$parameterClassName = (string) $intersection[0];
279+
}
280+
}
281+
282+
// If the intersection type isn't registered in the container
283+
// then we'll just set the classname back to null
284+
285+
if ($parameterClassName !== null && !$this->has($parameterClassName)) {
286+
$parameterClassName = null;
287+
}
265288
}
266289
}
267290

tests/unit/syringe/ContainerTest.php

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,14 @@ public function __construct(
200200
}
201201
}
202202

203+
class NullableIntersection
204+
{
205+
public function __construct(
206+
public null|(IA&IB) $ab
207+
) {
208+
}
209+
}
210+
203211
// --------------------------------------------------------------------------
204212
// END CLASSES
205213
// --------------------------------------------------------------------------
@@ -906,7 +914,17 @@ public function testResolveIntersectionTypeWithoutRegisteredHint(): void
906914
$container = new Container;
907915

908916
$object = $container->get(Intersection::class);
917+
}
909918

910-
$this->assertInstanceOf(AB::class, $object->ab);
919+
/**
920+
*
921+
*/
922+
public function testResolveNullableIntersectionTypeWithoutRegisteredHint(): void
923+
{
924+
$container = new Container;
925+
926+
$object = $container->get(NullableIntersection::class);
927+
928+
$this->assertNull($object->ab);
911929
}
912930
}

0 commit comments

Comments
 (0)