PhpStorm无法将返回类型识别为另一个

时间:2017-11-17 09:12:59

标签: php phpstorm type-hinting php-7.1

方案

我使用PHP7类型提示来说我的函数的返回类型为City

public function getCityById(int $city_id) : City { ... }

在这个函数中,我返回运行finder的结果。

return $this->city_finder->findById($city_id);

但是PhpStorm在这里抱怨,因为findById()函数返回AbstractModel

但我有class City extends AbstractModel,所以这不是问题。然而,PhpStorm似乎并没有意识到这一点,并强调了返回声明并发出警告。

我不想将此类警告静音(禁用检查),因为这是一个重要警告。

问题

我可以让PhpStorm认识到这个return语句会满足返回类型吗?

其他信息

一种解决方法是提取变量并对其进行注释,如下所示:

/** @var City $city */
$city = $this->city_finder->findById($city_id);
return $city;

此时,它停止向我发出警告,但似乎应该可以避免额外的行,因为它只存在于IDE中的静音警告。

findById()函数受到保护,不会返回错误的类型,因为Finder类是基于每个模型生成的。

$this->city_finder = $this->orm->getFinder(City::class);
//...
$city = $city_finder->findById(...);

2 个答案:

答案 0 :(得分:4)

PHPStorm是正确的。

您的findById()返回AbstractModel,并且您尝试返回City的范围更广。如果您从findById()收到一些其他类也继承自AbstractModel,但不是City或其后代 - 您将收到来自PHP的致命错误是PHPStorm警告你的。

您可以通过添加注释,或者通过显式检查if ($city instanceof City) {return $city; }来解决此问题。它可能看起来略显臃肿,在运行时是安全的。

答案 1 :(得分:3)

PHPStorm在技术上就在这里:根据你的函数的合同,语句可能会返回错误的值。

$result = $this->city_finder->findById($city_id);

我们唯一能够了解$result的内容是findById向我们承诺的内容,以及它是AbstractModel的内容。 可能City,但它可能同样是User,或Widget,或定义为class extends AbstractModel {}的匿名对象。< / p>

潜在的问题是$this->city_finder是一些抽象存储库的实例;当知道它将始终处理City个对象时,它们实际上并没有内置到你的类型系统中。如果它是一个更具体的类,它可以声明它从City方法返回findById个对象,并且代码是类型安全的。

根据您的评论,您的ORM将类名作为参数($finder = $orm->getFinder(City::class);),如果PHP支持&#34;泛型&#34;或者&#34;模板元编程&#34;,你可能写这样的东西:

class ORM {
    public function getFinder<T>(): Finder<T> { ... }
}
class Finder<T> {
     public function findById(int $id): T { ...}
}
$finder = $orm->getFinder<City>();
$city = $finder->findById($city_id);

分析器会知道$finderFinder<City>的一个实例,因此findById会返回City

如果没有泛型,没有办法告诉分析器,如果在其构造函数中给出City::classFinder类将始终返回该类的实例。