3

说我有标签如何在PHP中使用array_filter()进行函数式编程?

$all_tags = array('A', 'B', 'C'); 

一个数组,我想创建一个$ _GET变量URL集。
我想的链接是:
'A'链接到"index.php?x[]=B&x[]=C"
'B'链接到"index.php?x[]=A&x[]=C"
等($ _ GET是除了“当前”元素中的所有元素的数组) (我知道有一个更简单方式来实现这一点:我实际上是简化更复杂的情况)

我想使用array_filter()来解决这个问题。
这里是我的尝试:

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

但它不工作。我怀疑它可能与PHP中的映射和过滤器实际上是如何改变数据结构本身有关,并且返回一个布尔值,而不是使用函数式样,它们不会改变并返回一个新列表。

我也对其他方法使这段代码更简洁。

+0

so ...无论链接是什么,从链接集合中删除该特定条目,然后用剩余的值构建URL? –

+0

也许这样:http://www.ideone.com/vVnWe? –

+0

@BradChristie:正确 – amindfv

回答

1

东西在PHP接近函数式编程风格真正的支持是非常,非常新的 - 这是只有在PHP 5.3,其功能成为第一类和匿名函数是可能的。

顺便说一句,你不应该使用create_function()。它真正的作用是在全局命名空间中定义一个新函数(这将使从不被垃圾收集!),并在幕后使用eval()。如果你有一个PHP < 5.3,你应该使用一个类+对象为你关闭,而不是create_function()

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

如果你有PHP 5.3或更高版本,你可以做到这一点。

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'))); 
} 

但一般情况下,PHP是不是很适合于实用的风格,以及使用array_filter()不是很地道的PHP你的特定任务。 array_diff()是一个更好的方法。

1

基于一个答案我评价得到(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 

基本上,使用array_diff以除去从阵列的条目(而不是滤波),然后将其传递到http_build_query来使用有效的网址。

+0

对于一个非常好的方法+1。我真诚地希望你在那里没有使用过全球。 :) – Jon

+0

@Jon:与OP给我的工作。 ;-) –

2

这里的另一种方法:

// 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"; 

它只是一个呼叫array_reduce,然后一个implode的结果一起拉成一个查询字符串。

+0

+1无副作用。仍渴望与map(“x [] =”++)(filter(/ = tag_name)all_tags)一样短的答案'tho :) – amindfv

1

我只是要回答“为什么它不工作”的一部分。

$filta = create_function('$x', 'global $all_tags; return ($x != $tag_name);'); 

tag_name变量在您的lambda函数的作用域中未定义。现在,它在创建函数范围(tag_to_url)中定义的。您无法在此处完全使用全局关键字,因为$ tag_name不在全局范围内,而是位于本地tag_to_url范围内。你可以在全局范围声明变量,然后它可以工作,但考虑到你喜欢功能方法,我怀疑你喜欢全局变量:)

你可以做字符串连接和var_export($ tag_name)并将其传递给create_function(),但还有其他更好的方法来实现您的目标。另外,我猜你可能会从开发php的错误报告级别中受益。 PHP会在你身上发出未定义的变量通知,这有助于调试和理解。

// ideally set these in php.ini instead of in the script 
error_reporting(E_ALL); 
ini_set('display_errors', 1); 
相关问题