Использование обратного вызова в implode()

У меня есть многомерный массив, например:

$values = array(
    'one' => array(
        'title' => 'Title One',
        'uri'   => 'http://example.com/one',
    ),
    'two' => array(
        'title' => 'Title Two',
        'uri'   => 'http://example.com/two',
    ),
);

... и я хотел бы проанализировать это с закрытием в моей функции implode, à la:

$final_string = implode(' | ', function($values) {
    $return = array();

    foreach($values as $value)
        $return[] = '<a href="' . $value['uri'] . '">' . $value['title'] . '</a>';

    return $return;
});

Однако это использование приводит к ошибке Invalid arguments passed. Есть ли синтаксис, который мне не хватает, что сделает возможным использование закрытия? Я использую PHP v5.3.16.

Ответ 1

Ответ Ashwin правильный. Здесь почему:

Когда вы передаете закрытие непосредственно методу implode, который явно хочет второй аргумент типа array, он, по существу, проверяет instanceof - следовательно, неверный аргумент. Функция implode не ожидает mixed и не знает, чтобы выполнить закрытие.

Когда вы сначала назначаете эту функцию переменной, она заставляет PHP сначала оценивать эту переменную, и она заканчивает передачу возвращаемого значения из функции в implode.

В этом случае вы возвращаете массив из функции и передаете это в implode -, который проверяет.

изменить/добавить: эта анонимная функция будет instanceof Closure.

Closure !== array

Ответ 2

Используйте array_map:

$final_string = implode(' | ', array_map(function($item) {
    return '<a href="' . $item['uri'] . '">' . $item['title'] . '</a>';
}, $values));

Я верю, что вы правильно избегаете значений как HTML в своем реальном коде.


Что касается этого, и ваш код не работает, вы передавали функцию в качестве второго аргумента в implode. Честно говоря, это мало смысла: вы можете объединить кучу строк или, может быть, даже кучу функций, но вы не можете присоединиться к одной функции вместе. Это звучит странно, особенно если вы так говорите.

Вместо этого мы сначала хотим преобразовать все элементы в массиве с помощью функции и передать результат этого в implode. Эта операция обычно называется map. К счастью, PHP предоставляет эту функцию как, ну, array_map. После того, как мы изменили элементы в массиве, мы можем присоединиться к результатам.

Ответ 3

Кажется, вам нужно назначить функцию переменной, а затем передать ее, чтобы она работала.

$fn = function($values) {
    $return = array();
    foreach($values as $value)
        $return[] = '<a href="' . $value['uri'] . '">' . $value['title'] . '</a>';
    return $return;
};
$final_string(' | ', $fn($values));
echo $final_string;

Я не уверен, в чем причина, и вам нужно будет проверить это немного глубже, чтобы у вас была правильная причина.

Вы можете увидеть код, работающий здесь

EDIT. Преобразовал этот ответ в вики сообщества, чтобы каждый мог внести свой вклад.

РЕДАКТИРОВАТЬ: Объяснение @kmfk

Когда вы передаете закрытие непосредственно методу implode, который явно хочет второй аргумент типа array, он по существу проверяет instanceof - следовательно, недопустимый аргумент. Функция implode не ожидает типа mixed и не знает, чтобы выполнить закрытие, чтобы получить array.

Когда вы сначала назначаете эту функцию переменной, она заставляет PHP сначала оценивать эту переменную, и она заканчивает передачу возвращаемого значения из функции в implode.

В этом случае вы возвращаете массив из функции и передаете это в implode -, который проверяет.

Эта анонимная функция будет instanceof Closure, а

Closure !== array

Ответ 4

Вы не можете использовать implode для того, что вы пытаетесь достичь, потому что implode принимает только array в качестве второго аргумента.

Вы можете попробовать что-то вроде этого.

$values = array(
    'one' => array(
        'title' => 'Title One',
        'uri'   => 'http://example.com/one',
    ),
    'two' => array(
        'title' => 'Title Two',
        'uri'   => 'http://example.com/two',
    ),
);

$links = array();
foreach ($values as $value) {
      $links[] = "<a href='" . $value['uri'] . "'>" . $value['title'] . "</a>";
}

$string = implode(" | ", $links);