0

An example is better than any explaining: Let's say I have the following code

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);

What I want to do is, to inform PHP automatically the types of $carMap and $truckMap so that I have some code that acts like the following pseudocode:

/**
 * @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

Is this possible or not?

2

1 Answer 1

1

This could be done with PhpStorm's Advanced Meta functionality (PhpStorm uses it for standard array_xxx PHP functions -- have a look here: https://github.com/JetBrains/phpstorm-stubs/blob/master/meta/.phpstorm.meta.php#L64

This does not use PHPDoc though. The extra info (advanced metadata) should be stored in a separate file for PhpStorm eyes only.

Make .phpstorm.meta.php in the project root wit the following content:

<?php

namespace PHPSTORM_META {
    override(\arrayToIdMap(0), type(0));
}

Now the file with your code:

<?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]->

With the code above PhpStorm provides correct methods:

enter image description here


If it has to be via PHPDoc ... look at generics.

You would need Psalm (or is it PHPStan?) plugin enabled for that (even if you do not use the actual Psalm) as it is how such a support is supplied here. Anyway, both plugins are bundled with PhpStorm and enabled by default. https://www.jetbrains.com/help/phpstorm/using-psalm.html#generics-support

The code:

<?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]->

That's what I see in my PhpStorm:

enter image description here

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.