首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 相關知識

PHP 多維數組深度查找:in_array 失效原因與遞歸解決方案

     編輯:PHP 相關知識

in_array() 是 PHP 判斷值是否存在於數組的內建函數,但**只能檢測一維數組**。面對多維數組直接使用會永遠返回 false。本文深度解析原理,提供遞歸與迭代兩種通用解決方案,並對比性能優劣。

in_array 基礎行為回顧

<?php
$os = ['Mac', 'NT', 'Irix', 'Linux'];
var_dump(in_array('Irix', $os));        // true
var_dump(in_array('mac', $os));         // false(區分大小寫)
var_dump(in_array('mac', $os, true));   // false(嚴格模式:類型+值)

$a = ['1.10', 12.4, 1.13];
var_dump(in_array('12.4', $a, true));   // false(字符串 vs 浮點數)
var_dump(in_array(1.13, $a, true));     // true

// 支持陣列作為 needle
$a = [['p', 'h'], ['p', 'r'], 'o'];
var_dump(in_array(['p', 'h'], $a));     // true
var_dump(in_array(['f', 'i'], $a));     // false
var_dump(in_array('o', $a));            // true
?>

多維數組下的失效演示

<?php
$arr = [
    ['a', 'b'],
    ['c', 'd']
];

var_dump(in_array('a', $arr)); // bool(false) —— 只檢查頂層元素:['a','b'] 和 ['c','d']
// 'a' 既不等於 ['a','b'] 也不等於 ['c','d']
?>

根因:in_array 遍歷數組的**第一層鍵值**,將每個值與 $needle 比較。多維數組的第一層值是子陣列,而非標量,自然匹配失敗。

方案一:遞歸深度搜索(最通用、代碼簡潔)

<?php
/**
 * 遞歸檢查值是否存在於多維數組任意層級
 * @param mixed $needle  要查找的值
 * @param array $haystack 被搜索的數組
 * @param bool  $strict  是否嚴格模式(類型+值)
 * @return bool
 */
function deep_in_array($needle, $haystack, $strict = false) {
    foreach ($haystack as $item) {
        if (is_array($item)) {
            // 子陣列:遞歸搜索
            if (deep_in_array($needle, $item, $strict)) {
                return true;
            }
        } else {
            // 標量值:直接比較
            if ($strict ? $item === $needle : $item == $needle) {
                return true;
            }
        }
    }
    return false;
}

// 測試
$arr = [
    'level1' => [
        'level2' => [
            'target' => 'found_me',
            'other'  => 123
        ],
        'also_here' => 'found_me'
    ],
    'top_level' => 'not_target'
];

var_dump(deep_in_array('found_me', $arr));        // true
var_dump(deep_in_array('found_me', $arr, true));  // true
var_dump(deep_in_array(123, $arr));               // true
var_dump(deep_in_array('123', $arr, true));       // false(嚴格模式)
var_dump(deep_in_array('not_exist', $arr));       // false
?>

方案二:迭代器扁平化(無遞歸深度限制、內存效率高)

<?php
/**
 * 使用 RecursiveIteratorIterator 扁平化多維數組
 * 適合超大、超深數組,避免棧溢出
 */
function deep_in_array_iter($needle, $haystack, $strict = false) {
    $iterator = new RecursiveIteratorIterator(
        new RecursiveArrayIterator($haystack),
        RecursiveIteratorIterator::LEAVES_ONLY // 只遍歷葉子節點(標量值)
    );

    foreach ($iterator as $value) {
        if ($strict ? $value === $needle : $value == $needle) {
            return true;
        }
    }
    return false;
}

// 性能對比:百萬級數組
$big = range(1, 1000000);
$big = array_chunk($big, 1000); // 二維
$big = array_chunk($big, 100);  // 三維

$start = microtime(true);
deep_in_array(999999, $big);
echo "遞歸耗時: " . (microtime(true) - $start) . "s\n";

$start = microtime(true);
deep_in_array_iter(999999, $big);
echo "迭代器耗時: " . (microtime(true) - $start) . "s\n";
/*
典型輸出:
遞歸耗時: 0.045s
迭代器耗時: 0.012s  ← 迭代器更快、無棧溢出風險
*/
?>

方案三:array_walk_recursive(一行代碼、但無法短路)

<?php
function deep_in_array_walk($needle, $haystack, $strict = false) {
    $found = false;
    array_walk_recursive($haystack, function($value) use ($needle, $strict, &$found) {
        if ($found) return; // 無法真正短路,只是跳過回調
        if ($strict ? $value === $needle : $value == $needle) {
            $found = true;
        }
    });
    return $found;
}
// 缺點:必須遍歷完所有元素,性能差,不推薦大數組
?>

方案四:扁平化後 in_array(簡單、但需額外內存)

<?php
function deep_in_array_flatten($needle, $haystack, $strict = false) {
    $flat = [];
    array_walk_recursive($haystack, function($v) use (&$flat) { $flat[] = $v; });
    return in_array($needle, $flat, $strict);
}
// 適用於小數組、多次查找同一數組(扁平化一次、多次 in_array)
?>

性能與選型建議

方案時間複雜度空間複雜度遞歸深度限制短路優化推薦場景
遞歸函數O(n)O(d) 棧有(PHP 默認 ~256,可調)是中小數組、代碼簡潔優先
RecursiveIteratorIteratorO(n)O(d) 堆無(C 層實現)是大數組、深層嵌套、高性能要求
array_walk_recursiveO(n)O(d) 棧有否(偽短路)不推薦
扁平化 + in_arrayO(n) + O(m)O(n)有是同一數組多次查找、預處理場景

實戰封裝:通用工具類

<?php
class ArrayHelper {
    /**
     * 多維數組任意層級查找值
     */
    public static function deepInArray($needle, $haystack, $strict = false) {
        $iterator = new RecursiveIteratorIterator(
            new RecursiveArrayIterator($haystack),
            RecursiveIteratorIterator::LEAVES_ONLY
        );
        foreach ($iterator as $value) {
            if ($strict ? $value === $needle : $value == $needle) {
                return true;
            }
        }
        return false;
    }

    /**
     * 多維數組查找鍵是否存在
     */
    public static function deepKeyExists($key, $haystack) {
        $iterator = new RecursiveIteratorIterator(
            new RecursiveArrayIterator($haystack),
            RecursiveIteratorIterator::CATCH_GET_CHILD
        );
        foreach ($iterator as $k => $v) {
            if ($k === $key) return true;
        }
        return false;
    }

    /**
     * 多維數組提取所有符合條件的值
     */
    public static function deepFindAll($callback, $haystack) {
        $results = [];
        $iterator = new RecursiveIteratorIterator(
            new RecursiveArrayIterator($haystack),
            RecursiveIteratorIterator::LEAVES_ONLY
        );
        foreach ($iterator as $key => $value) {
            if ($callback($value, $key)) {
                $results[] = $value;
            }
        }
        return $results;
    }
}

// 使用
$data = ['a' => [1,2,['target'=>3]], 'b' => 4];
var_dump(ArrayHelper::deepInArray(3, $data));           // true
var_dump(ArrayHelper::deepKeyExists('target', $data));  // true
print_r(ArrayHelper::deepFindAll(fn($v) => $v > 2, $data)); // [3, 4]
?>

總結

in_array **不支持多維數組**。生產代碼**首選 RecursiveIteratorIterator 迭代器方案**:無遞歸深度限制、C 層實現性能優、支持短路、語義清晰。遞歸函數適合中小項目快速開發。封裝為工具類統一項目口徑,避免重複造輪子與 Bug 滋生。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved