From b2a89487f1eb434b0e6fcea07003d6796a28638e Mon Sep 17 00:00:00 2001 From: cdosoftei Date: Wed, 12 Aug 2020 23:56:00 -0400 Subject: [PATCH 1/3] Adjustments for 7.1, support for union types, test suite updates --- src/functions.php | 28 ++++++++++-- tests/ErrorCollector.php | 4 +- tests/FunctionCheckTypehintTest.php | 66 ++++++++++++++++++++++++++++- 3 files changed, 92 insertions(+), 6 deletions(-) diff --git a/src/functions.php b/src/functions.php index 31e7db7b..df50eb33 100644 --- a/src/functions.php +++ b/src/functions.php @@ -342,11 +342,33 @@ function _checkTypehint(callable $callback, \Throwable $reason): bool return true; } - $expectedClass = $parameters[0]->getClass(); + $type = $parameters[0]->getType(); - if (!$expectedClass) { + if (!$type) { return true; } - return $expectedClass->isInstance($reason); + $types = [$type]; + + if ($type instanceof \ReflectionUnionType) { + $types = $type->getTypes(); + } + + $mismatched = false; + + foreach ($types as $type) { + if (!$type || $type->isBuiltin()) { + continue; + } + + $expectedClass = $type->getName(); + + if ($reason instanceof $expectedClass) { + return true; + } + + $mismatched = true; + } + + return !$mismatched; } diff --git a/tests/ErrorCollector.php b/tests/ErrorCollector.php index 970f8628..0ad3fffd 100644 --- a/tests/ErrorCollector.php +++ b/tests/ErrorCollector.php @@ -10,8 +10,8 @@ public function start() { $errors = []; - set_error_handler(function ($errno, $errstr, $errfile, $errline, $errcontext) use (&$errors) { - $errors[] = compact('errno', 'errstr', 'errfile', 'errline', 'errcontext'); + set_error_handler(function ($errno, $errstr, $errfile, $errline) use (&$errors) { + $errors[] = compact('errno', 'errstr', 'errfile', 'errline'); }); $this->errors = &$errors; diff --git a/tests/FunctionCheckTypehintTest.php b/tests/FunctionCheckTypehintTest.php index bebda2c7..171c9b71 100644 --- a/tests/FunctionCheckTypehintTest.php +++ b/tests/FunctionCheckTypehintTest.php @@ -42,6 +42,49 @@ public function shouldAcceptStaticClassCallbackWithTypehint() self::assertFalse(_checkTypehint([TestCallbackWithTypehintClass::class, '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() { @@ -52,7 +95,7 @@ public function shouldAcceptClosureCallbackWithoutTypehint() /** @test */ public function shouldAcceptFunctionStringCallbackWithoutTypehint() { - self::assertTrue(_checkTypehint(new TestCallbackWithTypehintClass(), new InvalidArgumentException())); + self::assertTrue(_checkTypehint(new TestCallbackWithoutTypehintClass(), new InvalidArgumentException())); } /** @test */ @@ -97,6 +140,27 @@ public static function testCallbackStatic(InvalidArgumentException $e) } } +if (defined('PHP_MAJOR_VERSION') && (PHP_MAJOR_VERSION >= 8)) { + eval(<< Date: Tue, 11 Aug 2020 15:27:22 -0400 Subject: [PATCH 2/3] php8: address ReflectionParameter::getClass deprecation --- tests/FunctionCheckTypehintTest.php | 89 ++++--------------- tests/fixtures/CallbackWithTypehintClass.php | 20 +++++ .../CallbackWithUnionTypehintClass.php | 21 +++++ .../fixtures/CallbackWithoutTypehintClass.php | 18 ++++ 4 files changed, 78 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 171c9b71..b6f8aef5 100644 --- a/tests/FunctionCheckTypehintTest.php +++ b/tests/FunctionCheckTypehintTest.php @@ -17,29 +17,29 @@ public function shouldAcceptClosureCallbackWithTypehint() /** @test */ public function shouldAcceptFunctionStringCallbackWithTypehint() { - self::assertTrue(_checkTypehint(new TestCallbackWithTypehintClass(), new InvalidArgumentException())); - self::assertFalse(_checkTypehint(new TestCallbackWithTypehintClass(), new Exception())); + self::assertTrue(_checkTypehint(new CallbackWithTypehintClass(), new InvalidArgumentException())); + self::assertFalse(_checkTypehint(new CallbackWithTypehintClass(), new Exception())); } /** @test */ public function shouldAcceptInvokableObjectCallbackWithTypehint() { - self::assertTrue(_checkTypehint(new TestCallbackWithTypehintClass(), new InvalidArgumentException())); - self::assertFalse(_checkTypehint(new TestCallbackWithTypehintClass(), new Exception())); + self::assertTrue(_checkTypehint(new CallbackWithTypehintClass(), new InvalidArgumentException())); + self::assertFalse(_checkTypehint(new CallbackWithTypehintClass(), new Exception())); } /** @test */ public function shouldAcceptObjectMethodCallbackWithTypehint() { - self::assertTrue(_checkTypehint([new TestCallbackWithTypehintClass(), 'testCallback'], new InvalidArgumentException())); - self::assertFalse(_checkTypehint([new TestCallbackWithTypehintClass(), 'testCallback'], new Exception())); + self::assertTrue(_checkTypehint([new CallbackWithTypehintClass(), 'testCallback'], new InvalidArgumentException())); + self::assertFalse(_checkTypehint([new CallbackWithTypehintClass(), 'testCallback'], new Exception())); } /** @test */ public function shouldAcceptStaticClassCallbackWithTypehint() { - self::assertTrue(_checkTypehint([TestCallbackWithTypehintClass::class, 'testCallbackStatic'], new InvalidArgumentException())); - self::assertFalse(_checkTypehint([TestCallbackWithTypehintClass::class, 'testCallbackStatic'], new Exception())); + self::assertTrue(_checkTypehint([CallbackWithTypehintClass::class, 'testCallbackStatic'], new InvalidArgumentException())); + self::assertFalse(_checkTypehint([CallbackWithTypehintClass::class, 'testCallbackStatic'], new Exception())); } /** @@ -61,8 +61,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())); } /** @@ -71,8 +71,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())); } /** @@ -81,11 +81,11 @@ 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([CallbackWithUnionTypehintClass::class, 'testCallbackStatic'], new InvalidArgumentException())); + self::assertFalse(_checkTypehint([CallbackWithUnionTypehintClass::class, 'testCallbackStatic'], new Exception())); } - /** @test */ +/** @test */ public function shouldAcceptClosureCallbackWithoutTypehint() { self::assertTrue(_checkTypehint(function (InvalidArgumentException $e) { @@ -95,25 +95,25 @@ public function shouldAcceptClosureCallbackWithoutTypehint() /** @test */ public function shouldAcceptFunctionStringCallbackWithoutTypehint() { - self::assertTrue(_checkTypehint(new TestCallbackWithoutTypehintClass(), new InvalidArgumentException())); + self::assertTrue(_checkTypehint(new CallbackWithoutTypehintClass(), new InvalidArgumentException())); } /** @test */ public function shouldAcceptInvokableObjectCallbackWithoutTypehint() { - self::assertTrue(_checkTypehint(new TestCallbackWithoutTypehintClass(), new InvalidArgumentException())); + self::assertTrue(_checkTypehint(new CallbackWithoutTypehintClass(), new InvalidArgumentException())); } /** @test */ public function shouldAcceptObjectMethodCallbackWithoutTypehint() { - self::assertTrue(_checkTypehint([new TestCallbackWithoutTypehintClass(), 'testCallback'], new InvalidArgumentException())); + self::assertTrue(_checkTypehint([new CallbackWithoutTypehintClass(), 'testCallback'], new InvalidArgumentException())); } /** @test */ public function shouldAcceptStaticClassCallbackWithoutTypehint() { - self::assertTrue(_checkTypehint([TestCallbackWithoutTypehintClass::class, 'testCallbackStatic'], new InvalidArgumentException())); + self::assertTrue(_checkTypehint([CallbackWithoutTypehintClass::class, 'testCallbackStatic'], new InvalidArgumentException())); } } @@ -124,54 +124,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: Thu, 7 Oct 2021 13:01:30 +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 2bf63e6c..a96e911e 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