
К сожалению, невозможно определить явные типы массивов, как это делают другие языки программирования, такие как Java:
List<User> users = new ArrayList<>();
Было несколько попыток добиться этого, одна из последних была сделана Никитой Поповым в этом pull request, к сожалению, вывод о текущем статусе PHP был невозможен, это потребуется переписать огромное количество кода, и некоторые из них очень важны.
Будем надеяться, что некоторые инструменты, такие как PHPStan или Psalm, помогают нам анализировать код статически, то есть они не выполняют, а проверяют код на несоответствия на основе комментариев PHP.
Существует 3 разных способа определить тип элементов массива PHP:
- Устаревший способ:
User[] - Форма списка:
array<int,mixed>иlist<mixed> - Форма объекта:
array{0:int, foo:?string, bar:mixed}
Наследие
Это модный способ определить список элементов определенного типа, но проблема в том, что он становится неоднозначным, и клиенты, использующие такой список, не могут знать, являются ли ключи целыми числами, числами с плавающей запятой или строками.< br /> Также статические анализаторы не дадут сбой, если вы попытаетесь получить элемент по ключу с неправильным типом, в этих сценариях я бы предложил использовать array<int,mixed>.
В конце концов, чем откровеннее, тем лучше.
/** @var User[] $users */ $users = [ ... ]; # Are keys autoincremental integers, random numbers, maybe strings... ? $firstUser = $users[ ? ]; # Static analyzers won't complain if you use an incorrect type 🤕
Форма списка
Мы используем списки, когда у нас есть массив элементов одного типа.
Для этого мы используем алмазный синтаксис для объявления типов ключа и значения: array<int,mixed>. Есть очень удобный ярлык, когда ключ является автоматически увеличивающимся целым числом: list<mixed>.
/** @var array<string, User> $users */
$users = [
'jesus' => new User('Jesus Valera'),
'chema' => new User('Chema Valera'),
];
$userJesus = $users['jesus'];
$userChema = $users['chema'];
$users[0]; # ERROR: "Offset 0 does not exist on array<string, User>"
---
/** @var list<User> $users */
$users = [ ... ];
$firstUser = reset($users);
$lastUser = end($users);
Форма объекта
Мы используем форму объекта, когда массив представляет собой не набор объектов, а карту, которая содержит информацию.
Для этого мы используем фигурные синтаксис квадратных скобок и определяем имя ключа и тип, мы можем разделить запятыми, если есть несколько элементов: array{foo:int, bar:string}.
/** @var array{id:int, birthdate:DateTimeImmutable} */
$additionalInfo = [ ... ];
$id = $additionalInfo['id']; # int
$birthdate = $additionalInfo['birthdate']; # DateTimeImmutable
Пример класса User, содержащего два массива: список и форму объекта.
final class User
{
/** @var list<Comment> */
public readonly array $comments;
/** @var array{id:int, birthdate:DateTimeImmutable} */
public readonly array $additionalInfo;
}
Использование этих PHP-комментариев дает множество преимуществ: они не только предоставляют разработчикам лучшую обратную связь о форме массива, но и IDE предлагают автозавершение при повторении отдельных элементов!
Конечно, с помощью этих PHP-комментариев можно представить любую сложную структуру массива в PHP. Пример:
/**
* @var list<
* array{
* uuid?: string,
* content: array{name:string, foo:?stdClass},
* }
* > $array
*/
$array = [
0 => [
'uuid' => 'XXXX-XXX-XXX-XXXX',
'content' => [
'name' => 'str',
'foo' => null,
],
],
1 => [
'content' => [
'name' => 'str',
'foo' => new stdClass(),
],
],
// ...
];
Мы можем использовать комментарии PHP к массивам где угодно (свойства класса, параметры функции, встроенная инициализация…)