Программирование - это синтаксис и семантика. Первое определяется правилами языка, второе - опытом разработчика. В отношении массивов разработчик может предметно нагрузить синтаксис семантикой. Это еще не объект, но уже не массив в традиционном понимании. PHP дает возможность создавать массивы из переменных различных типов, включая самих себя. Элементом массива может быть функция, то есть возможность нагрузить массив реальным алгоритмом, реальным смыслом.
Синтаксис стабилен, но меняется от версии к версии и не всегда может быть совместимым даже снизу вверх. Переносимость программ - хорошо забытое достижение прошлого века. Семантика развивается и всегда может быть применена не только в любой версии любого языка; стало традицией использовать синтаксические конструкции для выражения того, что правилами языка даже предусмотрено не было. На примере массивов это можно понять наиболее просто.
Конструирование массивов
Массив в PHP имеет удобный синтаксис и функциональность. Этот тип данных можно описать предварительно, но часто удобно создавать массивы на лету по мере необходимости.
public $aNone = array(); // массив описан и ничего не содержит
public $aFact = array('авокадо', 'персик', 'вишня'); // в этом массиве три элемента
Создание массива в процессе проверки какого-либо условия:
$cSrcLine = 'строка анализируемых данных';
for ($i=0; $i<13; $i++) {
$cUserLine = inputUserLine(); // ввод чего-то
if (checkFunc($cSrcLine, $cUserLine) {
$aResult[] = 'Yes'; // добавить в массив PHP
} else {
$aResult[] = 'No';
}
}
В результате исполнения данного примера создастся массив из 13 элементов, значениями которого будут только строки 'Yes' или 'No'. Элементы получат индексы от 0 до 12. Тот же эффект можно получить, предварительно записав "будущий" PHP-массив в строку:
$cFutureArray = '';
for ($i=0; $i<13; $i++) {
$cUserLine = inputUserLine(); // ввод чего-то
if ($i > 0) { $cFutureArray .= '|'; }
if (checkFunc($cSrcLine, $cUserLine) { $cFutureArray .= 'Yes';
} else { $cFutureArray .= 'No'; }
}
$aResult = explode('|', $cFutureArray);
Многомерные массивы
Многие системы управления сайтами (СМС) используют массивы «с размахом». С одной стороны, это хорошая практика, с другой стороны, это затрудняет применение. Даже если автору понятна доктрина "PHP-массив в массиве", то не следует ей злоупотреблять: не только разработчику придется привыкать к сложной нотации. Часто спустя время сам создатель будет долго вспоминать, что писал поначалу:
return array(
'view_manager' => array(41, 'template_path_stack' => array( __DIR__ . '/../view', ),
'router' => array('routes' => array('sayhello' => array(
'type' => 'Zend\Mvc\Router\Http\Literal',
'options' => array('route' => '/sayhello', 'defaults' => array(
'controller' => 'Helloworld\Controller\Index', 'action' => 'index',))))),
'controllers' => array('invokables' => array(
'Helloworld\Controller\Index' => 'Helloworld\Controller\IndexController'))
);
Это образец практики «PHP-массив в массиве» от ZF 2. Не слишком вдохновляет поначалу, но это работает и, возможно, делает данный фреймворк успешным (пример из модуля ZendSkeletonApplication/module/Helloworld/config/module.config.php).
Массив - важная конструкция данных в ходе проектирования и разработки. Его многомерный вариант когда-то был популярен, но с течением времени осталась потребность в массивах максимум двух-трех размерностей. Так проще и понятнее, а с точки зрения профессиональности когда что-то начинает множится, значит, что-то в постановке задачи или в коде обстоит не так.
Просто, доступно и понятно
Создавая на php массив в массиве, лучше всего ограничиваться двумя-тремя уровнями. Несмотря на стабильность и надежность PHP допускает ошибки при обработке синтаксических конструкций. С этим мириться можно, имея хороший редактор кода, привыкнув точно считать скобки и запятые. Однако PHP не контролирует типы данных (это карма современного программирования) и позволяет разработчику практиковать семантические ошибки.
Правило контролировать типы переменных или собственные идеи превращения семантики в синтаксис - часто непозволительная роскошь. Это потеря скорости скрипта, читабельности кода, ... потому простота в кодировании всегда имеет существенное значение.
У PHP есть существенная отрицательная черта: при возникновении неопределенности скрипт просто зависает. Не все отладчики справляются с непредвиденными обстоятельствами, и многое зависит от опыта и интуиции разработчика. Чем проще алгоритм, чем доступнее структурирована информация, тем больше шансов найти ошибку или вовсе не допустить ее.
Характерно, что когда появились первые массивы, были предложены варианты данных в виде структур - неуклюжая попытка создать что-то из различных типов данных. Первые выжили и приобрели новый эффективный синтаксис, вторые ушли в историю.
Простые и ассоциативные массивы
Запись двумерного массива - это еще одна пара скобок "[" и "]", например: $aSrcData[1][2] означает обращение к элементу [2] массива [1], входящего в массив $aSrcData. В PHP нет требования объявлять заранее данные. Любою заявленную информацию всегда можно проверить на предмет существования.
Очень эффективно создавать что-то только тогда, когда это нужно, в том виде, в котором оно потребовалось, и уничтожать, когда в нем исчезла необходимость. Используя в качестве ключей (индексов) осмысленные имена, можно получить читабельные конструкции, осмысленные в контексте текущего места в алгоритме:
$aAnketa['name'] = 'Иванов';
$aAnketa['age'] = 42;
$aAnketa['work'] = 'Директор';
$aAnketa['active'] = true;
$aTable[] = $aAnketa;
$aAnketa['name'] = 'Петров';
$aAnketa['age'] = 34;
$aAnketa['work'] = 'Менеджер';
$aAnketa['active'] = true;
$aTable[] = $aAnketa;
$aAnketa['name'] = 'Афанасьев';
$aAnketa['age'] = 28;
$aAnketa['work'] = 'Рабочий';
$aAnketa['active'] = false;
$aTable[] = $aAnketa;
$sOne .= implode ("; ", $aTable[1]) . '<br/>'; // второй PHP-массив в строку
$sOne .= $aTable[1]['work']; // обращение к одному элементу второго массива
Результат работы этого примера (первый массив - обычный, ключи в нем начинаются с 0, второй массив - ассоциативный, в нем четыре ключа: 'name', 'age', 'work', 'active'):
$sOne = 'Петров; 34; Менеджер; 1<br/>Менеджер';
На этом простом примере можно видеть, как созданная анкета может быть применена ко всем сотрудникам. Можно создать массив сотрудников с индексами по табельным номерам и, если нужен будет конкретный сотрудник, то выбрать его по табельному номеру.
Если в организации есть подразделения, или есть сезонные рабочие, или требуется отдельно выделить работающих пенсионеров, ... конструкция "PHP-массив в массиве" очень удобна, но никогда не следует увлекаться размерностью. Два-три измерения - предел для эффективного решения.
Ключи для работы с массивами
Если раньше имело значение, как все устроено, то в последние годы традиции бинарной эпохи, когда программист хотел знать, как именно хранятся элементы массива, и желал иметь к ним прямой доступ, забылись окончательно. Появилось много кодировок символов, которые занимают в памяти далеко не один байт. Слово "бит" можно встретить теперь разве что в операциях битового поиска, но поиск в массиве PHP - это отдельная тема. Доступ к элементам может быть простым и ассоциативным. В первом случае элементы массива (имеющие любой из доступных в PHP типов) нумеруются 0, 1, 2, ... Во втором случае программист указывает собственный индекс, именуемый чаще "ключ" для доступа к нужному значению.
$aLine["фрукт"] = "апельсин"; // здесь PHP-ключ массива = "фрукт"
или (чтобы все было корректно с соблюдением кодировки страницы и кода):
$aLine[iconv ('UTF-8', 'CP1251', "фрукт")] = iconv ('UTF-8', 'CP1251', "апельсин");
При добавлении к массиву $aLine нового значения:
$aLine[] = iconv ('UTF-8', 'CP1251', 'персик');
$aLine[iconv ('UTF-8', 'CP1251', "овощ")] = iconv ('UTF-8', 'CP1251', "огурец");
$aLine[] = iconv ('UTF-8', 'CP1251', 'баклажан');
в результате выполнения цикла:
foreach ($aLine as $ck => $cv) {
$cOne .= $ck . '=' . $cv . '<br/>';
}
будет получено:
фрукт=апельсин
0=персик
овощ=огурец
1=баклажан
PHP-ключ массива при добавлении элементов 'персик' и 'баклажан' формируется последовательно от 0, а при указании его значения будет равен этому значению.
Удаление элементов из массива
Проще всего удалить элемент массива PHP в ходе его обработки. В этом случае, например, в результате исполнения цикла, исходный массив просматривается, и формируется новый, в который ненужные элементы просто не записываются.
Можно поступить проще. Если к последнему примеру применить:
unset($aLine[0]); // удалить элемент массива PHP
то результат будет:
фрукт=апельсин
овощ=огурец
1=баклажан
Вариантов манипулирования элементами массивов можно сконструировать множество. Например, используя функции: implode() и explode(), можно записать PHP-массив в строку с одним разделителем, а разобрать обратно в другой массив - по другому разделителю.
Чтобы просто на PHP удалить массив целиком, достаточно написать: unset($aLine);
Этого достаточно.
Поиск в массиве
PHP содержит специальные функции поиска array_keys(), array_values(), array_key_exists(), и in_array(), однако прежде чем решить их использовать, следует рассмотреть возможность выполнить поиск в массиве PHP собственными силами.
Любой проект есть конкретная предметная область, сконструированные массивы, особенно когда часть семантики перенесена в синтаксис и представлена набором вполне конкретных осмысленных ключей. Это позволяет выполнять собственные функции поиска, которые также можно обозначить осмысленно.
В PHP можно вызывать функции, имя которых определяется в ходе исполнения программы. Очень практичный пример из библиотеки PHPWord, которая позволяет читать и создавать документы MS Word:
$elements = array('Text', 'Inline', 'TextRun', 'Link', 'PreserveText', 'TextBreak',
'ListItem', 'ListItemRun', 'Table', 'Image', 'Object', 'Footnote',
'Endnote', 'CheckBox', 'TextBox', 'Field', 'Line');
$functions = array();
for ($i = 0; $i < count($elements); $i++) {
$functions[$i] = 'add' . $elements[$i];
}
В результате массив $functions получит значения массива $elements, то есть имена реальных функций, которые выполняют работу с реальными элементами документа.
Вызывая для $elements[4] функцию $functions[4], можно получить идеальный поиск и быстрый результат.
Сортировка элементов
Задача сортировки данных имеет важное значение, и PHP предлагает несколько функций для этого: sort(), rsort(), asort(), ksort(), ... По возрастанию и по убыванию элементов вторые две функции сохраняют отношения между ключами и значениями. Иногда имеет смысл перемешать значения массива случайным образом - shuffle().
Используя функции PHP для сортировки, не следует забывать, что элементы могут иметь не только разный тип, но и не совсем естественное содержание. В первую очередь нужно очень внимательно относиться к сортировке строк, содержащих русские буквы, сортировке даты, а также чисел, которые записаны в разных форматах.
Лучший способ написать самостоятельно идеальное решение, во всяком случае на этапе тестирования скрипта, - это ручная сортировка. Она поможет предусмотреть непредвиденные ситуации.
Строчные массивы
Благодаря функциям implode() и explode() массив можно легко трансформировать в строку и получить обратно. Это позволяет хранить данные в компактном представлении и разворачивать их в удобное состояние по мере надобности.
Массив, обращенный в строку, открывает новые возможности. Например, задача поиска ключевых слов в тексте требует того, чтобы найденное не добавлялось повторно.
$cSrcLine = 'Text Text ListItemRun TextBox ListItem TextBox Check Box CheckBox TextBox Footnote';
$aSrc = explode(' ', $cSrcLine);
$cDstLine = '';
for ($i=0; $i < count($aSrc); $i++) {
$cFind = '[' . $aSrc[$i] . ']';
if ( ! is_integer(strpos($cDstLine, $cFind))) {
$cDstLine .= $cFind;
}
}
$aDst = explode('][', $cDstLine);
$cOne = implode('; ', $aDst);
В результате переменная $cOne получит только те значения из исходной строки, которые там встречаются по одному разу: "Text; ListItemRun; TextBox; ListItem; Check; Box; CheckBox; Footnote".
Русский язык в ключах и значениях
Не рекомендуется использовать ничего, что связано с национальными кодировками, в синтаксических конструкциях. Русский язык, как и все прочие языки, символы которых выходят за пределы a-z, не будет создавать проблем, находясь в области данных, но не в синтаксисе кода. Иногда даже простая задача на PHP «вывести массив на принтер или на экран» приведет к "кракозябрам", а чаще просто остановит скрипт.
PHP - лояльный язык и терпимо относится к национальным кодировкам, но существует масса ситуаций, когда выполненный объем работ приходится делать повторно только потому, что в нужном месте и в нужное время выскочит ключевое значение, распознать которое не представится возможным.
Синтаксис PHP и окружение языка
Следует помнить, что синтаксис PHP - это одно, но конструкции этого синтаксиса «имеют дело» с другими приложениями, с операционной системой, с аппаратными опциями. Вариантов много, предусмотреть все никогда не представляется возможным.
Правило «в коде есть только код, а на входе, внутри, и на выходе есть всякая информация» поможет избежать непредвиденных неожиданностей. PHP-значение в массиве может быть «русским», но ключ на него должен быть синтаксически корректным не только с позиций данного языка, но и с позиций среды его работы.