可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
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