在 WordPress 中如何查找数组元素?从 PHP 的 array_find 到 wpjam_find

在 PHP 8.4 之前,如果你想在数组里找到第一个满足条件的元素,要么写个 foreach 加 break:

$found = null;

foreach($arr as $v){
    if($v > 10){
        $found = $v;
        break;
    }
}

要么先 array_filter 再取第一个:

$filtered = array_filter($arr, fn($v) => $v > 10);
$found    = reset($filtered);

前者啰嗦,后者不短路还会额外分配数组,性能和优雅度都不够。如果想找数字索引,还得再套一层:

$index = array_search($key, array_keys($arr));

代码越写越长,语义越来越模糊。

array_find 和 array_find_key

到了 PHP 8.4,终于补上了这两块拼图:

// 找第一个满足条件的值
$value = array_find($arr, fn($v) => $v > 10);

// 找第一个满足条件的键
$key = array_find_key($arr, fn($v) => $v > 10);

PHP 7 用户注意:WPJAM Basic 内置了这两个函数的 polyfill,在 PHP 7 及以上环境下也能正常使用。

它们都支持“命中即停”(短路),性能确实比老旧的 array_filter 强得多。但实际在项目里写代码时,你会发现原生函数只解决了 80% 的基础操作,剩下 20% 的复合场景依然写得很别扭:

原生函数没解决的三个问题

问题 1:想找“数字索引”还得折腾:

$key   = array_find_key($arr, $cb);
$index = array_search($key, array_keys($arr));

array_find_key 拿到的是键(Key),如果想要真正的数字索引(Index),得再套一步 array_search。不仅两步走,要是没找到还容易踩到 false 的类型坑。

问题 2:只支持回调,不支持条件查找

$post = array_find($posts, fn($p) => $p['status'] === 'publish' && $p['type'] === 'post');

如果想按关联数组当条件查找(比如['status'=>'publish', 'type'=>'post']),还得手写闭包和 wpjam_matches,外层包得严严实实,噪音极大。

$post = array_find($posts, fn($p) => wpjam_matches($p, ['status'=>'publish', 'type'=>'post']));

问题 3:想"边映射边查找",原生完全不支持

最常见的场景:列表里存的是 ID,如果想边映射边查找:

// 想:找到第一个有缩略图的 term
$url = null;

foreach($terms as $term){
    if($url = wpjam_get_term_thumbnail_url($term)){
        break;
    }
}

又回到了 foreach。

PHP 数组查找增强:wpjam_find

为了把这些弯路抹平,我设计了 wpjam_find 函数。它的核心思路很简单:不取代原生,而是补缺。把各种查找场景统一成一个函数,用参数和返回值来灵活控制。

function wpjam_find($arr, $cb, ...$args){
	$assoc	= wpjam_is_assoc_array($cb);
	$output	= in_array($args[0] ?? '', ['value', 'key', 'index'], true) ? $args[0] : ($assoc ? 'value' : 'result');
	$cb		= $assoc ? fn($v)=> wpjam_matches($v, $cb) : $cb;

	if($output == 'result'){
		foreach($arr as $k => $v){
			$v	= $cb($v, $k);

			if(!is_null($v)){
				return $v;
			}
		}
	}else{
		$res	= wpjam_call('array_find'.($output == 'value' ? '' : '_key'), $arr, $cb);

		return $res === null || $output != 'index' ? $res : array_search($res, array_keys($arr), true);
	}
}

四种输出模式

通过传入不同的第三个参数,可以轻松切换输出结果:

模式返回说明
value元素值原生 array_find 转发
key数组键原生 array_find_key 转发
index数字索引自动处理严格比较(防止 0 和 '0' 混淆)与 null 安全
result映射后的结果原生完全没有的全新能力(闭包默认模式)

前两种是原生的直接转发;在 index 模式 下,函数内部使用 array_search(..., true) 进行了严格比较,彻底避免了 0 和 '0' 搞混带来的误匹配,找不到时也会安全地返回 null。

两种匹配形式

可以给 $cb 传两种内容:

1. 关联数组(语法糖):比如传 ['status' => 'publish'],会自动走 wpjam_matches 匹配。

