PHP: Массивы

15 вопросов

1 Как устроены массивы в PHP?

Массив в PHP - это упорядоченная хеш-таблица. Внутренняя структура (HashTable) содержит:

  • Массив бакетов (Bucket) для хранения ключей и значений
  • Двусвязный список для сохранения порядка вставки
  • Хеш-функция для быстрого поиска по ключу

Это гибрид массива и хеш-таблицы: поддерживает числовые индексы (как массив) и строковые ключи (как map/dict). Порядок элементов всегда сохраняется (в отличие от HashMap в Java или map в Go).

Сложность операций: доступ по ключу O(1) amortized, добавление O(1) amortized, поиск по значению O(n).

Открыть отдельно →
2 Чем ассоциативный массив отличается от индексированного?

Технически это один и тот же тип array, разница только в ключах:

// Индексированный - числовые ключи (0, 1, 2...)
$fruits = ['apple', 'banana', 'cherry'];

// Ассоциативный - строковые ключи
$user = ['name' => 'John', 'age' => 30];

// Смешанный (допускается, но не рекомендуется)
$mixed = [0 => 'zero', 'key' => 'value', 1 => 'one'];

Функция array_is_list() (PHP 8.1) проверяет, является ли массив списком (последовательные числовые ключи от 0).

Открыть отдельно →
3 Что такое SplFixedArray? Когда эффективнее обычного массива?

SplFixedArray - массив фиксированного размера с числовыми индексами. Использует на 30-50% меньше памяти, чем обычный array:

$arr = new SplFixedArray(1000);
$arr[0] = 'hello';
$arr[999] = 'world';
// $arr[1000] - OutOfRangeException

$arr->setSize(2000); // можно изменить размер

Эффективнее обычного массива когда: большой массив (10K+ элементов), только числовые индексы, не нужны ассоциативные операции (array_filter, array_map). Для обычных задач стандартный array предпочтительнее из-за гибкости.

Открыть отдельно →
4 Как передается массив в функцию? По значению или по ссылке?

По значению, но с оптимизацией copy-on-write:

function process(array $arr) {
    // $arr - "копия", но реально данные не скопированы (COW)
    $arr[] = 'new'; // ЗДЕСЬ происходит реальное копирование
}

$data = [1, 2, 3];
process($data);
var_dump($data); // [1, 2, 3] - не изменился

Для передачи по ссылке:

function addItem(array &$arr) {
    $arr[] = 'new'; // изменяет оригинал
}

COW делает передачу по значению эффективной для чтения - копия создается только при модификации.

Открыть отдельно →
5 Что произойдет, если изменить массив внутри функции?

При передаче по значению (по умолчанию) - изменения не видны снаружи:

function modify(array $arr) {
    $arr[0] = 'changed';
}
$data = ['original'];
modify($data);
echo $data[0]; // "original"

При передаче по ссылке - изменения видны:

function modify(array &$arr) {
    $arr[0] = 'changed';
}
$data = ['original'];
modify($data);
echo $data[0]; // "changed"

В момент модификации массива, переданного по значению, срабатывает copy-on-write: PHP создает полную копию массива и модифицирует ее.

Открыть отдельно →
6 Какие функции для работы с массивами нужно знать?
// Трансформация
array_map(fn($x) => $x * 2, [1, 2, 3]);        // [2, 4, 6]
array_filter([0, 1, '', 'a'], fn($x) => $x);    // [1 => 1, 3 => 'a']
array_reduce([1,2,3], fn($c, $x) => $c + $x, 0); // 6

// Объединение
array_merge($a, $b);      // перенумеровывает числовые ключи
$a + $b;                   // сохраняет ключи первого
array_combine($keys, $vals);

// Сравнение
array_diff($a, $b);       // элементы из $a, которых нет в $b
array_intersect($a, $b);  // общие элементы

// Поиск
in_array($val, $arr, true);  // true = строгое сравнение
array_search($val, $arr);
array_key_exists('key', $arr);

// Извлечение
array_column($users, 'name');  // столбец из 2D массива
array_slice($arr, 1, 3);
array_unique($arr);
Открыть отдельно →
7 Как сортировать массивы?
$arr = [3, 1, 2];

sort($arr);           // по значению, сбрасывает ключи: [1, 2, 3]
rsort($arr);          // обратная сортировка
asort($arr);          // по значению, сохраняет ключи
arsort($arr);         // обратная с сохранением ключей
ksort($arr);          // по ключам
krsort($arr);         // по ключам, обратная

// Пользовательская сортировка
usort($arr, fn($a, $b) => $a <=> $b);  // spaceship operator
uasort($arr, $callback); // с сохранением ключей
uksort($arr, $callback); // по ключам

// Многополевая
array_multisort($col1, SORT_ASC, $col2, SORT_DESC, $arr);

Все функции сортируют массив in-place (модифицируют оригинал). Используют алгоритм Quicksort. Spaceship оператор <=> (PHP 7) возвращает -1, 0 или 1.

Открыть отдельно →
8 Как преобразовать массив в JSON и обратно?
// Кодирование
$json = json_encode(['name' => 'John', 'age' => 30]);
// '{"name":"John","age":30}'

$json = json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);

// Декодирование
$data = json_decode($json, true);   // true = ассоциативный массив
$obj  = json_decode($json);          // объект stdClass

