Я думаю, что хороший способ подойти к этому "снизу вверх", т.е. определите, что делать с самыми внутренними ценностями, затем используйте эти результаты для разработки следующего уровня и так далее, пока мы не достигнем вершины. Хорошей практикой также является написание нашего кода в небольших одноцелевых, многократно используемых функциях, насколько это возможно, поэтому я буду этим заниматься.
Обратите внимание, что я предполагаю, что ваши данные в безопасности (т.е. они не были предоставлены потенциально злонамеренным пользователем). Я также предполагаю, что ключи «ime» и «opi» предназначены для соответствия «name» и «description» других массивов;)
Мы можем игнорировать самые внутренние строки, так как нам не нужно их изменять. В этом случае самой внутренней структурой, которую я вижу, являются отдельные ссылки, которые представляют собой массивы, содержащие значение «URL». Вот некоторый код для рендеринга одной ссылки:
function render_link($link) {
return "<a href='{$link['URL']}'>{$link['URL']}</a>";
}
Это уменьшило массив до строки, поэтому мы можем использовать его для удаления самого внутреннего слоя. Например:
// Input
array('URL' => "http://www.artist1.com")
// Output
"<a href='http://www.artist1.com'>http://www.artist1.com</a>"
Теперь мы перемещаем слой в массивы 'links'. Здесь нужно сделать две вещи: применить «render_link» к каждому элементу, что мы можем сделать с помощью «array_map», затем уменьшить полученный массив строк до одной строки, разделенной запятыми, что мы можем сделать с помощью «implode» функция:
function render_links($links_array) {
$rendered_links = array_map('render_link', $links_array);
return implode(', ', $rendered_links);
}
Это позволило удалить другой слой, например:
// Input
array(1 => array('URL' => "http://www.artist1.com"),
6 => array('URL' => "http://www.artist1-2.com"))
// Output
"<a href='http://www.artist1.com'>http://www.artist1.com</a>, <a href='http://www.artist1-2.com'>http://www.artist1-2.com</a>"
Теперь мы можем перейти на другой уровень к отдельному исполнителю, который представляет собой массив, содержащий «имя», «описание» и «ссылки». Мы знаем, как отображать «ссылки», поэтому мы можем свести их к одной строке, разделенной переносами строк:
function render_artist($artist) {
// Replace the artist's links with a rendered version
$artist['links'] = render_links($artist['links']);
// Render this artist's details on separate lines
return implode("\n<br />\n", $artist);
}
Это позволило удалить другой слой, например:
// Input
array('name' => 'ARTIST 1',
'description' => 'artist 1 desc',
'links' => array(
1 => array(
'URL' => 'http://www.artist1.com')
6 => array(
'URL' => 'http://www.artist1-2.com')))
// Output
"ARTIST 1
<br />
artist 1 desc
<br />
<a href='http://www.artist1.com'>http://www.artist1.com</a>, <a href='http://www.artist1-2.com'>http://www.artist1-2.com</a>"
Теперь мы можем переместить слой в массивы 'художников'. Точно так же, как когда мы переходили от одной ссылки к массиву 'links', мы можем использовать array_map для обработки содержимого и взрыва, чтобы объединить их вместе:
function render_artists($artists) {
$rendered = array_map('render_artist', $artists);
return implode("\n<br /><br />\n", $rendered);
}
Это удалило еще один слой (без примера, потому что он становится слишком длинным;))
Далее у нас есть событие, которое мы можем выполнить так же, как мы делали для художника, хотя я также удалю идентификационный номер и отформатирую заголовок:
function render_event($event) {
unset($event['eventID']);
$event['eventTitle'] = "<strong>{$event['eventTitle']}</strong>";
$event['artists'] = render_artists($event['artists']);
return implode("\n<br />\n", $event);
}
Теперь мы достигли внешнего массива, который является массивом событий. Мы можем справиться с этим так же, как мы это делали для массивов художников:
function render_events($events) {
$rendered = array_map('render_event', $events);
return implode("\n<br /><br />--<br /><br />", $rendered);
}
Возможно, вы захотите на этом остановиться, поскольку передача массива в render_events вернет вам нужный HTML-код:
echo render_events($my_data);
Однако, если мы хотим больше проблем, мы можем попытаться реорганизовать код, который мы только что написали, чтобы он был менее избыточным и более пригодным для повторного использования. Один простой шаг - избавиться от render_links, render_artists и render_events, так как все они являются вариациями более общего шаблона:
function reduce_with($renderer, $separator, $array) {
return implode($separator, array_map($renderer, $array));
}
function render_artist($artist) {
$artist['links'] = reduce_with('render_link', ', ', $artist['links']);
return implode("\n<br />\n", $artist);
}
function render_event($event) {
unset($event['eventID']);
$event['eventTitle'] = "<strong>{$event['eventTitle']}</strong>";
$event['artists'] = reduce_with('render_artist',
"\n<br /><br />\n",
$event['artists']);
return implode("\n<br />\n", $event);
}
echo reduce_with('render_event', "\n<br /><br />--<br /><br />", $my_data);
Если это часть более крупного приложения, мы можем захотеть выявить некоторые более общие закономерности. Это делает код немного более сложным, но гораздо более пригодным для повторного использования. Вот несколько образцов, которые я заметил:
// Re-usable library code
// Partial application: apply some arguments now, the rest later
function papply() {
$args1 = func_get_args();
return function() use ($args1) {
return call_user_func_array(
'call_user_func',
array_merge($args1, func_get_args()));
};
}
// Function composition: chain functions together like a(b(c(...)))
function compose() {
$funcs = array_reverse(func_get_args());
$first = array_shift($funcs);
return function() use ($funcs, $first) {
return array_reduce($funcs,
function($x, $f) { return $f($x); },
call_user_func_array($first, func_get_args()));
};
}
// Transform or remove a particular element in an array
function change_elem($key, $func, $array) {
if is_null($func) unset($array[$key]);
else $array[$key] = $func($array[$key]);
return $array;
}
// Transform all elements then implode together
function reduce_with($renderer, $separator) {
return compose(papply('implode', $separator),
papply('array_map', $renderer));
}
// Wrap in HTML
function tag($tag, $text) {
return "<{$tag}>{$text}</{$tag}>";
}
// Problem-specific code
function render_link($link) {
return "<a href='{$link['URL']}'>{$link['URL']}</a>";
}
$render_artist = compose(
papply('implode', "\n<br />\n"),
papply('change_elem', 'links', papply('reduce_with',
'render_link',
', '));
$render_event = compose(
papply('implode', "\n<br />\n"),
papply('change_elem', null, 'eventID'),
papply('change_elem', 'eventTitle', papply('tag', 'strong')),
papply('change_elem', 'artists', papply('reduce_with',
$render_artist,
"\n<br /><br />\n")));
echo reduce_with($render_event, "\n<br /><br />--<br /><br />", $my_data);