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); 
相關問題