From fad3b5404dcdf4083698283f3d276efb058884a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9C=D0=B0=D0=BA=D1=81=D0=B8=D0=BC=20=D0=A1=D0=BF=D0=B8?= =?UTF-8?q?=D1=80=D0=BA=D0=BE=D0=B2?= Date: Mon, 1 Dec 2025 12:34:09 +0400 Subject: [PATCH 1/4] Improve the conversion of `Callable` to a string --- src/Types/CallableParameter.php | 12 +++++++ src/Types/Callable_.php | 14 +++++++- tests/unit/TypeResolverTest.php | 28 +++++++++++++++ tests/unit/Types/CallableTest.php | 59 +++++++++++++++++++++++++++++++ 4 files changed, 112 insertions(+), 1 deletion(-) diff --git a/src/Types/CallableParameter.php b/src/Types/CallableParameter.php index 51c550b6..8b531981 100644 --- a/src/Types/CallableParameter.php +++ b/src/Types/CallableParameter.php @@ -14,6 +14,8 @@ use phpDocumentor\Reflection\Type; +use function trim; + /** * Value Object representing a Callable parameters. * @@ -74,4 +76,14 @@ public function isOptional(): bool { return $this->isOptional; } + + public function __toString(): string + { + $reference = $this->isReference ? '&' : ''; + $variadic = $this->isVariadic ? '...' : ''; + $optional = $this->isOptional ? '=' : ''; + $name = $this->name !== null ? '$' . $this->name : ''; + + return trim($this->type . ' ' . $reference . $variadic . $name . $optional); + } } diff --git a/src/Types/Callable_.php b/src/Types/Callable_.php index e9b9b232..f06325ba 100644 --- a/src/Types/Callable_.php +++ b/src/Types/Callable_.php @@ -15,6 +15,8 @@ use phpDocumentor\Reflection\Type; +use function implode; + /** * Value Object representing a Callable type. * @@ -63,6 +65,16 @@ public function getReturnType(): ?Type */ public function __toString(): string { - return $this->identifier; + if (!$this->parameters && $this->returnType === null) { + return $this->identifier; + } + + if ($this->returnType instanceof self) { + $returnType = '(' . (string) $this->returnType . ')'; + } else { + $returnType = (string) $this->returnType; + } + + return $this->identifier . '(' . implode(', ', $this->parameters) . '): ' . $returnType; } } diff --git a/tests/unit/TypeResolverTest.php b/tests/unit/TypeResolverTest.php index 4de0d433..61ce547b 100644 --- a/tests/unit/TypeResolverTest.php +++ b/tests/unit/TypeResolverTest.php @@ -1192,6 +1192,34 @@ public function callableProvider(): array new Object_(new Fqsen('\\phpDocumentor\\Foo')) ), ], + [ + 'Closure(mixed): (callable(mixed): mixed)', + new Callable_( + 'Closure', + [ + new CallableParameter( + new Mixed_(), + null, + false, + false, + false + ), + ], + new Callable_( + 'callable', + [ + new CallableParameter( + new Mixed_(), + null, + false, + false, + false + ), + ], + new Mixed_() + ) + ), + ], ]; } diff --git a/tests/unit/Types/CallableTest.php b/tests/unit/Types/CallableTest.php index e9da6755..6eca2387 100644 --- a/tests/unit/Types/CallableTest.php +++ b/tests/unit/Types/CallableTest.php @@ -76,6 +76,65 @@ public static function provideToStringData(): array '\Closure', new Callable_('\Closure'), ], + 'with different types' => [ + 'callable(\\phpDocumentor\\C, \\phpDocumentor\\A &...$a=, \\phpDocumentor\\B &...=): ' + . '\\phpDocumentor\\Foo', + new Callable_( + 'callable', + [ + new CallableParameter( + new Object_(new Fqsen('\\phpDocumentor\\C')), + null, + false, + false, + false + ), + new CallableParameter( + new Object_(new Fqsen('\\phpDocumentor\\A')), + 'a', + true, + true, + true + ), + new CallableParameter( + new Object_(new Fqsen('\\phpDocumentor\\B')), + null, + true, + true, + true + ), + ], + new Object_(new Fqsen('\\phpDocumentor\\Foo')) + ), + ], + 'return callable' => [ + 'Closure(mixed): (callable(mixed): mixed)', + new Callable_( + 'Closure', + [ + new CallableParameter( + new Mixed_(), + null, + false, + false, + false + ), + ], + new Callable_( + 'callable', + [ + new CallableParameter( + new Mixed_(), + null, + false, + false, + false + ), + ], + new Mixed_() + ) + ), + ], ]; } } From 157f069d46cd23d1c09c208df9ac506b8b800fdd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9C=D0=B0=D0=BA=D1=81=D0=B8=D0=BC=20=D0=A1=D0=BF=D0=B8?= =?UTF-8?q?=D1=80=D0=BA=D0=BE=D0=B2?= Date: Mon, 1 Dec 2025 12:36:34 +0400 Subject: [PATCH 2/4] Fix CS --- src/Types/CallableParameter.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Types/CallableParameter.php b/src/Types/CallableParameter.php index 8b531981..84a6a7b8 100644 --- a/src/Types/CallableParameter.php +++ b/src/Types/CallableParameter.php @@ -78,12 +78,12 @@ public function isOptional(): bool } public function __toString(): string - { - $reference = $this->isReference ? '&' : ''; - $variadic = $this->isVariadic ? '...' : ''; - $optional = $this->isOptional ? '=' : ''; + { + $reference = $this->isReference ? '&' : ''; + $variadic = $this->isVariadic ? '...' : ''; + $optional = $this->isOptional ? '=' : ''; $name = $this->name !== null ? '$' . $this->name : ''; - return trim($this->type . ' ' . $reference . $variadic . $name . $optional); - } + return trim($this->type . ' ' . $reference . $variadic . $name . $optional); + } } From dfed23fc5e786b4633303ba2a272dd1b536efb52 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9C=D0=B0=D0=BA=D1=81=D0=B8=D0=BC=20=D0=A1=D0=BF=D0=B8?= =?UTF-8?q?=D1=80=D0=BA=D0=BE=D0=B2?= Date: Mon, 1 Dec 2025 13:51:20 +0400 Subject: [PATCH 3/4] Refactor `CallableParameter` --- src/Types/CallableParameter.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Types/CallableParameter.php b/src/Types/CallableParameter.php index 84a6a7b8..a53ecf54 100644 --- a/src/Types/CallableParameter.php +++ b/src/Types/CallableParameter.php @@ -21,7 +21,7 @@ * * @psalm-immutable */ -final class CallableParameter +final class CallableParameter implements Type { /** @var Type */ private $type; From 0e6fc6c07a73d046526f9d5765938056f54bf1cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9C=D0=B0=D0=BA=D1=81=D0=B8=D0=BC=20=D0=A1=D0=BF=D0=B8?= =?UTF-8?q?=D1=80=D0=BA=D0=BE=D0=B2?= Date: Tue, 2 Dec 2025 23:08:37 +0400 Subject: [PATCH 4/4] Revert "Refactor `CallableParameter`" This reverts commit dfed23fc5e786b4633303ba2a272dd1b536efb52. --- src/Types/CallableParameter.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Types/CallableParameter.php b/src/Types/CallableParameter.php index a53ecf54..84a6a7b8 100644 --- a/src/Types/CallableParameter.php +++ b/src/Types/CallableParameter.php @@ -21,7 +21,7 @@ * * @psalm-immutable */ -final class CallableParameter implements Type +final class CallableParameter { /** @var Type */ private $type;