-
Notifications
You must be signed in to change notification settings - Fork 664
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
Support question: how to use conditional return types on a complicated DBAL case #3277
Comments
Hey @greg0ire, can you reproduce the issue on https://psalm.dev ? |
Here you go: https://psalm.dev/r/f1d18ed5c2 |
I found these snippets: https://psalm.dev/r/f1d18ed5c2<?php
class Connection
{
}
class SpecificConnection extends Connection
{
public function foo(): void
{
}
}
class DriverManager
{
/**
* @param array{wrapperClass?: class-string<T>} $params The parameters.
*
* @return T|Connection
*
* @template T of Connection
*/
public static function getConnection(
array $params
) : Connection {
// lots and lots of code
$wrapperClass = Connection::class;
if (isset($params['wrapperClass'])) {
if (! is_subclass_of($params['wrapperClass'], $wrapperClass)) {
throw new \Exception();
}
$wrapperClass = $params['wrapperClass'];
}
return new $wrapperClass();
}
}
DriverManager::getConnection(['wrapperClass' => SpecificConnection::class])->foo();
|
This should work: https://psalm.dev/r/98267e7f6b |
I found these snippets: https://psalm.dev/r/98267e7f6b<?php
class Connection {}
class SpecificConnection extends Connection {
public function foo(): void {}
}
class DriverManager {
/**
* @template T of Connection
* @template TArray of array{wrapperClass?: class-string<T>}
* @param TArray $params
*
* @return (TArray is array{wrapperClass:mixed} ? T : Connection)
*/
public static function getConnection(array $params) {
// lots and lots of code
$wrapperClass = Connection::class;
if (isset($params['wrapperClass'])) {
if (! is_subclass_of($params['wrapperClass'], $wrapperClass)) {
throw new \Exception();
}
$wrapperClass = $params['wrapperClass'];
}
return new $wrapperClass();
}
}
DriverManager::getConnection(['wrapperClass' => SpecificConnection::class])->foo();
|
It does not work for me, I have the same warnings as on psalm.dev:
EDIT: I realise that might have been what you wanted to say since you added the "bug" label 😅 |
I found these snippets: https://psalm.dev/r/98267e7f6b<?php
class Connection {}
class SpecificConnection extends Connection {
public function foo(): void {}
}
class DriverManager {
/**
* @template T of Connection
* @template TArray of array{wrapperClass?: class-string<T>}
* @param TArray $params
*
* @return (TArray is array{wrapperClass:mixed} ? T : Connection)
*/
public static function getConnection(array $params) {
// lots and lots of code
$wrapperClass = Connection::class;
if (isset($params['wrapperClass'])) {
if (! is_subclass_of($params['wrapperClass'], $wrapperClass)) {
throw new \Exception();
}
$wrapperClass = $params['wrapperClass'];
}
return new $wrapperClass();
}
}
DriverManager::getConnection(['wrapperClass' => SpecificConnection::class])->foo();
|
Yup! |
This works now! |
This return type is conditional to $params['wrapperClass']. Luckily, recent versions of Psalm allow documenting it properly. See vimeo/psalm#3277 Note that phpstan is not able to understand this yet, but still attempts to, hence the extra ignore rules.
This return type is conditional to $params['wrapperClass']. Luckily, recent versions of Psalm allow documenting it properly. See vimeo/psalm#3277 Note that phpstan is not able to understand this yet, but still attempts to, hence the extra ignore rules.
This return type is conditional to $params['wrapperClass']. Luckily, recent versions of Psalm allow documenting it properly. See vimeo/psalm#3277 Note that phpstan is not able to understand this yet, but still attempts to, hence the extra ignore rules.
This return type is conditional to $params['wrapperClass']. Luckily, recent versions of Psalm allow documenting it properly. See vimeo/psalm#3277 Note that phpstan is not able to understand this yet, but still attempts to, hence the extra ignore rules.
This return type is conditional to $params['wrapperClass']. Luckily, recent versions of Psalm allow documenting it properly. See vimeo/psalm#3277 Note that phpstan is not able to understand this yet, but still attempts to, hence the extra ignore rules.
This return type is conditional to $params['wrapperClass']. Luckily, recent versions of Psalm allow documenting it properly. See vimeo/psalm#3277 Note that phpstan is not able to understand this yet, but still attempts to, hence the extra ignore rules.
This return type is conditional to $params['wrapperClass']. Luckily, recent versions of Psalm allow documenting it properly. See vimeo/psalm#3277 Note that phpstan is not able to understand this yet, but still attempts to, hence the extra ignore rules.
This return type is conditional to $params['wrapperClass']. Luckily, recent versions of Psalm allow documenting it properly. See vimeo/psalm#3277 Note that phpstan is not able to understand this yet, but still attempts to, hence the extra ignore rules.
This return type is conditional to $params['wrapperClass']. Luckily, recent versions of Psalm allow documenting it properly. See vimeo/psalm#3277 Note that phpstan is not able to understand this yet, but still attempts to, hence the extra ignore rules.
This return type is conditional to $params['wrapperClass']. Luckily, recent versions of Psalm allow documenting it properly. See vimeo/psalm#3277 Note that phpstan is not able to understand this yet, but still attempts to, hence the extra ignore rules.
This return type is conditional to $params['wrapperClass']. Luckily, recent versions of Psalm allow documenting it properly. See vimeo/psalm#3277 Note that phpstan is not able to understand this yet, but still attempts to, hence the extra ignore rules.
This return type is conditional to $params['wrapperClass']. Luckily, recent versions of Psalm allow documenting it properly. See vimeo/psalm#3277 Note that phpstan is not able to understand this yet, but still attempts to, hence the extra ignore rules.
I want to make SA tools (namely PHPStan, and of course Psalm) understand this method: https://github.com/doctrine/dbal/blob/6c789b30a46906c5e669158809076d2405ea4fa9/lib/Doctrine/DBAL/DriverManager.php#L124
It reads like this:
At first, I tried using templates, like this:
but PHPStan rightfully pointed out that the output type is not necessarily T (even if it's a T of Connection).
So I made this change:
Phpstan was happy, but I think it defeats the whole purpose, because this is just as good as
@return T
isn't it. I got the same errors I had at the beginning from Psalm, about methods from a subtype of connection that I can't be sure will be there.How do I make Psalm understand that
T
will be returned iffwrapperClass
is not null, and thatConnection
will be returned otherwise?The text was updated successfully, but these errors were encountered: