Using a callback in implode()

隐身守侯 提交于 2019-12-12 08:23:50

问题


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.


回答1:


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



回答2:


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.




回答3:


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



回答4:


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:


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



来源:https://stackoverflow.com/questions/17311099/using-a-callback-in-implode

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!