方案
我使用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(...);
答案 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);
分析器会知道$finder
是Finder<City>
的一个实例,因此findById
会返回City
。
如果没有泛型,没有办法告诉分析器,如果在其构造函数中给出City::class
,Finder
类将始终返回该类的实例。