TGViewer
PHP Fart Time PHP Fart Time @php_fart · 1.95K subscribers
Post #31 727
#Article #Типизация #php

#️⃣ Variadic параметр

Вроде тут и сказать нечего. Ну поставил три точки в параметре и всё.
Ан нет. Приколов хватает. Погнали 

⭕️ Что известно

Variadic параметр, он же "списки аргументов переменной длины", пользователем с помощью добавления (сюрприз!) многоточия. Примерно столько вы можете прочитать про variadic в документации. А ещё про то, что в него можно распаковывать итерируемые значения другим многоточием.

function toArray(...$items): array { return $items; }
$a = ['foo', 'bar'];
toArray(...$a);


Variadic является опциональным параметром. Всегда. Т.е. вы можете ничего в него не передавать и ему с того норм.

> Кстати, многие путают понятия "аргумент" и "параметр". Параметр - то, что в определении функции, аргумент - значение, которое передаётся в функцию.

Зачем он нужен, если и так можно передать сколько угодно аргументов, а потом вынуть их с помощью func_get_arg(), как делали ещё наши предки? Кроме того, мы можем в конце списка параметров сунуть массив и даже распаковка не понадобится при вызове функции. function foo(Foo $a, array $myVariadic = []) {}.
А затем, что в variadic умеет в типизацию! (про типы см. предыдущий пост).

function foo(Foo $a, Bar ...$variadic) {}


Теперь только объекты Bar попадут в массив $variadic. Ну это и так все знали.

⭕️ Приколы с распаковкой

Распаковывая iterable в variadic, ключи могут быть разные. Если вы распаковываете список (ключи типа int), то их порядок будет сброшен. Т.е. распаковка массива [3 => 'a', 2 => 'b', 1 => 'c'] приведёт к ['a', 'b', 'c'] в вариадике.
Ассоциативный массив останется ассоциативным массивом с теми же ключами.
Но не всегда можно смешивать целочисленные ключи со строковыми. При распаковке аргументов из массива, как и при передаче именованных+позиционных аргументов, позиционные аргументы должны идти перед именованными. Причём сортируется это по параметрам 💥

⭕️ Именованные аргументы (PHP 8.0)

Поиграем в игру. Есть сигнатура bar(int $a = 1, int $b = 2, int ...$c). Что попадёт в $c?

(если нажать на один скрытый элемент — откроются все)
bar(a: 1, c: 3) - `["c" => 3]`
bar(c: [1, 2, 3]) - `Fatal Error`
bar(foo: 3) - `["foo" => 3]`
bar(1, 2, a: 3) - `Fatal Error`
bar(c: 3, a: 1, b: 2) - `["c" => 3]`
bar(foo-bar: 3) - `Syntax Error`
bar(1, 2, 3, 4, foo: 5) - `[3, 4, "foo" => 5]`
bar(b: 2, 3, 4, foo: 5) - `Fatal Error`
Сколько промахов?
Как итог: распаковка аргументов из массива даёт возможность передать любой сроковой ключ, именованные аргументы — нет.

⭕️ Хрень какая-то. Где оно надо то вообще?

- Когда нужна типизация на списке аргументов, при этом не нужно сохранять ключи. При этом сигнатура точно не будет дополняться. Например, в yiisoft/injector в конструктор можно было бы передавать переменное число ContainerInterface, а не один и только один (@samdark, я смотрю на тебя). Или вот пример, как заставить передать минимум один аргумент нужного типа: function setEncoders(Encoder $encoder, Encoder ...$encoders) {}.

- В атрибутах, которые конфижат непонятно что. В атрибуте Column компонента cycle/orm можно передать любые именованные аргументы сверх тех, что предопределены заранее (спасибо, variadic). Например, определяем #[Column(type: 'bigint', unsigned: true). Здесь unsigned попадёт в variadic и, если у вас MySQL, столбец будет unsigned.

⭕️ Аннотации

Артефакты прошлого ещё долго будут встречаться в коде даже современном. Да, это про аннотации. Там variadic'и не поддерживаются. До недавнего времени они вообще фейлили парсер doctrine/annotations, однако там решили ограничиться просто фиксом "чтоб не падало". Поэтому (и не только) не пользуйтесь аннотациями, если есть возможность пользоваться атрибутами.

⭕️ Поддержка IDE

Её нет. Пока нет известного мне способа рассказать IDE или Psalm'у, какие ключи можно передать в variadic. Можно описать тип только одного (каждого) передаваемого элемента. Если вам известно об этом больше - го в комменты.
  • 🔥 8
  • 🤯 3
More from @php_fart
  1. Sep 26, 2026Post #387
  2. Sep 26, 2026Testo: тестирование со вкусом хинкали 👤 Алексей Гагарин 🕘 2 октября, 10:00 (МСК) Зачем P…
  3. Sep 24, 2026#ТоксикСреда в четверг. PHPStorm в следующем году будет спонсировать Larabelles*. * Larabe…
  4. Sep 9, 2026Попрошу перенести старт на конец сентября этого года. Лишь бы не жрать лимон 🍋
  5. Sep 9, 2026Если по моему промокоду придёт 50 фартанов, то я сожру лимон в прямом эфире перед докладом…
  6. Sep 9, 2026А у меня для вас вот такой промокод на Пыхник: PHPFART-26. Приходите смотреть, как я облаж…
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →