Номер телефона

Последнее обновление:

Создание многомерных массивов в PHP

Массив в языке РНР создается при помощи такой команду:

$m = array();

При этом будет создан пустой массив. Это - универсальная команда, работающая даже в самых старых версиях РНР. В более новых, начиная, кажется, с 7-й версии, также есть более простой синтаксис:

$m = [];

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

Как создать массив с числом измерений более одного, т.е. многомерный? В РНР это делается просто путем создания соответствующих элементов массива, например:

$m[0] = 34;

Или просто

$m[] = 34;

Если продублировать последнюю команду, будет создан следующий элемент массива, т.е. $m[1]. И так далее. Но, это - одномерный массив. Для создания многомерного можно воспользоваться, например, следующим:

$m['qwerty'][] = 34;

Или

$m['qwerty'][2] = 34;

Таким образом можно создавать любые массивы, любой размерности. Однако, этот способ подходит, когда количество измерений массива известно заранее. И, кроме того, когда индексы задаются явно.

А как быть, когда мы хотим создать массив с числом измерений, заранее неизвестным? Т.е. когда оно меняется динамически. Например, мы хотим создать элемент массива типа

$m[2]['qwe']['57']['y']

Это - достаточно редкий класс задач, но иногда он все равно возникает.

Стоит иметь в виду, что многомерные массивы в языке PHP требуют достаточно высокого объема оперативной памяти. Не стоит полагаться на высокую производительность многих современных компьютеров. Ибо когда-то наступит момент, когда "вдруг" обнаружится нехватка оперативной памяти. Очень ориентировочно, можно сказать, что объем оперативной памяти, затрачиваемой на создание массива, превышает фактический объем имеющихся в нем данных примерно на 1-2 порядка. Что особенно актуально для массивов большой размерности. Чем больше число измерений, тем больше затрачивается памяти.

Рассмотрим подходы, как можно это реализовать.

1. С использованием рекурсии

Пример взят на основе этой статьи. 

$in['a--b--c--d'] = 'value';
$keys = explode('--', key($in));

function arr_to_keys($keys, $val){
if(count($keys) == 0){
return $val;
}
return array($keys[0] => arr_to_keys(array_slice($keys,1), $val));
}
$out = arr_to_keys($keys, $in[key($in)]);

print_r($out);

Вот что получим на выходе:

Array
(
[a] => Array
(
[b] => Array
(
[c] => Array
(
[d] => value
)
)
)
)

Здесь индексы массива a, b, c сами являются, в свою очередь, массивами. Таким образом можно создавать массивы. по сути, любой размерности, заранее не зная ее.

Если требуется создать такой массив для строки 'abcd',  то функция explode не поможет. Слегка модернизируем код:

$str = 'abcd';
$keys = array();
for($i = 0; $i < strlen($str); $i++){
$keys[$i] = substr($str, $i, 1);
}

function arr_to_keys($keys, $val){
if(count($keys) == 0){
return $val;
}
return array($keys[0] => arr_to_keys(array_slice($keys,1), $val));
}
$out = arr_to_keys($keys, 'value');

print_r($out);

Выводимый результат будет тем же самым.

2. При помощи цикла

$out = array();
$temp = &$out;
$keys = explode('--', 'a--b--c--d');
foreach ($keys as $key) {
$temp[$key] = array();
$temp = &$temp[$key];
}
$temp = 'value';

print_r($out);

Результат - тот же самый.

Обсуждение этих способов

В целом, способы удобные, если бы не большое "но". Что, если будет потребность присвоить индексам и другие значения. Например, потребуется создать такой элемент массива:

$m['a']['b']['c']['d']['e'] = 'value1';

Вероятно, возникнет ошибка. Причина которой, кстати, может быть не сразу очевидна. Ее причина в том, что элемент массива $m['a']['b']['c']['d'] является строкой. А не массивом. Строке нельзя присвоить функциональность массива. Чтобы переменная являлась массивом, ее необходимо предварительно объявить, как массив; или же использовать соответствующие функции, которые автоматически создают массив на выходе (типа explode или array_map).