2. 闭包(Mapper 映射器):当传入闭包时,wpjam_find 默认走 result 模式,它会把闭包当成映射函数,把元素一个个送进去转换,找到非 null 值立刻返回。

result 模式 = 映射后查找

wpjam_find($arr, $mapper)
  • $mapper:对每个元素先做转换
  • 返回第一个"映射结果非 null"的值
  • null = 跳过,其他值(包括 0、''、false)= 命中

在 result(映射查找)模式下,它的工作规则极其清晰:只有返回 null 才算没找到/跳过,或者换个说法只要不是 null 就算“命中”!

mapper 返回结果
null跳过,继续找下一个
0 / '' / false / '0' / []命中,返回该值
非空值命中,返回该值

这条约定非常关键,在很多业务逻辑里,0、''(空字符串)或者 false 都是完全合法的业务结果,不应该被误当作“没找到”而跳过。

// 找第一个存在的配置值
wpjam_find(['enabled', 'disabled'], fn($k) => $config[$k] ?? null)

// 如果 $config['enabled'] = 0,会正确返回 0,而不是继续找 'disabled'

💡 如果确实想把空值当“未命中”跳过怎么办? 非常简单!在闭包映射表达式后面加个 ?: null(例如 $url ?: null),显式地把它转成 null 就行了。

四大实战场景对比

场景 1:取第一个存在的查询参数

// 原生:得写 foreach + break
$cat = null;
foreach(['category_id', 'cat_id'] as $key){
    if(!is_null($cat = wpjam_param($key))){
        break;
    }
}

// wpjam_find:一行搞定,短路逻辑完全一致
$cat = wpjam_find(['category_id', 'cat_id'], fn($k) => wpjam_param($k));

场景 2:按关联条件查找

// 原生:手写闭包和 matches,噪音大
$post = array_find($posts, fn($p) => wpjam_matches($p, ['status'=>'publish', 'type'=>'post']));

// wpjam_find:把关联数组当条件直接传,语义一眼就懂
$post = wpjam_find($posts, ['status'=>'publish', 'type'=>'post']);

场景 3:映射后查找(原生做不到)

// 想:找到第一个有缩略图的 term,并直接返回缩略图 URL
$url = wpjam_find($terms, fn($term) => wpjam_get_term_thumbnail_url($term) ?: null);

// 原生必须写 foreach:
$url = null;
foreach($terms as $term){
    if($url = wpjam_get_term_thumbnail_url($term)){
        break;
    }
}

场景 4:安全拿数字索引

// 原生:两步走,还要手写防坑逻辑
$key = array_find_key($arr, $cb);
$index = $key !== null ? array_search($key, array_keys($arr), true) : null;

// wpjam_find:指定 'index' 模式,一步到位
$index = wpjam_find($arr, $cb, 'index');

总结:一句话搞懂 wpjam_find

简单查找:直接用 PHP 8.4 原生的 array_find 和 array_find_key,干净利落,只有到了复合场景,才需要用 wpjam_find。

wpjam_find 的核心原则很简单:不取代原生,而是补缺:通过关联数组条件,省去手写 wpjam_matches,映射后查找:原生完全缺失的能力。

它通过参数类型自动推断你的意图(传数组查条件,加 'index' 拿索引,传闭包做映射),让你不用记复杂的函数名。

wpjam_find($arr, ['a'=>1])         // 关联数组 → 条件
wpjam_find($arr, fn($v)=> ...)      // 闭包 → mapper
wpjam_find($arr, fn($v)=> ..., 'key') // 加模式字符串 → 换输出

还有最重要的一条约定就是“null 才算跳过”,用明确的 null 信号代替模糊的“真值”判断,让 0、''(空字符串)、false 都能作为合法的业务返回值,帮你避开 99% 的类型和逻辑坑。

如果你的项目里也有大量“遍历 + 判断 + 取值”的冗余代码,不妨试试 wpjam_find,大多数情况下,一行就能优雅搞定!


©我爱水煮鱼,本站推荐使用的主机:阿里云,国外主机建议使用BlueHost。

本站长期承接 WordPress 优化和建站业务,请联系微信:「chenduopapa」。