假设我有以下 PHP 函数:
/**
* @param string $className
* @param array $parameters
* @return mixed
*/
function getFirstObject($className, $parameters) {
// This uses a Doctrine DQl builder, but it could easily replaced
// by something else. The point is, that this function can return
// instances of many different classes, that do not necessarily
// have common signatures.
$builder = createQueryBuilder()
->select('obj')
->from($className, 'obj');
addParamClausesToBuilder($builder, $parameters, 'obj');
$objects = $builder
->getQuery()
->getResult();
return empty($objects) ? null : array_pop($objects);
}
基本上,如果出现问题,该函数总是返回用
$className
参数或null
指定的类的实例。唯一的问题是,我不知道这个函数可以返回的类的完整列表。 (在编译时)
这种函数的返回类型是否可以得到类型提示?
在 Java 中,我会简单地使用泛型来暗示返回类型:
static <T> T getOneObject(Class<? extends T> clazz, ParameterStorage parameters) {
...
}
我知道手动类型提示,比如
/** @var Foo $foo */
$foo = getOneObject('Foo', $params);
但我想要一个不需要此样板行的解决方案。
详细说明:我正在尝试围绕 Doctrine 编写一个包装器,以便我可以轻松获得我想要的模型实体,同时封装 ORM 系统的所有特定用法。我正在使用 PhpStorm。
** 编辑功能以反映我的预期用途。我最初想让它不包含任何特定的用例,以免使问题膨胀。另请注意,实际的包装器更复杂,因为我还合并了特定于模型的隐式对象关系并连接等。
我为此目的使用 phpdoc
@method
。例如,我创建了 AbstractRepository
类,它由其他 Repository 类扩展。假设我们有 AbstractRepository::process(array $results)
方法,其返回类型根据扩展它的类而变化。
所以在子类中:
/**
* @method Car[] process(array $results)
*/
class CarRepo extends AbstractRepository {
//implementation of process() is in the parent class
}
更新一:
你也可以使用
phpstan/phpstan
库。它用于静态代码分析,您可以使用它来定义通用返回类型:
/**
* @template T
* @param class-string<T> $className
* @param int $id
* @return T|null
*/
function findEntity(string $className, int $id)
{
// ...
}
现在可以使用 IntellJ (IDEA/phpStorm/webStorm) 插件 DynamicReturnTypePlugin 来实现: https://github.com/pbyrne84/DynamicReturnTypePlugin
如果您使用 PHPStorm 或 VSCode(带有 Ben Mewburn 的扩展 PHP Intelephense),则有一个名为 metadata 的实现,您可以在其中根据您的代码在其中执行魔术来指定您自己的类型提示。所以下面应该工作(就像它在 VSCode 1.71.2 上所做的那样)
<?php
namespace PHPSTORM_META {
override(\getFirstObject(0), map(['' => '$0']));
}