PHP中与JavaScript的“array.every()”相当的是什么?

27

我目前正在尝试将一些 JavaScript 移植到 PHP 上。但是,我似乎找不到 PHP 中与 JavaScript 的 array.every() 函数等价的函数。我找到了 PHP 的 each() 函数,但它似乎并不完全符合我的需求。


2
普通的for循环,当测试条件为false时跳出循环。 - Jaromanda X
1
every函数是否检查每个元素是否满足谓词?有时它被称为all - Carcigenicate
你在下面的评论中说你不太擅长PHP,但如果你擅长JavaScript,可以查看Array#every polyfill代码并将其转换为PHP - 也许? - Jaromanda X
12个回答

17

使用for循环并进行提前返回。

PHP没有原生函数能够像Javascript的array#every一样执行相同的功能。


10
这个页面上的答案是不完整的,并且改变了其他语言中类似的函数(如JS中的every或Python中的all)的语义。映射和归约是不正确的,因为它们会访问每个元素,而不管它们的真值如何。
我们需要一些支持任意谓词回调并且在找到第一个不满足谓词函数的元素时能够提前退出的东西。这个答案接近我们的需求,因为它提供了提前退出的功能,但是没有提供回调谓词。
我们可以顺便写一下someany
<?php

function array_every(array $arr, callable $predicate) {
    foreach ($arr as $e) {
        if (!call_user_func($predicate, $e)) {
             return false;
        }
    }

    return true;
}

function array_any(array $arr, callable $predicate) {
    return !array_every($arr, fn($e) => !call_user_func($predicate, $e));
}

// sample predicate
function is_even(int $e) {
    return $e % 2 === 0;
}

var_dump(array_every([0, 1, 2, 3], "is_even")); // => bool(false)
var_dump(array_every([0, 2], "is_even")); // => bool(true)
var_dump(array_any([1, 2], "is_even")); // => bool(true)
var_dump(array_any([1, 3], "is_even")); // => bool(false)

8
请使用foreach():
function allEven(array $values) 
{
    foreach ($values as $value) {
        if (1 === $value % 2) {
            return false;
        }
    }

    return true;
}

$data = [
    1,
    42,
    9000,
];

$allEven = allEven($data);

参考资料:

注意:使用foreach比使用array_reduce()更好,因为一旦找到不符合规定的值,评估就会停止。


2
这是一个相当不错的答案,因为它 (a) 提供了完整的代码示例,(b) 采用了早期退出机制,但可以通过接受回调函数来改进,而不是硬编码谓词。我不确定你为什么要链接到 array_reduce 文档--那个函数并不适合这个目的(正如你所说!),而且你在代码中也没有使用它(正确!)。 - ggorlen

1

我首先写下了这些代码:

function array_every(callable $callback, array $array) {
    $matches = [];
    foreach ($array as $item) {
        if ($callback($item)) {
            $matches[] = true;
        } else {
            $matches[] = false;
        }
    }
    if (in_array(false, $matches)) {
        return false;
    }
    return true;
}

然后编写了其迷你版本:

function array_every(callable $callback, array $array) {
    foreach ($array as $item) {
        if (!$callback($item)) return false;
    }
    return true;
}

用法:

$array = [1, 2, 3];
$result = array_every(function($item) {
    return $item == 3; // Check if all items are 3 or not (This part is like JS)
}, $array);

echo $result; // Returns false, but returns true if $array = [3, 3, 3]

所以两个版本都很好
你已经得到了答案!:)


1

Php array_every函数


function array_every($array,$callback)
{

   return  !in_array(false,  array_map($callback,$array));
}


array_every([1,2,3],function($n){
     return $n>0;
});


1
我对这个答案进行了负评,因为即使它是一个写得很好的解决方案,它也不能像“every”一样工作。当遇到一个假值时,“every”会提前返回(不会调用更多的回调函数)。而这个解决方案将会调用所有的回调函数,无论它们中的一个是否遇到了假值。 - Torben
也许我没有考虑到性能,我并没有想过它,只是展示了如何实现。当然你是正确的... - dılo sürücü
注意:使用foreach比使用array_reduce()更好,因为一旦找到不满足规范的值,评估就会停止。 - dılo sürücü
1
不仅如此,如果传递给every的函数具有副作用,它也会触发这些副作用,而实际的every函数则不会 :) - Torben

0

2
该方法也被设计为具有破坏性,会改变您的数组值。 - Bricky
6
array_reduce 这个函数很好用(我经常使用它),但你应该把它当成“备选方案”。因为它每次都需要扫描整个数组,而 Array#every 函数只要有一个回调函数返回假值就会立即停止执行。 - Josh from Qaribou

