Программирование - это синтаксис и семантика. Первое определяется правилами языка, второе - опытом разработчика. В отношении массивов разработчик может предметно нагрузить синтаксис семантикой. Это еще не объект, но уже не массив в традиционном понимании. PHP дает возможность создавать массивы из переменных различных типов, включая самих себя. Элементом массива может быть функция, то есть возможность нагрузить массив реальным алгоритмом, реальным смыслом.
Видео: Массивы - Основы PHP | Урок #8
Синтаксис стабилен, но меняется от версии к версии и не всегда может быть совместимым даже снизу вверх. Переносимость программ - хорошо забытое достижение прошлого века. Семантика развивается и всегда может быть применена не только в любой версии любого языка- стало традицией использовать синтаксические конструкции для выражения того, что правилами языка даже предусмотрено не было. На примере массивов это можно понять наиболее просто.
Конструирование массивов
Массив в 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` => `ZendMvcRouterHttpLiteral`,
`options` => array(`route` => `/sayhello`, `defaults` => array(
`controller` => `HelloworldControllerIndex`, `action` => `index`,))))),
`controllers` => array(`invokables` => array(
`HelloworldControllerIndex` => `HelloworldControllerIndexController`))
)-
Это образец практики «PHP-массив в массиве» от ZF 2. Не слишком вдохновляет поначалу, но это работает и, возможно, делает данный фреймворк успешным (пример из модуля ZendSkeletonApplication/module/Helloworld/config/module.config.php).
Массив - важная конструкция данных в ходе проектирования и разработки. Его многомерный вариант когда-то был популярен, но с течением времени осталась потребность в массивах максимум двух-трех размерностей. Так проще и понятнее, а с точки зрения профессиональности когда что-то начинает множится, значит, что-то в постановке задачи или в коде обстоит не так.
Видео: Изучаем PHP | Урок №16 - Двумерные массивы
Просто, доступно и понятно
Создавая на 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]) . `
`- // второй PHP-массив в строку
$sOne .= $aTable[1][`work`]- // обращение к одному элементу второго массива
Результат работы этого примера (первый массив - обычный, ключи в нем начинаются с 0, второй массив - ассоциативный, в нем четыре ключа: `name`, `age`, `work`, `active`):
$sOne = `Петров- 34- Менеджер- 1
Менеджер`-
На этом простом примере можно видеть, как созданная анкета может быть применена ко всем сотрудникам. Можно создать массив сотрудников с индексами по табельным номерам и, если нужен будет конкретный сотрудник, то выбрать его по табельному номеру.
Если в организации есть подразделения, или есть сезонные рабочие, или требуется отдельно выделить работающих пенсионеров, ... конструкция "PHP-массив в массиве" очень удобна, но никогда не следует увлекаться размерностью. Два-три измерения - предел для эффективного решения.
Ключи для работы с массивами
Если раньше имело значение, как все устроено, то в последние годы традиции бинарной эпохи, когда программист хотел знать, как именно хранятся элементы массива, и желал иметь к ним прямой доступ, забылись окончательно. Появилось много кодировок символов, которые занимают в памяти далеко не один байт. Слово "бит" можно встретить теперь разве что в операциях битового поиска, но поиск в массиве PHP - это отдельная тема. Доступ к элементам может быть простым и ассоциативным. В первом случае элементы массива (имеющие любой из доступных в PHP типов) нумеруются 0, 1, 2, ... Во втором случае программист указывает собственный индекс, именуемый чаще "ключ" для доступа к нужному значению.
$aLine["фрукт"] = "апельсин"- // здесь PHP-ключ массива = "фрукт"
или (чтобы все было корректно с соблюдением кодировки страницы и кода):
$aLine[iconv (`cp1251`, `CP1251`, "фрукт")] = iconv (`cp1251`, `CP1251`, "апельсин")-
При добавлении к массиву $aLine нового значения:
$aLine[] = iconv (`cp1251`, `CP1251`, `персик`)-
$aLine[iconv (`cp1251`, `CP1251`, "овощ")] = iconv (`cp1251`, `CP1251`, "огурец")-
$aLine[] = iconv (`cp1251`, `CP1251`, `баклажан`)-
в результате выполнения цикла:
foreach ($aLine as $ck => $cv) {
$cOne .= $ck . `=` . $cv . `
`-
}
будет получено:
фрукт=апельсин
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-значение в массиве может быть «русским», но ключ на него должен быть синтаксически корректным не только с позиций данного языка, но и с позиций среды его работы.