我在9级的项目中运行PHPStan,现在我已经接近零错误了。不过,我找不到解决方案的一个问题是我项目的CRUD部分。
带有>50个需要权限、有关系等的复杂实体。当然,我无法多次编写CRUD部分,一遍又一遍地重复相同的逻辑和模板。相反,我有一个中央CrudController,实体的名称以及例如需要更新的特定条目的ID都是URL的一部分:
.../crud/[Entity]/[ID]
,例如.../crud/Article/123
控制器操作(Symfony此处=类方法(然后采用变量$entity中实体的名称,以加载ID在$ID中的特定条目。所以不是
$entry = new Article(...);
我必须加载正确的实体,如下所示:
$entry = new $entity(...);
我的CRUD中的所有东西都已经工作了。这里的问题是PHPStan不理解返回的对象的类型。我试过各种方法,比如
/** @var $entity $entry */
在变量$entry的声明之上,但无效。PHPStan只是抛出类似的错误
PHPDoc tag @var contains unknown class ...
或PHPDoc tag @var has invalid value...
以下是这个问题在操场上的一个非常基本的版本:https://phpstan.org/r/d9cb71bc-f2c5-4387-a3d6-841656824d41
如果没有像@var这样的东西,$entry发生的任何其他事情都会引发错误,例如:
$id = $entry->getId();
投掷Call to undefined method object::getId().
我在文档中读到过关于泛型/模板等的内容,但那并不成功。我无法更改实体或它们的PHPDoc注释。所以我想我必须依赖变量声明上方的@var。但我也不能添加所有可能的实体名称,比如:
/** @var Article|Blog|Statistic|... $entry */
那么,有没有一种干净的方法可以告诉PHPDoc对象类型是动态的,并且基于$entity?
phpstan/条令扩展将为您解决大部分这些问题。然而,PHPStan实际上并没有运行任何代码,因此它不可能在运行时处理变量中存在未知动态类名的情况。你可以忽略:
// @phpstan-ignore-next-line
$id = $entry->getId();
或者,如果getId()
是以这种方式使用的唯一方法,则可以为该方法创建一个接口:
interface IdInterface {
public function getId();
}
然后让你的所有实体实现:
class Article implements IdInterface {
public function getId() {
return $this->id;
}
// ...
}
然后你可以在界面上键入提示:
/** @var IdInterface $entry */
$entry = new $entity(...);
$id = $entry->getId();