-
-
Notifications
You must be signed in to change notification settings - Fork 74
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: add support for PHP 8.4 #567
Conversation
@@ -83,7 +85,8 @@ public function for(callable $function): FunctionDefinition | |||
*/ | |||
private function signature(ReflectionFunction $reflection): string | |||
{ | |||
if (str_contains($reflection->name, '{closure}')) { | |||
// PHP8.4 Only `str_starts_with($name, '{closure:')` is needed |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
With 8.2 you can just use ReflectionFunction::isAnonymous()
.
I guess you don't feel comfortable to release a version without Psalm CI on your side, so you have a proof. |
4e448d5
to
0038849
Compare
Hi @TimWolla sorry to poke you here, but as you fixed the It seems that even with the latest PHP 8.4-RC, we're still having an issue with \CuyZ\Valinor\Tests\Integration\Mapping\Namespace\NamespacedInterfaceInferringTest::test_interface_inferred_from_same_namespace_as_file_runs_correctly ; the issue lies in \CuyZ\Valinor\Type\Parser\Factory\Specifications\AliasSpecification::resolveNamespaced(): the closure is namespaced but the method still returns Any idea what is wrong here? Thanks! |
@romm Closures are never considered namespaced with PHP 8.4+. Generally speaking you can't really rely on a specific closure naming, because Closures are anonymous and thus you would be relying on an implementation detail. From how the PHP code looked like, even the namespacing of Closures prior to 8.4 was an accident (they are just named |
@TimWolla thanks for your answer. The usecase here is to get the namespace of a closure so that short class names in docblock can be transformed to FQCN. For instance: namespace SimpleNamespace;
use CuyZ\Valinor\MapperBuilder;
interface SomeInterface {}
final class ImplementationOne implements SomeInterface {}
final class ImplementationTwo implements SomeInterface {}
return (new MapperBuilder())
->infer(
SomeInterface::class,
/** @return class-string<ImplementationOne|ImplementationTwo> */
static fn (string $type): string => match ($type) {
'one' => ImplementationOne::class,
'two' => ImplementationTwo::class,
default => throw new \RuntimeException(),
},
)
->mapper()
->map(
SomeInterface::class,
['type' => 'one'],
); The annotation It seems strange to me that closures cannot be namespaced, is there any chance the old behavior could be reverted and tested? If not, would you have a suggestion on how to get this information? Using |
Namespaces are not a first class citizen in PHP. It's really just compiler assisted automated prefixing of any names. The
Unfortunately not for PHP 8.4, it's much too late in the release cycle.
The effect on docblock parsing is an unfortunate side-effect of the improved closure naming that I did not anticipate when initially implementing it.
For any closure that is not a top-level closure you can strip the |
Thank you @TimWolla for the details. Tokenization was not that hard, and all this stuff gets cached anyway (if the cache is used), so that's not a big deal. |
@romm FWIW: The tokenization solution is not quite correct in all cases, because the following is legal PHP code:
|
if (! $reflection->inNamespace()) { | ||
if ($reflection->inNamespace()) { | ||
$namespace = $reflection->getNamespaceName(); | ||
} elseif ($reflection instanceof ReflectionFunction) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You could guard this against closures to not unnecessarily tokenize the file for top-level functions in non-namespaced code.
References: