PHP 12579 ~ 3 мин.

Деструктуризация массива в PHP

Деструктуризация массива в PHP

В PHP list является такой же «языковой конструкцией», как и array(). Эта языковая конструкция используется для «разложения» массива на переменные

Я никогда не видел слишком частого использования list() в "дикой природе", но он позволяет вам писать довольно интересные вещи. Деструктуризация не есть разрушение 😉.

list или []

Вот как это выглядит:

$array = [1, 2, 3]; 

//использование Oldschool:
list($a, $b, $c) = $array;

// или короткий вариант, начиная с PHP 7.1:
[$a, $b, $c] = $array;

// $a = 1
// $b = 2
// $c = 3

Можно использовать list или его короткий вариант [], как вам удобно. Есть мнение, что [] это неоднозначное использование с синтаксисом сокращенного массива, и поэтому предпочитают list. Я обычно использую сокращенную версию в примерах кода.

Так что еще можно сделать с list?

Пропустить элементы

Скажем, вам нужен только третий элемент массива, первые два можно пропустить, просто не указав переменную.


[, , $c] = $array;

// $c = 3

Также стоит обратить внимание, что list всегда начинается с индекса 0. Возьмем, к примеру, следующий массив:


$array = [
    1 => 'a',
    2 => 'b',
    3 => 'c',
];

Значение первой переменной, которое вытащит list будет null, потому что нет элемента с индексом 0. Это может показаться недостатком, но, к счастью, имеет большие перспективы.

В PHP5 list() присваивает значения начиная с самого правого значения. В PHP7 - с самого левого значения.
Если вы используете обычные переменные, можете не думать об этом, но, если вы используете массивы с индексами, вы ожидаете, что порядок элементов в массиве будет ровно таким, как вы его определили в list(), слева направо, но в PHP5 вы получите обратный порядок.

Вообще говоря, желательно не полагаться на конкретный порядок операций, так как в будущем это поведение может быть изменено.

Не числовые ключи

PHP 7.1 позволяет list использовать ассоциативный массив. Это открывает много возможностей:


$array = [
    'a' => 1,
    'b' => 2,
    'c' => 3,
];

Присвоение можно сделать так:


['c' => $c, 'a' => $a] = $array;

Как видите, вы можете изменить порядок, какой хотите, а также полностью пропустить элементы.

Или другой пример:


$person = [
    'name' => 'Sergey',
    'job' => 'Developer',
];

list('job' => $job) = $person;

echo $job; // "Developer"


На практике


Разбор адреса или пути файла

Часто list применяют с такими функциями  как parse_url() и pathinfo(). Поскольку эти функции возвращают массив с именованными параметрами, можно использовать list для извлечения нужной нам информации:


[   'basename' => $file,
    'dirname' => $directory,
] = pathinfo('/products/001/product-1.png');

Как видно из примера, переменные не нуждаются в том же имени, что и ключ. Также обратите внимание, что разложение массива с неизвестным ключом вызовет предупреждение:


[  'path' => $path, 
   'query' => $query,
] = parse_url('https://sergeymukhin.com/blog');

// PHP Notice:  Undefined index: query

В этом случае $query будет null. Еще одна деталь: с именованными деструкторами допускаются конечные запятые, так же как это делается в обычных массивах.


Explode строки

Если после explode строки вы хотите сразу представить результат как две отдельные переменные:


[$user, $repository] = explode('/', 'sinbadxiii/my-repo', 2);


Создание нескольких объектов

Итак, вы создали несколько объектов одновременно, например с помощью фабрики, и хотите, чтобы они все были отдельными переменными:


[$userA, $userB, $userC] = factory(User::class, 3)->create();


Обмен значений переменных

И мое любимое, это просто шедевр в синтаксисе PHP, например, вы хотите поменять местами две переменные;


$a = 'hello';
$b = 'world';

[$a, $b] = [$b, $a];

echo $a; // "world"
echo $b; // "hello"

Что-то похожее есть на Python:


