Using a callback in implode()

2019-04-05 03:33发布

I have a multidimensional array, e.g.:

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

...and I'd like to parse through that with a closure in my implode function, à la:

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

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

    return $return;
});

However, this usage yields an Invalid arguments passed error. Is there syntax that I'm missing which will make this use of closures possible? I'm using PHP v5.3.16.

标签: php closures
5条回答
该账号已被封号
2楼-- · 2019-04-05 03:51

Ashwin's answer is correct. Here's why:

When you pass the closure directly to the implode method - which explicitly wants a second argument of type array, it essentially checks the instanceof - hence the invalid argument. The implode function does not expect mixed and doesn't know to execute the closure.

When you first assign that function to a variable, it causes PHP to first evaluate that variable and it ends up passing the returned value from the function into implode.

In that case you're returning an array from the function and passing that into implode - that checks out.

edit/adding: that anonymous function would be instanceof Closure.

Closure !== array
查看更多
Juvenile、少年°
3楼-- · 2019-04-05 03:53

Use array_map:

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

I trust you'll properly escape the values as HTML in your real code.


As to why this works and your code doesn't, you were passing a function as the second argument to implode. Frankly, that makes little sense: you can join a bunch of strings together, or maybe even a bunch of functions, but you can't join a single function together. It sounds strange, especially if you word it that way.

Instead, we first want to transform all of the items in an array using a function and pass the result of that into implode. This operation is most commonly called map. Luckily, PHP provides this function as, well, array_map. After we've transformed the items in the array, we can join the results.

查看更多
干净又极端
4楼-- · 2019-04-05 03:56

You can't use implode to what your trying to achieve, because implode only accept an array as the second argument.

You can try something like this.

$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);
查看更多
放我归山
5楼-- · 2019-04-05 03:58

It seems that you need to assign the function to a variable, and then pass it through to make it work.

$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;

I am not sure what the reason is, though, and will need to check it in a little more depth to be able to give you a proper reason.

You can see the code working here

EDIT : Converted this answer to a community wiki so that everyone can contribute here.

EDIT : Explanation by @kmfk

When you pass the closure directly to the implode method - which explicitly wants a second argument of type array, it essentially checks the instanceof - hence the invalid argument. The implode function does not expect mixed type and doesn't know to execute the closure to get an array.

When you first assign that function to a variable, it causes PHP to first evaluate that variable and it ends up passing the returned value from the function into implode.

In that case you're returning an array from the function and passing that into implode - that checks out.

That anonymous function would be instanceof Closure, and

Closure !== array
查看更多
时光不老,我们不散
6楼-- · 2019-04-05 04:10
function implode_callback( $array, $separator = '', $callback = false )
{
    return implode(
                    $separator,

                    $callback === false ?
                      $array : array_map( $callback, $array )
                  );
}

Example use:

$tab = array( 1, 2, 3 );

echo implode_callback( $tab, '<hr>', function($x) { return "<p>$x</p>"; } );

See example code

查看更多
登录 后发表回答