[英]How do I use array_filter() for functional programming in PHP?
Say I have an array of tags 说我有一系列标签
$all_tags = array('A', 'B', 'C');
And I want to create a set of URLs with $_GET variables. 我想用$ _GET变量创建一组URL。
I'd like the links to be: 我希望链接是:
'A'
linking to "index.php?x[]=B&x[]=C"
'A'
链接到"index.php?x[]=B&x[]=C"
'B'
linking to "index.php?x[]=A&x[]=C"
'B'
链接到"index.php?x[]=A&x[]=C"
etc. ($_GET is an array with all elements except for "current" element) (I know there's an easier way to implement this: I'm actually simplifying a more complex situation) 等等($ _GET是一个包含除“current”元素之外的所有元素的数组)(我知道有一种更简单的方法来实现它:我实际上是在简化更复杂的情况)
I'd like to use array_filter()
to solve this. 我想用
array_filter()
来解决这个问题。
Here's my attempt: 这是我的尝试:
function make_get ($tag) { return 'x[]=' . $tag; }
function tag_to_url ($tag_name) {
global $all_tags;
$filta = create_function('$x', 'global $all_tags; return ($x != $tag_name);');
return 'index.php?' . implode('&', array_map("make_get", array_filter($all_tags, "filta")));
}
print_r(array_map("", $all_tags));
But it doesn't work. 但它不起作用。 I have a suspicion that maybe it has to do with how maps and filters in PHP actually mutate the data structure themselves, and return a boolean, instead of using a functional style, where they don't mutate and return a new list.
我怀疑它可能与PHP中的地图和过滤器实际上如何改变数据结构本身有关,并返回一个布尔值,而不是使用功能样式,它们不会变异并返回一个新列表。
I am also interested in other ways to make this code more succinct. 我也对其他方法感兴趣,使这段代码更简洁。
Here's an alternative approach: 这是另一种方法:
// The meat of the matter
function get_link($array, $tag) {
$parts = array_reduce($array, function($result, $item) use($tag)
{
if($item != $tag) $result[] = 'x[]='.$tag;
return $result;
});
return implode('&', $parts);
}
// Test driver
$all_tags = array('A', 'B', 'C');
echo get_link($all_tags, 'A');
echo "\n";
echo get_link($all_tags, 'B');
echo "\n";
echo get_link($all_tags, 'C');
echo "\n";
It's simply one call to array_reduce
, and then an implode
to pull the results together into a query string. 它只是对
array_reduce
的一次调用,然后是将结果一起拉入查询字符串的内implode
。
Based on an answer I gave in the comments ( shown here ): 基于我在评论中给出的答案( 如下所示 ):
<?php
$all_tags = array('A', 'B', 'C');
function tag_to_url($tag_name)
{
global $all_tags;
$remaining_tags = array_diff($all_tags, array($tag_name));
return sprintf('index.php?%s',
http_build_query(array('x'=>array_values($remaining_tags))));
}
echo tag_to_url('B'); // index.php?x%5B0%5D=A&x%5B1%5D=C
// basically: index.php?x[0]=A&x[1]=C
Basically, use array_diff
to remove the entry from the array (instead of filtering), then pass it off to the http_build_query
to come up with a valid URL. 基本上,使用
array_diff
从数组中删除条目(而不是过滤),然后将其传递给http_build_query
以提供有效的URL。
I'm just going to answer the "why it doesnt work" part. 我只想回答“为什么它不起作用”的部分。
$filta = create_function('$x', 'global $all_tags; return ($x != $tag_name);');
The tag_name variable is undefined in your lambda function's scope. 在lambda函数的作用域中未定义tag_name变量。 Now, it is defined in the creating functions scope(tag_to_url).
现在,它在创建函数范围(tag_to_url) 被定义。 You can't exactly use the global keyword here either, because $tag_name isn't in the global scope, it is in the local tag_to_url scope.
您也不能在此处使用global关键字,因为$ tag_name不在全局范围内,而是在本地tag_to_url范围内。 You could declare the variable in the global scope and then it could work, but considering you're fond of functional approaches, I doubt you like global variables :)
你可以在全局范围内声明变量然后它可以工作,但考虑到你喜欢功能方法,我怀疑你喜欢全局变量:)
You could do trickery with string concatenation and var_export($tag_name) and pass that to create_function() if you wanted, but there's other better ways to achieve your goals. 您可以使用字符串连接和var_export($ tag_name)进行欺骗,并根据需要将其传递给create_function(),但还有其他更好的方法可以实现您的目标。
Also, as an aside, I'm guessing you might benefit from turning up php's error reporting level while developing. 另外,另外,我猜你可能会在开发时提高php的错误报告水平。 php would have thrown undefined variable notices at you, which helps debugging and understanding.
php会向你抛出未定义的变量通知,这有助于调试和理解。
// ideally set these in php.ini instead of in the script
error_reporting(E_ALL);
ini_set('display_errors', 1);
Something approaching real support for functional programming styles in PHP is very, very new--it was only in PHP 5.3 that functions became first class and anonymous functions were possible. 接近真正支持PHP中的函数式编程风格的东西非常非常新 - 只有在PHP 5.3中,函数才能成为一流的,并且匿名函数是可能的。
BTW, you should never use create_function()
. 顺便说一句,你永远不应该使用
create_function()
。 What it really does is define a new function in the global namespace (which will never be garbage-collected!), and it uses eval()
behind the scenes. 它真正做的是在全局命名空间中定义一个新函数( 永远不会被垃圾收集!),它在幕后使用
eval()
。
If you have PHP 5.3 or greater, you can do this: 如果你有PHP 5.3或更高版本,你可以这样做:
$all_tags = array('A', 'B', 'C');
function is_not_equal($a, $b) {
return $a != $b;
}
function array_filter_tagname($alltags, $name) {
$isNotEqualName = function($item) use ($name){
return is_not_equal($item, $name);
};
// array_merge() is ONLY to rekey integer keys sequentially.
// array_filter() preserves keys.
return array_merge(array_filter($alltags, $isNotEqualName));
}
function make_url($arr) {
return 'input.php?'.http_build_query(array('x'=>$arr));
}
$res = array_filter_tagname($all_tags, 'B');
print_r($res);
print_r(make_url($res));
If you have a PHP < 5.3, you should use a class+object for your closures instead of create_function()
. 如果PHP <5.3,则应该使用类+对象作为闭包而不是
create_function()
。
class NotEqualName {
protected $otheritem;
function __construct($otheritem) { // with PHP 4, use "function NotEqualName($otheritem) {"
$this->otheritem = $otheritem;
}
function compare($item) {
return $item != $this->otheritem;
}
}
function array_filter_tagname_objectcallback($alltags, $name) {
$isNotEqualName = new NotEqualName($name);
return array_merge(array_filter($alltags, array($isNotEqualName,'compare')));
}
In general, however, PHP is not very well suited to a functional style, and for your particular task using array_filter()
is not very idiomatic PHP. 但是,一般情况下,PHP并不是很适合功能样式,对于使用
array_filter()
特定任务而言,PHP并不是非常惯用的。 array_diff()
is a better approach. array_diff()
是一种更好的方法。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.