a, b = b, a


В циклах

Вы также можете использовать конструкцию списка в циклах:


$array = [
    [
        'name' => 'a',
        'id' => 1
    ],
    [
        'name' => 'b',
        'id' => 2
    ],
];

foreach ($array as ['id' => $id, 'name' => $name]) {
    // …
}

Это может быть полезно при разборе файла, например, JSON или CSV. Но нужно быть осторожным, неопределенные ключи могут вызывать предупреждения.

Несколько возвращаемых значений

Некоторые языки допускают возвращение нескольких значений. Рассмотрим функцию, у которой в качестве параметра целое число и возвращает она два целых числа, одно из которых является $int + 5, другое $int - 5. Вот как это будет выглядеть в Go:


func addAndRemoveFive(i int) (int, int) {
    return i + 5, i - 5
}

func main() {
    x, y := addAndRemoveFive(10)
}

Мы могли бы достичь что-то подобного, возвращая массив в PHP и немедленно его уничтожая:


function addAndRemoveFive(int $i): array {
    return [$i + 5, $i - 5];
}

[$x, $y] = addAndRemoveFive(10);

echo $x; // 15
echo $y; // 5

Более реальная ситуация, когда несколько возвращаемых значений могут быть полезны, - это случаи, когда вы ожидаете статус и сообщение, например валидация;


[$valid, $reason] = $validator->validate($data);

if (! $valid) {
    return new JsonResponse(422, ['reason' => $reason]);
}

return new JsonResponse(200);


Ну что, я вас убедил в полезности использования list в своем коде?

Что думаешь?

Прохожий04.12.2023

Шедевр в синтаксисе PHP? А ничего, что в js этот синтаксис свопа переменных существует уже больше пятнадцати лет? И не только в нем :-)

Сергей Мухин 05.12.2023

Ну так мы же в рамках PHP и говорим) как написано в посте, синтаксис того же python для этих целей еще элегантнее.

А если прямо совсем "докапываться" до мелочей, то JS мог предоставить синтаксис свопа, если не ошибаюсь с ES2015, что логично было в 2015 году, в то время, как PHP 7.1 вышел в 2016, так что разница не велика.

Стоит так же заметить, что деструктуризация работает еще с PHP 4 (2000-х годов, но там конечно есть ограничения на числовые значения массива)

Но, кстати, заимствование классных вещей из других языков не есть плохо, в последних версиях PHP (Тот же Никита Попов ссылался на другие языки), некоторые фишки были взято из Java, Rust и пр.

Вася11.06.2023

А что на счет Warning, когда ключа не существует?

Сергей Мухин 13.06.2023

Не совсем понятен вопрос, но в посте есть указание "разложение массива с неизвестным ключом вызовет предупреждение"

Категории
  • PHP 66
  • Заметки 15
  • Безопасность 3
  • Флуд 2
  • Nginx 2
  • ИТ новости 2
  • Видео 1
  • Docker 1
  • Roadmap 1
  • Архитектура 0

Хочешь поддержать сайт?

Делаем из мухи слона

sergeymukhin.com

персональный блог о веб-разработке от Сергея Мухина. Блог был основан в 2018 году, и собирался уделять основное внимание последним тенденциям, учебным пособиям, а также советам и рекомендациям, позволяющим начинающим девелоперам встать быстрее на правильную дорогу веб разработки, но что-то пошло не так 😃

Релизы PHP 8.4

Дата Релиз
8 Июня 2024 Альфа 1
20 Июня 2024 Альфа 2
04 Июля 2024 Альфа 3
16 Июля 2024 Feature freeze
18 Июля 2024 Бета 1
01 Августа 2024 Бета 2
15 Августа 2024 Бета 3
29 Августа 2024 RC 1
12 Сентября 2024 RC 2
26 Сентября 2024 RC 3
10 Октября 2024 RC 4
24 Октября 2024 RC 5
07 Ноября 2024 RC 6
21 Ноября 2024 GA

Что нового?