From 990eead21f4114c04fa77156eb1f2a9fe4164423 Mon Sep 17 00:00:00 2001 From: cdosoftei Date: Fri, 15 Oct 2021 11:17:16 +0200 Subject: [PATCH 1/3] Adjustments for 7.1, support for union types, test suite updates --- src/functions.php | 42 ++++++++++++++++--- tests/FunctionCheckTypehintTest.php | 62 +++++++++++++++++++++++++++++ 2 files changed, 99 insertions(+), 5 deletions(-) diff --git a/src/functions.php b/src/functions.php index bdbdf52d..68763db3 100644 --- a/src/functions.php +++ b/src/functions.php @@ -341,11 +341,43 @@ function _checkTypehint(callable $callback, $object) return true; } - $expectedException = $parameters[0]; + if (\PHP_VERSION_ID < 70100 || \defined('HHVM_VERSION')) { + $expectedException = $parameters[0]; - if (!$expectedException->getClass()) { - return true; - } + if (!$expectedException->getClass()) { + return true; + } + + return $expectedException->getClass()->isInstance($object); + } else { + $type = $parameters[0]->getType(); - return $expectedException->getClass()->isInstance($object); + if (!$type) { + return true; + } + + $types = [$type]; + + if ($type instanceof \ReflectionUnionType) { + $types = $type->getTypes(); + } + + $mismatched = false; + + foreach ($types as $type) { + if (!$type || $type->isBuiltin()) { + continue; + } + + $expectedClass = $type->getName(); + + if ($object instanceof $expectedClass) { + return true; + } + + $mismatched = true; + } + + return !$mismatched; + } } diff --git a/tests/FunctionCheckTypehintTest.php b/tests/FunctionCheckTypehintTest.php index 8449bc1f..2824c403 100644 --- a/tests/FunctionCheckTypehintTest.php +++ b/tests/FunctionCheckTypehintTest.php @@ -41,6 +41,49 @@ public function shouldAcceptStaticClassCallbackWithTypehint() $this->assertfalse(_checkTypehint(['React\Promise\TestCallbackWithTypehintClass', 'testCallbackStatic'], new \Exception())); } + /** + * @test + * @requires PHP 8 + */ + public function shouldAcceptClosureCallbackWithUnionTypehint() + { + eval( + 'namespace React\Promise;' . + 'self::assertTrue(_checkTypehint(function (\RuntimeException|\InvalidArgumentException $e) {}, new \InvalidArgumentException()));' . + 'self::assertFalse(_checkTypehint(function (\RuntimeException|\InvalidArgumentException $e) {}, new \Exception()));' + ); + } + + /** + * @test + * @requires PHP 8 + */ + public function shouldAcceptInvokableObjectCallbackWithUnionTypehint() + { + self::assertTrue(_checkTypehint(new TestCallbackWithUnionTypehintClass(), new InvalidArgumentException())); + self::assertFalse(_checkTypehint(new TestCallbackWithUnionTypehintClass(), new Exception())); + } + + /** + * @test + * @requires PHP 8 + */ + public function shouldAcceptObjectMethodCallbackWithUnionTypehint() + { + self::assertTrue(_checkTypehint([new TestCallbackWithUnionTypehintClass(), 'testCallback'], new InvalidArgumentException())); + self::assertFalse(_checkTypehint([new TestCallbackWithUnionTypehintClass(), 'testCallback'], new Exception())); + } + + /** + * @test + * @requires PHP 8 + */ + public function shouldAcceptStaticClassCallbackWithUnionTypehint() + { + self::assertTrue(_checkTypehint([TestCallbackWithUnionTypehintClass::class, 'testCallbackStatic'], new InvalidArgumentException())); + self::assertFalse(_checkTypehint([TestCallbackWithUnionTypehintClass::class, 'testCallbackStatic'], new Exception())); + } + /** @test */ public function shouldAcceptClosureCallbackWithoutTypehint() { @@ -99,6 +142,25 @@ public static function testCallbackStatic(\InvalidArgumentException $e) } } +if (defined('PHP_MAJOR_VERSION') && (PHP_MAJOR_VERSION >= 8)) { + eval(<< Date: Fri, 15 Oct 2021 12:14:46 +0200 Subject: [PATCH 2/3] php8: address ReflectionParameter::getClass deprecation --- tests/FunctionCheckTypehintTest.php | 85 ++++--------------- tests/fixtures/CallbackWithTypehintClass.php | 20 +++++ .../CallbackWithUnionTypehintClass.php | 21 +++++ .../fixtures/CallbackWithoutTypehintClass.php | 18 ++++ 4 files changed, 74 insertions(+), 70 deletions(-) create mode 100644 tests/fixtures/CallbackWithTypehintClass.php create mode 100644 tests/fixtures/CallbackWithUnionTypehintClass.php create mode 100644 tests/fixtures/CallbackWithoutTypehintClass.php diff --git a/tests/FunctionCheckTypehintTest.php b/tests/FunctionCheckTypehintTest.php index 2824c403..5c78ab36 100644 --- a/tests/FunctionCheckTypehintTest.php +++ b/tests/FunctionCheckTypehintTest.php @@ -23,22 +23,22 @@ public function shouldAcceptFunctionStringCallbackWithTypehint() /** @test */ public function shouldAcceptInvokableObjectCallbackWithTypehint() { - $this->assertTrue(_checkTypehint(new TestCallbackWithTypehintClass(), new \InvalidArgumentException())); - $this->assertfalse(_checkTypehint(new TestCallbackWithTypehintClass(), new \Exception())); + $this->assertTrue(_checkTypehint(new CallbackWithTypehintClass(), new \InvalidArgumentException())); + $this->assertfalse(_checkTypehint(new CallbackWithTypehintClass(), new \Exception())); } /** @test */ public function shouldAcceptObjectMethodCallbackWithTypehint() { - $this->assertTrue(_checkTypehint([new TestCallbackWithTypehintClass(), 'testCallback'], new \InvalidArgumentException())); - $this->assertfalse(_checkTypehint([new TestCallbackWithTypehintClass(), 'testCallback'], new \Exception())); + $this->assertTrue(_checkTypehint([new CallbackWithTypehintClass(), 'testCallback'], new \InvalidArgumentException())); + $this->assertfalse(_checkTypehint([new CallbackWithTypehintClass(), 'testCallback'], new \Exception())); } /** @test */ public function shouldAcceptStaticClassCallbackWithTypehint() { - $this->assertTrue(_checkTypehint(['React\Promise\TestCallbackWithTypehintClass', 'testCallbackStatic'], new \InvalidArgumentException())); - $this->assertfalse(_checkTypehint(['React\Promise\TestCallbackWithTypehintClass', 'testCallbackStatic'], new \Exception())); + $this->assertTrue(_checkTypehint([new CallbackWithTypehintClass(), 'testCallbackStatic'], new \InvalidArgumentException())); + $this->assertfalse(_checkTypehint([new CallbackWithTypehintClass(), 'testCallbackStatic'], new \Exception())); } /** @@ -60,8 +60,8 @@ public function shouldAcceptClosureCallbackWithUnionTypehint() */ public function shouldAcceptInvokableObjectCallbackWithUnionTypehint() { - self::assertTrue(_checkTypehint(new TestCallbackWithUnionTypehintClass(), new InvalidArgumentException())); - self::assertFalse(_checkTypehint(new TestCallbackWithUnionTypehintClass(), new Exception())); + self::assertTrue(_checkTypehint(new CallbackWithUnionTypehintClass(), new \InvalidArgumentException())); + self::assertFalse(_checkTypehint(new CallbackWithUnionTypehintClass(), new \Exception())); } /** @@ -70,8 +70,8 @@ public function shouldAcceptInvokableObjectCallbackWithUnionTypehint() */ public function shouldAcceptObjectMethodCallbackWithUnionTypehint() { - self::assertTrue(_checkTypehint([new TestCallbackWithUnionTypehintClass(), 'testCallback'], new InvalidArgumentException())); - self::assertFalse(_checkTypehint([new TestCallbackWithUnionTypehintClass(), 'testCallback'], new Exception())); + self::assertTrue(_checkTypehint([new CallbackWithUnionTypehintClass(), 'testCallback'], new \InvalidArgumentException())); + self::assertFalse(_checkTypehint([new CallbackWithUnionTypehintClass(), 'testCallback'], new \Exception())); } /** @@ -80,8 +80,8 @@ public function shouldAcceptObjectMethodCallbackWithUnionTypehint() */ public function shouldAcceptStaticClassCallbackWithUnionTypehint() { - self::assertTrue(_checkTypehint([TestCallbackWithUnionTypehintClass::class, 'testCallbackStatic'], new InvalidArgumentException())); - self::assertFalse(_checkTypehint([TestCallbackWithUnionTypehintClass::class, 'testCallbackStatic'], new Exception())); + self::assertTrue(_checkTypehint(['React\Promise\CallbackWithUnionTypehintClass', 'testCallbackStatic'], new \InvalidArgumentException())); + self::assertFalse(_checkTypehint(['React\Promise\CallbackWithUnionTypehintClass', 'testCallbackStatic'], new \Exception())); } /** @test */ @@ -100,19 +100,19 @@ public function shouldAcceptFunctionStringCallbackWithoutTypehint() /** @test */ public function shouldAcceptInvokableObjectCallbackWithoutTypehint() { - $this->assertTrue(_checkTypehint(new TestCallbackWithoutTypehintClass(), new \InvalidArgumentException())); + $this->assertTrue(_checkTypehint(new CallbackWithoutTypehintClass(), new \InvalidArgumentException())); } /** @test */ public function shouldAcceptObjectMethodCallbackWithoutTypehint() { - $this->assertTrue(_checkTypehint([new TestCallbackWithoutTypehintClass(), 'testCallback'], new \InvalidArgumentException())); + $this->assertTrue(_checkTypehint([new CallbackWithoutTypehintClass(), 'testCallback'], new \InvalidArgumentException())); } /** @test */ public function shouldAcceptStaticClassCallbackWithoutTypehint() { - $this->assertTrue(_checkTypehint(['React\Promise\TestCallbackWithoutTypehintClass', 'testCallbackStatic'], new \InvalidArgumentException())); + $this->assertTrue(_checkTypehint(['React\Promise\CallbackWithoutTypehintClass', 'testCallbackStatic'], new \InvalidArgumentException())); } } @@ -123,58 +123,3 @@ function testCallbackWithTypehint(\InvalidArgumentException $e) function testCallbackWithoutTypehint() { } - -class TestCallbackWithTypehintClass -{ - public function __invoke(\InvalidArgumentException $e) - { - - } - - public function testCallback(\InvalidArgumentException $e) - { - - } - - public static function testCallbackStatic(\InvalidArgumentException $e) - { - - } -} - -if (defined('PHP_MAJOR_VERSION') && (PHP_MAJOR_VERSION >= 8)) { - eval(<< Date: Fri, 15 Oct 2021 12:15:21 +0200 Subject: [PATCH 3/3] Run tests on PHP 8 --- .github/workflows/ci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 57422de5..a13804b5 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -11,6 +11,7 @@ jobs: strategy: matrix: php: + - 8.0 - 7.4 - 7.3 - 7.2