PHP静态分析:根据参数值定义从对象模板返回的方法

问题描述 投票:0回答:1

这可能很难描述,这就是为什么我正在努力寻找匹配的答案。

<?php
declare(strict_types=1);

/**
 * @template T of object{'a': string, 'b': int, 'c': DateTime}
 */
class Foo {
    /**
     * @var object<T>
     */
    private object $foo;

    // Assume __construct populates the $foo property

    /**
     * @param key-of<T> doesn't seem to apply here - only applies
     *                  to catching keys that aren't in T
     *
     * @return ??? indicate $key is a property of T, so return is that property's type
     */
    public function get(string $key)
    {
        return $this->foo->{$a};
    }
}

function string_only(string $a): string { return $a; }
function integer_only(int $b): int { return $b; }

// How do I know what was returned?
$a = (new Foo)->get('a');
// $a should be treated as string by code analysis
string_only($a);  // OK
integer_only($a); // Inspection type warning

$b = (new Foo)->get('b');
// $b should be treated as int by code analysis
string_only($b);  // Inspection type warning
integer_only($b); // OK

$c = (new Foo)->get('c');
// Code completion should know I can do this
$c->format('Ymd');

PhpStorm各种尝试的检查结果:

// @return T<$key>
// @return T{$key}
string_only($a); // "Return value must be of type 'string', 'object' returned"

// @return T->$key
string_only($a); // "Return value must be of type 'string', 'T-' returned"

各种其他尝试不被识别为任何东西或给出类似于上面的内容。

可以使用任何当前的 PHP SA 工具来完成此操作吗?


我在

@return
注释中尝试了各种模式,但检查要么根本无法识别它们,要么表明函数返回一个对象而不是对象键的类型。

我希望静态分析工具能够理解

$key
的值代表
T
对象的属性。

php templates generics static-analysis template-specialization
1个回答
0
投票

Primero,需要纠正错误。例如,在您的方法中,使用 $key 和 $a 来使用。

继续使用 @psalm-param 和 @psalm-return 来恢复参数值。

有一个可能的解决方案:

php
Copy code
declare(strict_types=1);

/**
 * @template T of array{'a': string, 'b': int, 'c': DateTime}
 */
class Foo {
    /**
     * @var T
     */
    private array $foo;

    // Supongamos que __construct llena la propiedad $foo

    /**
     * @psalm-param key-of<T> $key
     * @psalm-return T[$key]
     */
    public function get(string $key)
    {
        return $this->foo[$key];
    }
}

Usando @psalm-param key-of $key, estás diciendo que el valor de $key debe ser una de las claves del tipo T.

Usando @psalm-return T[$key], estás diciendo que el Tipo de retorno debe ser el tipo del valor counteriente a la clave $key en T.

Con estas anotaciones,诗篇 debería ser capaz de inferir que:

(new Foo)->get('a') devuelve un string.
(new Foo)->get('b') devuelve un int.
(new Foo)->get('c') devuelve un DateTime.
© www.soinside.com 2019 - 2024. All rights reserved.