2

I cannot figure how to annotate an array returned from API Response. Response have a structure: array{'totalCount': numeric-string, $vehicleType: array} Instead of variable $vehicleType there can be different keys. List of all possible keys ($vehicleType) I have stored in Enum named VehicleType.

Here is an example of API reponse:

{
'totalCount': '2',
'car': [
    {'id': '14', 'brand': 'Ford'},
    {'id': '15', 'brand': 'Honda'}
   ]
}

Instead of 'car' from example I want to declare that it would be a specific string. Preferably I would like to declare all possible variations of that string (from my VehicleType Enum).

PSALM gives me errors, because I cannot declare return array of a method right. Because keys in PHPDoc Array shapes can be only simple strings. More than that - it doesn't support enumeration (with '|') in it. Like 'car'|'airplane'


Example #1 (using Array shapes with 'value-of' in key)

The most obvious and intuitive way - simply does not work. Because of the statement above - keys in PHPDoc Array shapes can be only simple strings

* @return array{'totalCount': numeric-string, value-of<VehicleType>: array}

Example #2 (using Array shapes with generic as key)

* @template ModelKey of value-of<VehicleType>
class ...
....

* @return array{'totalCount': numeric-string, ModelKey: array}
function...

This way PSALM sees ModelKey just as a string 'ModelKey'


Example #3 - Using General arrays I understand that I can declare an multi-element as follows:

@return array<value-of<VehicleType>, array>

This obviously is not a solution:

  1. 'totalCount' element is not declared at all.
  2. This tells PSALM that this array can contain multiple elements with keys from VehicleType enum, instead of only one

Example #4 - Combination of General arrays and Generics Using generics this way:

/** @template TotalElement of array{'totalCount': numeric-string}
 * @template VehicleElement of array<value-of<VehicleType>, array>
 * @template ApiResponseArray of array{TotalElement, VehicleElement}
 */
class 
...
/** @return ApiResponseArray */
public function ...

Makes it even worse - besides problem #2 from previous example we will not have an array with multiple keys, but array with separated arrays


Link: https://phpstan.org/writing-php-code/phpdoc-types I would really like a help with this, not even sure right now if it even possible. Currently my thought about this:

  1. Since I couldn't find on internet how to solve this now I tend to think I will not be able to use generated strings as keys in Array shapes;
  2. I just might have to declare return array as more general. Just using string instead of value-of<VehicleType>;
  3. @return array{'keyOne'|'keyTwo': array}. I will repeat: even this is not working;
  4. Converting Arrays to some Objects and working with them seems like a stupid hack and an overkill
1
  • Please write your code as an example on phpstan.org/try, and share the link in PHPStan’s GitHub discussions. The community will definitely help you there! Commented Apr 12, 2023 at 17:41

0

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.