0
一个简单的解决方案:

function array_every(array $array, callable $fn) {
  return (bool)array_product(array_map($fn, $array));
}

在线查看: https://3v4l.org/1D1Ao

这只是一个概念验证,尚未进行优化。对于生产环境,我会使用 foreach 来在第一个未通过测试的项目上返回 false


0

我准备了这个解决方案,尽可能接近JavaScript的Array.prototype.every()

自定义函数建议:

描述:

array_every()方法测试提供的函数实现的数组中的所有元素是否都通过测试。它返回一个布尔值。

array_every()方法对数组中的每个元素执行提供的$callback函数,直到找到其中一个元素使$callback返回假值。如果找到这样的元素,则array_every()方法立即返回false。否则,如果$callback对于所有元素都返回真值,则返回true。

注意:在空数组上调用此方法将对任何条件返回true!

array_every()方法不会改变其被调用的数组。

array_every(array $array, string|callable $callback, null|string|object $thisArg = null): bool

参数:

$array

要迭代的数组。

$callback

一个回调函数,用于测试每个元素,它有四个参数:

       $value - 正在处理的元素的当前值。

       $key (可选) - 正在处理的元素的当前键。

       $index (可选) - 正在处理的元素在数组中的索引。

       $array (可选) - 正在遍历的数组。

$thisArg (可选)

在执行$callback函数时使用的$this值。

返回值:

如果$callback函数对每个数组元素返回一个 truthy 值,则返回true。否则,返回false

array_every()函数:

function array_every(array $array, string|callable $callback, null|string|object $thisArg = null): bool
{
    $index = 0;

    foreach ($array as $key => $value) {

        $condition = false;

        if (is_null($thisArg)) {
            $condition = call_user_func_array($callback, [$value, $key, $index, $array]);
        } else if (is_object($thisArg) || (is_string($thisArg) && class_exists($thisArg))) {
            $condition = call_user_func_array([$thisArg, $callback], [$value, $key, $index, $array]);
        } else if (is_string($thisArg) && !class_exists($thisArg)) {
            throw new TypeError("Class '$thisArg' not found");
        }

        if (!$condition)
            return false;
        $index++;
    }
    return true;
}

示例1(简单回调函数):

$isEven = fn($v) => ($v % 2 === 0);

var_export(array_every([2, 8, 16, 36], $isEven)); // true

示例2:

如果向array_every()方法提供了$thisArg参数,则它将用作$callback$this值。否则,将使用值null作为其$this值。

class Helper
{
    public function isOlderThan18(int $value): bool
    {
        return $value > 18;
    }

    public static function isVowel(string $character): bool
    {
        return in_array($character, ['a', 'e', 'i', 'o', 'u']);
    }

}

范例2a)静态类方法调用:

如果需要声明在命名空间下的类,您可以在$thisArg参数中传递完整的限定类名

var_export(array_every(["a", "u", "e"], "isVowel", "Helper")); // true

示例2b)对象方法调用:

$thisArg 参数也可以是一个对象。

var_export(array_every(["Peter" => "35", "Ben" => "16", "Joe" => "43"], "isOlderThan18", (new Helper))); // false

-1

这里还有另一个选项(实际上,许多数组函数可以相似地使用):

$bool = !empty(array_filter(['my', 'test', 'array'], function ($item) {
    return $item === 'array';
}));

或者针对PHP7.4+,使用箭头函数:

$bool = !empty(array_filter(['my', 'test', 'array'], fn($item) => $item === 'array'));

...看起来有点像JS:

let bool = ['my', 'test', 'array'].every(item => item === 'array'));

而且还分裂了:

function array_every(array $array, callable $callback) {
    return !empty(array_filter($array, $callback));
}

$myArr = ['my', 'test', 'array'];
$myTest = fn($item) => $item === 'array'; // PHP7.4+
$bool = array_every($myArr, $myTest);

同样,可以使用几个数组函数来返回一个空的或填充的数组。虽然正如上面有人提到的那样,实际的JS [].every 会在得到一个true返回时立即停止,如果你需要迭代一个大数组,这可以节省大量时间。我遇到了这个问题,寻找一种快速的函数式编程风格的代码来迭代仅三个数组项。


-1
我的情况是需要检查数组,以了解所有的值是否都是数字。如果一切顺利,返回 true 。如果有字符串或其他非数字类型,则函数必须返回 false
protected function checkIsNumber($arrayNumbers = []) {
    $ga = NULL;
    foreach($arrayNumbers as $value) { 
        if(is_null($ga)) {
            $ga = is_numeric(trim($value));
        } else {
            $ga = $ga === is_numeric(trim($value));
        }
    }
    
    return $ga;
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接