Skip to content

Commit ee59eae

Browse files
authored
Merge pull request #236 from nhedger/feat/dnf
[3.x] feat: add support for DNF types
2 parents d9aa5a3 + 19d5229 commit ee59eae

File tree

4 files changed

+87
-7
lines changed

4 files changed

+87
-7
lines changed

src/functions.php

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -267,14 +267,18 @@ function _checkTypehint(callable $callback, \Throwable $reason): bool
267267
}
268268

269269
foreach ($types as $type) {
270-
if (!$type instanceof \ReflectionNamedType) {
271-
throw new \LogicException('This implementation does not support groups of intersection or union types');
272-
}
273-
274-
// A named-type can be either a class-name or a built-in type like string, int, array, etc.
275-
$matches = ($type->isBuiltin() && \gettype($reason) === $type->getName())
276-
|| (new \ReflectionClass($type->getName()))->isInstance($reason);
277270

271+
if ($type instanceof \ReflectionIntersectionType) {
272+
foreach ($type->getTypes() as $typeToMatch) {
273+
if (!($matches = ($typeToMatch->isBuiltin() && \gettype($reason) === $typeToMatch->getName())
274+
|| (new \ReflectionClass($typeToMatch->getName()))->isInstance($reason))) {
275+
break;
276+
}
277+
}
278+
} else {
279+
$matches = ($type->isBuiltin() && \gettype($reason) === $type->getName())
280+
|| (new \ReflectionClass($type->getName()))->isInstance($reason);
281+
}
278282

279283
// If we look for a single match (union), we can return early on match
280284
// If we look for a full match (intersection), we can return early on mismatch

tests/FunctionCheckTypehintTest.php

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,39 @@ public function shouldAcceptStaticClassCallbackWithIntersectionTypehint()
115115
self::assertTrue(_checkTypehint([CallbackWithIntersectionTypehintClass::class, 'testCallbackStatic'], new CountableException()));
116116
}
117117

118+
/**
119+
* @test
120+
* @requires PHP 8.2
121+
*/
122+
public function shouldAcceptInvokableObjectCallbackWithDNFTypehint()
123+
{
124+
self::assertFalse(_checkTypehint(new CallbackWithDNFTypehintClass(), new \RuntimeException()));
125+
self::assertTrue(_checkTypehint(new CallbackWithDNFTypehintClass(), new ArrayAccessibleException()));
126+
self::assertTrue(_checkTypehint(new CallbackWithDNFTypehintClass(), new CountableException()));
127+
}
128+
129+
/**
130+
* @test
131+
* @requires PHP 8.2
132+
*/
133+
public function shouldAcceptObjectMethodCallbackWithDNFTypehint()
134+
{
135+
self::assertFalse(_checkTypehint([new CallbackWithDNFTypehintClass(), 'testCallback'], new \RuntimeException()));
136+
self::assertTrue(_checkTypehint([new CallbackWithDNFTypehintClass(), 'testCallback'], new CountableException()));
137+
self::assertTrue(_checkTypehint([new CallbackWithDNFTypehintClass(), 'testCallback'], new ArrayAccessibleException()));
138+
}
139+
140+
/**
141+
* @test
142+
* @requires PHP 8.2
143+
*/
144+
public function shouldAcceptStaticClassCallbackWithDNFTypehint()
145+
{
146+
self::assertFalse(_checkTypehint([CallbackWithDNFTypehintClass::class, 'testCallbackStatic'], new \RuntimeException()));
147+
self::assertTrue(_checkTypehint([CallbackWithDNFTypehintClass::class, 'testCallbackStatic'], new CountableException()));
148+
self::assertTrue(_checkTypehint([CallbackWithDNFTypehintClass::class, 'testCallbackStatic'], new ArrayAccessibleException()));
149+
}
150+
118151
/** @test */
119152
public function shouldAcceptClosureCallbackWithoutTypehint()
120153
{
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<?php
2+
3+
namespace React\Promise;
4+
5+
use RuntimeException;
6+
7+
class ArrayAccessibleException extends RuntimeException implements \ArrayAccess
8+
{
9+
public function offsetExists(mixed $offset): bool
10+
{
11+
return true;
12+
}
13+
14+
public function offsetGet(mixed $offset): mixed
15+
{
16+
return $offset;
17+
}
18+
19+
public function offsetSet(mixed $offset, mixed $value): void {}
20+
21+
public function offsetUnset(mixed $offset): void {}
22+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<?php
2+
3+
namespace React\Promise;
4+
5+
use Countable;
6+
use RuntimeException;
7+
8+
class CallbackWithDNFTypehintClass
9+
{
10+
public function __invoke((RuntimeException&Countable)|(RuntimeException&\ArrayAccess) $e)
11+
{
12+
}
13+
14+
public function testCallback((RuntimeException&Countable)|(RuntimeException&\ArrayAccess) $e)
15+
{
16+
}
17+
18+
public static function testCallbackStatic((RuntimeException&Countable)|(RuntimeException&\ArrayAccess) $e)
19+
{
20+
}
21+
}

0 commit comments

Comments
 (0)