Skip to content

Commit f23788b

Browse files
authored
Merge pull request #237 from nhedger/feat/dnf-2.x
[2.x] feat: add support for DNF types on PHP 8.2
2 parents caf9315 + 680afcf commit f23788b

File tree

4 files changed

+88
-8
lines changed

4 files changed

+88
-8
lines changed

src/functions.php

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -354,7 +354,7 @@ function _checkTypehint(callable $callback, $object)
354354

355355
// Extract the type of the argument and handle different possibilities
356356
$type = $expectedException->getType();
357-
357+
358358
$isTypeUnion = true;
359359
$types = [];
360360

@@ -379,14 +379,18 @@ function _checkTypehint(callable $callback, $object)
379379
}
380380

381381
foreach ($types as $type) {
382-
if (!$type instanceof \ReflectionNamedType) {
383-
throw new \LogicException('This implementation does not support groups of intersection or union types');
384-
}
385-
386-
// A named-type can be either a class-name or a built-in type like string, int, array, etc.
387-
$matches = ($type->isBuiltin() && \gettype($object) === $type->getName())
388-
|| (new \ReflectionClass($type->getName()))->isInstance($object);
389382

383+
if ($type instanceof \ReflectionIntersectionType) {
384+
foreach ($type->getTypes() as $typeToMatch) {
385+
if (!($matches = ($typeToMatch->isBuiltin() && \gettype($object) === $typeToMatch->getName())
386+
|| (new \ReflectionClass($typeToMatch->getName()))->isInstance($object))) {
387+
break;
388+
}
389+
}
390+
} else {
391+
$matches = ($type->isBuiltin() && \gettype($object) === $type->getName())
392+
|| (new \ReflectionClass($type->getName()))->isInstance($object);
393+
}
390394

391395
// If we look for a single match (union), we can return early on match
392396
// 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
@@ -117,6 +117,39 @@ public function shouldAcceptStaticClassCallbackWithIntersectionTypehint()
117117
self::assertTrue(_checkTypehint(['React\Promise\CallbackWithIntersectionTypehintClass', 'testCallbackStatic'], new CountableException()));
118118
}
119119

120+
/**
121+
* @test
122+
* @requires PHP 8.2
123+
*/
124+
public function shouldAcceptInvokableObjectCallbackWithDNFTypehint()
125+
{
126+
self::assertFalse(_checkTypehint(new CallbackWithDNFTypehintClass(), new \RuntimeException()));
127+
self::assertTrue(_checkTypehint(new CallbackWithDNFTypehintClass(), new ArrayAccessibleException()));
128+
self::assertTrue(_checkTypehint(new CallbackWithDNFTypehintClass(), new CountableException()));
129+
}
130+
131+
/**
132+
* @test
133+
* @requires PHP 8.2
134+
*/
135+
public function shouldAcceptObjectMethodCallbackWithDNFTypehint()
136+
{
137+
self::assertFalse(_checkTypehint([new CallbackWithDNFTypehintClass(), 'testCallback'], new \RuntimeException()));
138+
self::assertTrue(_checkTypehint([new CallbackWithDNFTypehintClass(), 'testCallback'], new CountableException()));
139+
self::assertTrue(_checkTypehint([new CallbackWithDNFTypehintClass(), 'testCallback'], new ArrayAccessibleException()));
140+
}
141+
142+
/**
143+
* @test
144+
* @requires PHP 8.2
145+
*/
146+
public function shouldAcceptStaticClassCallbackWithDNFTypehint()
147+
{
148+
self::assertFalse(_checkTypehint(['React\Promise\CallbackWithDNFTypehintClass', 'testCallbackStatic'], new \RuntimeException()));
149+
self::assertTrue(_checkTypehint(['React\Promise\CallbackWithDNFTypehintClass', 'testCallbackStatic'], new CountableException()));
150+
self::assertTrue(_checkTypehint(['React\Promise\CallbackWithDNFTypehintClass', 'testCallbackStatic'], new ArrayAccessibleException()));
151+
}
152+
120153
/** @test */
121154
public function shouldAcceptClosureCallbackWithoutTypehint()
122155
{
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)