Т.е. вполне допустима такая конструкция (ко крайней мере, в версии PHP < 7):

$m = 'qwerty';

$m = array();

Это допустимо потому, что во второй строчке происходит переобъявление переменной $m, которая превращается в массив. Однако, вот это недопустимо:

$m = 'qwerty';

$m[0] = 'value';

Будет ошибка. Впрочем, в ранних версиях РНР когда-то допускалось, что строка - это массив одиночных символов. Теперь такое поведение объявлено устаревшим.

3. Использование заранее объявленных массивов требуемой размерности

Что-то типа такого:

$temp = 'value';
switch (sizeof($keys)) {
case 1:
$m[$keys[0]] = $temp;
break;
case 2:
$m[$keys[0]][$keys[1]] = $temp;
break;
case 3:
$m[$keys[0]][$keys[1]][$keys[2]] = $temp;
break;
case 4:
$m[$keys[0]][$keys[1]][$keys[2]][$keys[3]] = $temp;
break;
case 5:
$m[$keys[0]][$keys[1]][$keys[2]][$keys[3]][$keys[4]] = $temp;
break;
case 6:
$m[$keys[0]][$keys[1]][$keys[2]][$keys[3]][$keys[4]][$keys[5]] = $temp;
break;
case 7:
$m[$keys[0]][$keys[1]][$keys[2]][$keys[3]][$keys[4]][$keys[5]][$keys[6]] = $temp;
break;
// И так далее...
}

Вместо индексов 0, 1, 2, ... можно использовать соответствующие строковые ключи. Главное - заблаговременно создать структуру массива с учетом требуемого числа измерений.

Бесконечно это продолжаться не может, т.к., еще раз, чем выше число измерений массива, тем существеннее возрастают требуемые ресурсы компьютера. Однако, этот способ - топорный, что называется, "колхозный". Едва ли он может быть применен в реальных проектах.

4. Использование eval

Эту функцию нередко осуждают. И, отчасти, совершенно правильно. Ибо в неумелых руках она вполне может натворить бед и привести к неожиданным результатам. Один из принципов программирования гласит: по возможности, не стоит использовать функцию eval. Стоит искать другие варианты, а eval применять, когда без нее уж точно обойтись нельзя. По всей видимости, это - как раз тот самый случай. Ведь в языке PHP, по крайней мере, на момент написания статьи, отсутствует удобная функциональность динамического создания массива с меняющимся числом измерений.

Вот как это может выглядеть:

$str = 'abcd';
$m = array();
$keys = array();
$value = 'qwerty';

for($i=0; $i < strlen($str); $i++){
$keys[] = substr($str, $i, 1);
}

$eval_str = "\$m['". implode("']['", $keys) ."'] = array(". $value .");";
eval($eval_str);
print_r($m);

Результат:

Array
(
[a] => Array
(
[b] => Array
(
[c] => Array
(
[d] => Array
(
[0] => qwerty
)
)

)

)

)

Обратим внимание: элемент массива $m['a']['b']['c']['d'] является массивом. Т.е. вполне можно добавить ему дополнительные индексы, например:

Array
(
[a] => Array
(
[b] => Array
(
[c] => Array
(
[d] => Array
(
[0] => qwerty
[1] => array()
)
)
)
)
)

Т.е. этот способ видится более универсальным. При этом, конечно же, следует тщательно контролировать, что именно попадает в переменную $eval_str. Иначе результаты могут быть непредсказуемыми.


Комментарии:
Всего комментариев:0
Пожалуйста, не забудьте ознакомиться с правилами оставления комментариев.



Подписаться на комментарии на этой странице

Мы можем выполнить

Другие услуги
Интересная и полезная
информация
НАПИШИТЕ НАМ
Яндекс.Метрика
Номер телефона
© Copyright Все права защищены 2013-2026 Научный консалтинг