簡體   English   中英

過濾數組和中斷引用的簡潔、慣用的方法?

[英]Concise, idiomatic way to filter an array and break references?

今天我了解到 array_filter 保留了array_filter中的引用:

$str = 'original';
$refArray = [&$str];
$filtered = array_filter($refArray, fn () => true);
$filtered[0] = 'MODIFIED';
echo $str;  // prints MODIFIED

3v4l

我正在尋找一種干凈、簡潔、慣用的方式來過濾數組,從而產生可以安全修改的結果,即。 echo $str將打印original

循環遍歷數組似乎有效: $value賦值刪除了引用。 雖然它並不簡潔(6 行對 1 行),並且需要注釋來解釋為什么使用這種方法:

$filtered = [];
foreach ($refArray as $key => $value) {
    if (true /*your filter here*/) {
        $filtered[$key] = $value;
    }
}
$filtered[0] = 'MODIFIED';
echo $str;  // prints original

我嘗試使用array_combine復制輸入數組,但顯然它也保留了引用以及array_values

$copy = array_combine(array_keys($refArray), array_values($refArray));
$filtered = array_filter($copy, fn () => true);
$filtered[0] = 'MODIFIED';
echo $str;  // prints MODIFIED

如果你有一個引用數組,作為一種解決方法,你可以使用 array_map (它將返回相同數量的項目)

讀取array_filter

遍歷數組中的每個值,將它們傳遞給回調 function。 如果回調 function 返回 true,則將數組中的當前值返回到結果數組中。

讀取array_map

返回一個數組,其中包含將回調應用於數組的相應索引的結果

對此進行測試時(在 PHP 7.4.3 上),似乎在使用 array_filter 並且回調返回 true 時,返回了當前值(引用)。 對於array_map,引用在回調中使用並返回它引用的值。

例如

$str = 'original';
$refArray = [&$str];
$refArray[0] = 'MODIFIED';
echo $str;  // prints MODIFIED

$str2 = 'original2';
$refArray2 = [&$str2];
$refArray2 = array_filter($refArray2, fn() => true);
$refArray2[0] = 'MODIFIED';
echo $str2;  // prints MODIFIED

$str3 = 'original3';
$refArray3 = [&$str3];
$refArray3 = array_map(fn($x) => $x, $refArray3);
$refArray3[0] = 'MODIFIED';
echo $str3;  // prints original3

$str4 = ['original4'];
$refArray4 = [&$str4];
$refArray4 = array_map(fn($x) => $x, $refArray4);
$refArray4[0][0] = 'MODIFIED';
var_dump($str4);  
// gives
//array(1) {
//  [0]=>
//  string(9) "original4"
//} 

$refArray是引用數組,而不是值,因此array_filter返回您傳入的相同元素 - 引用。

IMO 從一開始就是錯誤的假設,但不知道您的上下文。

您唯一的解決方案是使用基於 refs 數組的值創建新數組。

您可以像以前一樣通過循環或僅翻轉數組兩次來實現這一點,因為數組鍵不能被引用。

  • 它僅適用於原語
  • 僅當您在數組中有唯一值時它才有效

例子:

$str = 'original';
$refArray = [&$str];
$filtered = array_filter(array_flip(array_flip($refArray)), fn () => true);
$filtered[0] = 'MODIFIED';
echo $str;  // prints original

我不會稱之為解決方案,而是骯臟的解決方法。

lstrojny/functional-phpselect()或其別名filter()應該可以完成這項工作,因為它在內部使用循環

它是array_filter的替代品:

use function Functional\filter;
$filtered = filter($refArray, fn () => true);

序列化也刪除了引用,盡管它會更加占用資源並且如果為數組值實現魔術方法可能會產生額外的副作用:

$copy = unserialize(serialize($refArray));
$filtered = array_filter($copy, fn () => true);

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM