Пример лучше любого объяснения: допустим, у меня есть следующий код
function arrayToIdMap(array $models) : array
{
$result = [];
foreach ($models as $model) {
/** @var BaseClassWithGetIdMethod $model **/
$result[$model->getId()] = $model;
}
return $result;
}
/** @var Car[] **/
$carList = getCarList();
/** @var Truck[] **/
$truckList = getTruckList();
/** @var Car[] **/
$carMap = arrayToIdMap($carList);
/** @var Truck[] **/
$truckMap = arrayToIdMap($truckList);
Что я хочу сделать, так это автоматически информировать PHP о типах $carMap
и $truckMap
, чтобы у меня был код, который действует как следующий псевдокод:
/**
* @param array $$models
* @return The_Original_Type_Inferred_From_$models
*/
function arrayToIdMap(array $models) : array
{
$result = [];
foreach ($models as $model) {
/** @var BaseClassWithGetIdMethod $model **/
$result[$model->getId()] = $model;
}
return $result;
}
/** @var Car[] **/
$carList = getCarList();
/** @var Truck[] **/
$truckList = getTruckList();
$carMap = arrayToIdMap($carList);
$truckMap = arrayToIdMap($truckList);
// $carMap[$id]->someMethod() will not show error if Car class has the someMethod method and PhpStorm knows $carMap is of type Car[] at this point
Это возможно или нет?
С PHPDoc ... посмотрите на дженерики ... Вам понадобится плагин Psalm (или это PHPStan?), Включенный для этого AFAIK (даже если вы не используете фактический Psalm) - он включен по умолчанию. jetbrains.com/help/phpstorm/using-psalm.html#generics-support . Также 1) blog.jetbrains.com/phpstorm/2021/12/phpstorm-2021-3-release/… 2) blog.jetbrains.com/phpstorm/2022/08/…
Это можно сделать с помощью расширенной мета-функции PhpStorm (PhpStorm использует ее для стандартных array_xxx
функций PHP — посмотрите здесь: https://github.com/JetBrains/phpstorm-stubs/blob/master/meta/ .phpstorm.meta.php#L64
Однако это не использует PHPDoc. Дополнительная информация (расширенные метаданные) должна храниться в отдельном файле только для глаз PhpStorm.
Сделать .phpstorm.meta.php
в корне проекта со следующим содержимым:
<?php
namespace PHPSTORM_META {
override(\arrayToIdMap(0), type(0));
}
Теперь файл с вашим кодом:
<?php
// Defining used classes and functions
class BaseClassWithGetIdMethod {
private string $id;
public function getId(): string
{
return $this->id;
}
}
class Car extends BaseClassWithGetIdMethod {
public function makeCar(){}
}
class Truck extends BaseClassWithGetIdMethod {
public function makeTruck(){}
}
function arrayToIdMap(array $models) : array
{
$result = [];
foreach ($models as $model) {
/** @var BaseClassWithGetIdMethod $model **/
$result[$model->getId()] = $model;
}
return $result;
}
// Test code
/** @var Car[] $carList **/
$carList = getCarList();
/** @var Truck[] $truckList **/
$truckList = getTruckList();
$carMap = arrayToIdMap($carList);
//$carMap[0]->
$truckMap = arrayToIdMap($truckList);
//$truckMap[0]->
С приведенным выше кодом PhpStorm предоставляет правильные методы:
Если это должно быть через PHPDoc... посмотрите на дженерики.
Для этого вам понадобится включенный плагин Psalm (или это PHPStan?) (даже если вы не используете фактический Psalm), поскольку такая поддержка предоставляется здесь. В любом случае, оба плагина связаны с PhpStorm и включены по умолчанию. https://www.jetbrains.com/help/phpstorm/using-psalm.html#generics-support
Код:
<?php
// Defining used classes and functions
class BaseClassWithGetIdMethod {
private string $id;
public function getId(): string
{
return $this->id;
}
}
class Car extends BaseClassWithGetIdMethod {
public function makeCar(){}
}
class Truck extends BaseClassWithGetIdMethod {
public function makeTruck(){}
}
/**
* @template T
* @param T $models
* @return T
*/
function arrayToIdMapZ(array $models) : array
{
$result = [];
foreach ($models as $model) {
/** @var BaseClassWithGetIdMethod $model **/
$result[$model->getId()] = $model;
}
return $result;
}
// Test code
/** @var Car[] $carList **/
$carList = getCarList();
/** @var Truck[] $truckList **/
$truckList = getTruckList();
$carMapZ = arrayToIdMapZ($carList);
$truckMapZ = arrayToIdMapZ($truckList);
$carMapZ[0]->
//$truckMapZ[0]->
Вот что я вижу в моем PhpStorm:
Да. Это можно сделать с помощью расширенной мета-функции PhpStorm (PhpStorm использует ее для стандартных
array_xxx
функций PHP — посмотрите здесь: github.com/JetBrains/phpstorm-stubs/blob/master/meta/… Это не так. однако используйте PHPDoc - он должен храниться в отдельном файле только для глаз PhpStorm.