PHP array_filter() 過濾陣列

array_filter() 函數用來過濾陣列中的元素,保留符合條件的元素。

基本用法

<?php
$numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];

$evens = array_filter($numbers, fn($n) => $n % 2 === 0);

print_r($evens);
// [1 => 2, 3 => 4, 5 => 6, 7 => 8, 9 => 10]
// 注意:鍵會被保留
?>

語法

array_filter(array $array, ?callable $callback = null, int $mode = 0): array
  • $array:要過濾的陣列
  • $callback:過濾函數,回傳 true 保留元素
  • $mode:決定傳入回呼的參數
  • 回傳值:過濾後的陣列(保留原鍵)

不帶回呼函數

不帶回呼函數時,會過濾掉所有「假值」:

<?php
$arr = [0, 1, '', 'hello', null, false, [], [1, 2]];

$filtered = array_filter($arr);

print_r($filtered);
// [1 => 1, 3 => 'hello', 7 => [1, 2]]
?>

被過濾掉的假值:

  • false
  • 00.0
  • ''(空字串)
  • '0'(字串零)
  • [](空陣列)
  • null

過濾模式

ARRAY_FILTER_USE_KEY

只傳入鍵到回呼函數:

<?php
$arr = ['a' => 1, 'b' => 2, 'c' => 3, 'd' => 4];

$filtered = array_filter($arr, fn($key) => $key !== 'b', ARRAY_FILTER_USE_KEY);

print_r($filtered);
// ['a' => 1, 'c' => 3, 'd' => 4]
?>

ARRAY_FILTER_USE_BOTH

同時傳入值和鍵到回呼函數:

<?php
$arr = ['a' => 1, 'b' => 2, 'c' => 3, 'd' => 4];

$filtered = array_filter(
    $arr,
    fn($value, $key) => $key !== 'b' && $value > 1,
    ARRAY_FILTER_USE_BOTH
);

print_r($filtered);
// ['c' => 3, 'd' => 4]
?>

重新索引

array_filter() 會保留原本的鍵,如果需要重新索引:

<?php
$numbers = [1, 2, 3, 4, 5];

$filtered = array_filter($numbers, fn($n) => $n > 2);
print_r($filtered);
// [2 => 3, 3 => 4, 4 => 5]

// 重新索引
$reindexed = array_values($filtered);
print_r($reindexed);
// [0 => 3, 1 => 4, 2 => 5]
?>

常見應用

過濾空值

<?php
$data = ['Alice', '', 'Bob', null, 'Charlie', '   '];

// 過濾假值
$filtered = array_filter($data);

// 過濾空白字串
$filtered = array_filter($data, fn($v) => trim($v ?? '') !== '');

print_r($filtered);  // ['Alice', 'Bob', 'Charlie']
?>

過濾數字範圍

<?php
$numbers = [5, 12, 8, 130, 44, 3, 67];

// 大於 10
$large = array_filter($numbers, fn($n) => $n > 10);

// 範圍內
$range = array_filter($numbers, fn($n) => $n >= 10 && $n <= 100);

print_r($range);  // [12, 44, 67]
?>

過濾物件/關聯陣列

<?php
$users = [
    ['name' => 'Alice', 'age' => 25, 'active' => true],
    ['name' => 'Bob', 'age' => 30, 'active' => false],
    ['name' => 'Charlie', 'age' => 35, 'active' => true],
];

// 過濾活躍使用者
$active = array_filter($users, fn($u) => $u['active']);

// 過濾年齡大於 28
$older = array_filter($users, fn($u) => $u['age'] > 28);

print_r($active);
?>

過濾檔案類型

<?php
$files = ['doc.pdf', 'image.jpg', 'data.json', 'photo.png', 'text.txt'];

// 只保留圖片
$images = array_filter($files, function($file) {
    $ext = pathinfo($file, PATHINFO_EXTENSION);
    return in_array($ext, ['jpg', 'png', 'gif', 'webp']);
});

print_r($images);  // ['image.jpg', 'photo.png']
?>

搜尋過濾

<?php
$products = [
    ['name' => 'iPhone', 'category' => 'Electronics', 'price' => 999],
    ['name' => 'T-Shirt', 'category' => 'Clothing', 'price' => 29],
    ['name' => 'MacBook', 'category' => 'Electronics', 'price' => 1999],
    ['name' => 'Jeans', 'category' => 'Clothing', 'price' => 59],
];

// 多條件過濾
$filtered = array_filter($products, function($p) {
    return $p['category'] === 'Electronics' && $p['price'] < 1500;
});

print_r($filtered);
// [['name' => 'iPhone', ...]]
?>

去除重複(自訂邏輯)

<?php
$users = [
    ['id' => 1, 'name' => 'Alice'],
    ['id' => 2, 'name' => 'Bob'],
    ['id' => 1, 'name' => 'Alice Duplicate'],  // 重複 ID
];

$seen = [];
$unique = array_filter($users, function($user) use (&$seen) {
    if (in_array($user['id'], $seen)) {
        return false;
    }
    $seen[] = $user['id'];
    return true;
});

print_r($unique);
?>

array_filter vs foreach

<?php
$numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];

// 使用 array_filter
$evens = array_filter($numbers, fn($n) => $n % 2 === 0);

// 使用 foreach
$evens = [];
foreach ($numbers as $key => $n) {
    if ($n % 2 === 0) {
        $evens[$key] = $n;
    }
}

// 兩者結果相同
?>

組合使用

<?php
$users = [
    ['name' => 'alice', 'age' => 25],
    ['name' => 'bob', 'age' => 17],
    ['name' => 'charlie', 'age' => 30],
];

// 過濾成年人並格式化名稱
$adults = array_values(
    array_map(
        fn($u) => [...$u, 'name' => ucfirst($u['name'])],
        array_filter($users, fn($u) => $u['age'] >= 18)
    )
);

print_r($adults);
// [
//     ['name' => 'Alice', 'age' => 25],
//     ['name' => 'Charlie', 'age' => 30]
// ]
?>

效能考量

<?php
// 大量資料時,考慮使用生成器
function filterLarge(array $arr, callable $callback): Generator {
    foreach ($arr as $key => $value) {
        if ($callback($value, $key)) {
            yield $key => $value;
        }
    }
}

$large = range(1, 1000000);
$filtered = filterLarge($large, fn($n) => $n % 2 === 0);

// 逐一處理,不會一次載入所有結果
foreach ($filtered as $value) {
    // ...
}
?>

注意事項

<?php
// array_filter 回傳新陣列,不修改原陣列
$arr = [1, 2, 3, 4, 5];
$filtered = array_filter($arr, fn($n) => $n > 2);

print_r($arr);       // [1, 2, 3, 4, 5](不變)
print_r($filtered);  // [2 => 3, 3 => 4, 4 => 5]

// 回呼函數應該回傳布林值
$arr = [1, 2, 3];
$result = array_filter($arr, fn($n) => $n);  // 非布林值會被轉換
?>