// Проверка ошибок
if (json_last_error() !== JSON_ERROR_NONE) {
    echo json_last_error_msg();
}

// PHP 8.3
json_validate($json); // быстрая проверка без декодирования

Важно: json_encode() возвращает false при ошибке. Флаг JSON_THROW_ON_ERROR (PHP 7.3) превращает ошибки в исключения.

Открыть отдельно →
9 Что такое array destructuring?
// list() - классический синтаксис
list($a, $b, $c) = [1, 2, 3];

// Короткий синтаксис (PHP 7.1+)
[$a, $b, $c] = [1, 2, 3];

// Пропуск элементов
[, $second] = [1, 2, 3]; // $second = 2

// С ассоциативными ключами (PHP 7.1+)
['name' => $name, 'age' => $age] = ['name' => 'John', 'age' => 30];

// В foreach
$users = [['John', 30], ['Jane', 25]];
foreach ($users as [$name, $age]) {
    echo "$name is $age";
}

// Вложенная деструктуризация
[[$a, $b], [$c, $d]] = [[1, 2], [3, 4]];
Открыть отдельно →
10 Что такое spread operator для массивов?
// Распаковка массива (PHP 7.4+ для строковых ключей в 8.1)
$first = [1, 2, 3];
$second = [4, 5, 6];
$merged = [...$first, ...$second]; // [1, 2, 3, 4, 5, 6]

// В вызове функции
function sum(int ...$nums): int {
    return array_sum($nums);
}
$args = [1, 2, 3];
echo sum(...$args); // 6

// Ассоциативные массивы (PHP 8.1+)
$defaults = ['color' => 'red', 'size' => 'M'];
$custom   = ['color' => 'blue'];
$result   = [...$defaults, ...$custom]; // color=blue, size=M
Открыть отдельно →
11 Что такое compact() и extract()?
// compact() - создает массив из переменных
$name = 'John';
$age = 30;
$data = compact('name', 'age');
// ['name' => 'John', 'age' => 30]

// extract() - создает переменные из массива
$data = ['name' => 'John', 'age' => 30];
extract($data);
echo $name; // "John"
echo $age;  // 30

extract() считается опасным - может перезаписать существующие переменные, создает неявные зависимости. Используйте с EXTR_SKIP или EXTR_PREFIX для безопасности. В современном PHP лучше использовать деструктуризацию.

Открыть отдельно →
12 Что такое SplStack, SplQueue, SplPriorityQueue, SplHeap?

SPL структуры данных, реализованные на C (эффективнее массивов для специфичных задач):

// Стек (LIFO)
$stack = new SplStack();
$stack->push('a');
$stack->push('b');
echo $stack->pop(); // 'b'

// Очередь (FIFO)
$queue = new SplQueue();
$queue->enqueue('a');
$queue->enqueue('b');
echo $queue->dequeue(); // 'a'

// Приоритетная очередь
$pq = new SplPriorityQueue();
$pq->insert('low', 1);
$pq->insert('high', 10);
echo $pq->extract(); // 'high'

// Куча (MinHeap/MaxHeap)
$heap = new SplMinHeap();
$heap->insert(3);
$heap->insert(1);
echo $heap->extract(); // 1
Открыть отдельно →
13 Как удалить элемент из массива?
$arr = ['a', 'b', 'c', 'd'];

// unset - удаляет, НЕ перенумеровывает ключи
unset($arr[1]);
// [0 => 'a', 2 => 'c', 3 => 'd'] (дырка в индексах!)

// array_splice - удаляет и перенумеровывает
$arr = ['a', 'b', 'c', 'd'];
array_splice($arr, 1, 1);
// ['a', 'c', 'd'] (индексы 0, 1, 2)

// Удаление по значению
$arr = array_values(array_diff($arr, ['c']));

// array_filter для условного удаления
$arr = array_values(array_filter($arr, fn($x) => $x !== 'c'));

После unset() используйте array_values() для перенумерации, если нужны последовательные индексы.

Открыть отдельно →
14 Как проверить существование ключа?
$arr = ['key' => null, 'other' => 'value'];

// isset() - false для null значений!
isset($arr['key']);          // false (значение null)
isset($arr['other']);        // true
isset($arr['missing']);      // false

// array_key_exists() - проверяет только ключ
array_key_exists('key', $arr);     // true
array_key_exists('missing', $arr); // false

Если ключ может содержать null как допустимое значение - используйте array_key_exists(). Для большинства случаев isset() быстрее и предпочтительнее. Null coalescing: $val = $arr['key'] ?? 'default'.

Открыть отдельно →
15 Что такое генератор как lazy-итератор для больших массивов?

Генераторы позволяют обрабатывать данные по одному элементу, не загружая все в память:

// Обычный массив - 1 млн элементов в памяти
function getAll(): array {
    $data = [];
    for ($i = 0; $i < 1_000_000; $i++) {
        $data[] = $i;
    }
    return $data; // ~32 MB
}

// Генератор - 1 элемент в памяти
function getAll(): Generator {
    for ($i = 0; $i < 1_000_000; $i++) {
        yield $i;
    }
}

foreach (getAll() as $item) {
    process($item);
}

Генераторы идеальны для: чтения больших файлов, результатов из БД, потоковой обработки. Потребление памяти не зависит от объема данных.

Открыть отдельно →
🧠Квиз 🏆Лидеры 🎯Собесед. 📖Вопросы 📚База зн.