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
How to properly annotate @param class-string<T>|null
as fallback to object
?
#6638
Comments
I found these snippets: https://psalm.dev/r/bea75ab401<?php
abstract class C {
/**
* @template T as object
*
* @param class-string<T>|null $class
*
* @return T
*/
abstract public function createInstance(string $class = NULL);
/**
* @template T as object
*
* @param class-string<T>|null $class
*
* @return T[]
*/
abstract public function createInstances(string $class = NULL): array;
public function f(): void {
$single = $this->createInstance(); // No MixedAssignment warning.
unset($single);
foreach ($this->createInstances() as $item) { // MixedAssignment on 'as $item'.
unset($item);
}
}
}
|
I could do I could make the param default to Adding or removing the |
The current behavior kind of makes sense, because |
Do you need something like this: https://psalm.dev/r/d7599687dc (https://psalm.dev/docs/annotating_code/type_syntax/conditional_types/)? |
I found these snippets: https://psalm.dev/r/d7599687dc<?php
abstract class C {
/**
* @template T as object
*
* @param class-string<T>|null $class
*
* @return ($class is null ? object[] : T[])
*/
abstract public function createInstances(string $class = NULL): array;
public function f(): void {
foreach ($this->createInstances() as $item) { // MixedAssignment on 'as $item'.
unset($item);
}
}
}
|
Nice! Yes, exactly this. |
I don't think it does (I wasn't able to find a corresponding ticket on youtrack), neither does PHPStan (see phpstan/phpstan#3853). With that said, it's up to those tools to catch up. |
@weirdan I noticed that even the built-in stubs in psalm don't follow this syntax. In ReflectionMethod: * @since 8.0
* @template TClass as object
* @param class-string<TClass>|null $name
- * @return array<ReflectionAttribute<TClass>>
+ * @return array<ReflectionAttribute<$name is null ? object : TClass>>
*/
public function getAttributes(?string $name = null, int $flags = 0): array {} I think it would be simpler to just treat the |
Please read https://psalm.dev/docs/annotating_code/type_syntax/conditional_types/ again, your syntax is not valid |
@orklah I noticed one mistake: I swapped Otherwise, my code is based on the comment by @weirdan. The docs suggest that I can only use template types in the condition, not parameter names. The docs also say I need to use parentheses around the ternary expression. But it works fine without. Seems more like a case of incomplete docs. Or perhaps I am relying on undocumented features that might be removed in a future version? |
I found these snippets: https://psalm.dev/r/7b0ec389fa<?php
interface I {
/**
* Returns an array of constant attributes.
*
* @template T as object
*
* @param class-string<T>|null $name
* Name of an attribute class.
*
* @return list<\ReflectionAttribute<T>>
* @psalm-return list<\ReflectionAttribute<$name is null ? object : T>>
*
* @noinspection PhpUndefinedClassInspection
*/
public function getAttributes(string $name = null): array;
}
interface J {
function f(): void;
}
function f(I $obj): void {
foreach ($obj->getAttributes(J::class) as $attr) {
$attr->newInstance()->f();
}
}
|
Yeah, I was referring to the parentheses at least because I thought conditional inside the generic type was not working either. Turns out it does. I'm quite surprised, I never saw that before. I think you found some feature that was maybe not meant to work. I think it'd be safer to use something like |
@orklah The docs suggest that some kind of nesting is supported..
Perhaps create test cases for this and then make sure it continues to work? |
Psalm is very complicated and its author is not there anymore to maintain it. I won't do anything to break it, but if it's just a different syntax to express the same thing, I'm not sure it's a good idea to add constraints like that. Especially so if it was not by design |
I have a function/method with an optional
@param class-string<T>|null $class
parameter.The function should return
T
orT[]
if $class is provided, orobject
if $class is NULL.https://psalm.dev/r/bea75ab401
The MixedAssignment only happens in foreach() from
@return T[]
, not on the single-value case.However, in both cases the return value is resolved as
empty
instead ofobject
.(heads up: I might get my hands dirty with development at some point, but I need to make time for it. For now I am simply reporting what I find)
The text was updated successfully, but these errors were encountered: