From 689b41c555160d894b5e323ba8dcf8c80f29b3a0 Mon Sep 17 00:00:00 2001 From: Martin Seitz Date: Tue, 14 Apr 2026 13:19:39 +0200 Subject: [PATCH 1/3] Add tests for NotCallableException::fromInvalidCallable() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Tests for circular references * Tests for `[…, null]` values --- tests/Exception/NotCallableExceptionTest.php | 65 ++++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100644 tests/Exception/NotCallableExceptionTest.php diff --git a/tests/Exception/NotCallableExceptionTest.php b/tests/Exception/NotCallableExceptionTest.php new file mode 100644 index 0000000..b266a25 --- /dev/null +++ b/tests/Exception/NotCallableExceptionTest.php @@ -0,0 +1,65 @@ +self = $obj; + + $exception = NotCallableException::fromInvalidCallable($obj); + + $this->assertSame('Instance of stdClass is not a callable', $exception->getMessage()); + } + + /** + * @test + */ + #[\PHPUnit\Framework\Attributes\Test] + public function handles_array_with_object_and_null_method() + { + $obj = new stdClass(); + + $exception = NotCallableException::fromInvalidCallable([$obj, null]); + + $this->assertSame('stdClass::() is not a callable.', $exception->getMessage()); + } + + /** + * @test + */ + #[\PHPUnit\Framework\Attributes\Test] + public function handles_circular_array_reference() + { + $a = []; + $a[] = &$a; + + $exception = NotCallableException::fromInvalidCallable($a); + + $this->assertStringContainsString('is not a callable', $exception->getMessage()); + } + + /** + * @test + */ + #[\PHPUnit\Framework\Attributes\Test] + public function handles_circular_array_reference_as_container_entry() + { + $a = []; + $a[] = &$a; + + $exception = NotCallableException::fromInvalidCallable($a, true); + + $this->assertStringContainsString('is neither a callable nor a valid container entry', $exception->getMessage()); + } +} From aa10350c0d10bea5228cb8940c5e9c18954480db Mon Sep 17 00:00:00 2001 From: Martin Seitz Date: Tue, 14 Apr 2026 13:20:46 +0200 Subject: [PATCH 2/3] Fix second value entry being null If the second value entry is null, we should still print the object error message. `isset()` doesn't match it though. --- src/Exception/NotCallableException.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Exception/NotCallableException.php b/src/Exception/NotCallableException.php index 7f6cb3c..a3389cb 100644 --- a/src/Exception/NotCallableException.php +++ b/src/Exception/NotCallableException.php @@ -14,7 +14,7 @@ public static function fromInvalidCallable($value, bool $containerEntry = false) { if (is_object($value)) { $message = sprintf('Instance of %s is not a callable', get_class($value)); - } elseif (is_array($value) && isset($value[0], $value[1])) { + } elseif (is_array($value) && array_key_exists(0, $value) && array_key_exists(1, $value)) { $class = is_object($value[0]) ? get_class($value[0]) : $value[0]; $extra = method_exists($class, '__call') || method_exists($class, '__callStatic') From e19ace320e109a5eecdd2b93be534173ee6f6a66 Mon Sep 17 00:00:00 2001 From: Martin Seitz Date: Tue, 14 Apr 2026 13:21:26 +0200 Subject: [PATCH 3/3] Use print_r() instead of var_export() print_r() handles circular references nicely, but var_export() emits a warning. --- src/Exception/NotCallableException.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Exception/NotCallableException.php b/src/Exception/NotCallableException.php index a3389cb..ae09e84 100644 --- a/src/Exception/NotCallableException.php +++ b/src/Exception/NotCallableException.php @@ -23,9 +23,9 @@ public static function fromInvalidCallable($value, bool $containerEntry = false) $message = sprintf('%s::%s() is not a callable.%s', $class, $value[1], $extra); } elseif ($containerEntry) { - $message = var_export($value, true) . ' is neither a callable nor a valid container entry'; + $message = print_r($value, true) . ' is neither a callable nor a valid container entry'; } else { - $message = var_export($value, true) . ' is not a callable'; + $message = print_r($value, true) . ' is not a callable'; } return new self($message);