PHP 中是否有 true() 函数?

3
我正在编写一个名为all的函数,用于检查数组$arr中的所有元素,并返回单个boolean值(基于$f的返回值)。使用自定义函数时工作正常(请参见将$gte0传递给all的代码)。
然而,有时候我们只想检查数组是否包含所有true值:all(true, $arr)不起作用,因为true被传递为boolean(并且true不是函数名)。PHP是否具有本地的类似于true()的功能?
function all($f, array $arr)
{
    return empty($arr) ? false : array_reduce($arr, function($v1, $v2) use ($f) {
        return $f($v1) && $f($v2);
    }, true);
}

$test = array(1, 6, 2);
$gte0 = function($v) { return $v >= 0; }

var_dump(all($gte0, $test)); // True

$test = array(true, true, false);
$id   = function($v) { return $v; } // <-- this is what i would avoid
var_dump(all($id, $test)); // False

all(true, $test); // NOT WORKING because true is passed as boolean
all('true', $test); // NOT WORKING because true is not a function

编辑: 另一种方法是检查 all 函数中的 $f:

$f = is_bool($f) ? ($f ? function($v) { return $v; }
    : function($v) { return !$v; } ): $f;

添加这个后,调用trueall函数将是完全正常的。

3
这是一种非常误导性的编写代码的方式,我认为。特别是你的第二段代码,很难理解正确的流程。 - dynamic
@yes123 你应该在评论的结尾加上“在我看来”的缩写IMHO。 - gremo
1
@Gremo:注释总是陈述性的,从不表达观点。这就是为什么它们被称为注释的原因 ;) - hakre
5个回答

3
最好传递一个函数来将值映射为布尔值,然后将其缩减为最终值。
function all($map, $data) {
  if (empty($data)) { return false; }
  $reduce = function($f, $n) {
    return $f && $n;
  };
  return array_reduce(array_map($map, $data), $reduce, true);
}

$gte0 = function($v) { return $v >= 0; };
$gte2 = function($v) { return $v >= 2; };

$data = array(1, 2, 3, 4, 5);
var_dump(all($gte0, $data));
var_dump(all($gte2, $data));

这样,函数的结果仍然是期望的,但是测试可以根据需要插入。您甚至可以进一步允许传递map和reduce函数。

function mr($map, $reduce, $data) {
  return array_reduce(array_map($map, $data), $reduce, true);
}

3

intval 可能是您要寻找的(特别是在您的示例中数组只包含整数的情况下):

var_dump(all('intval', $test)); // False

然而,在PHP中许多类型转换为整数的结果未定义,并且使用浮点数会向零舍入,因此这可能不是您想要的。
更正确的“函数”应该是布尔值true的相反值:empty,但它不是一个函数,所以您不能使用它(并且翻转返回值)。
var_dump(!all('empty', $test)); // Does not work!

在PHP中没有名为boolval或类似的函数,所以如果需要,可以自己编写 ;)

此外,您的all函数可以进行优化。在迭代时,如果当前结果已经为FALSE,则最终结果将始终为FALSE。无论如何也不需要调用$f()n * 2次:

function all($f, array $arr)
{
    $result = (bool) $arr;
    foreach($arr as $v) if (!$f($v)) return FALSE;
    return $result;
}

编辑: knittl是正确的指向array_filter,它将转换为布尔值而没有给出函数,这似乎很酷,因为没有"boolval"函数:

function all($f, array $arr)
{   
    return ($c = count($arr))
        && ($f ? $arr = array_map($f, $arr) : 1)
        && $c === count(array_filter($arr));
}

var_dump(all(0, $test)); // False

将第一个函数参数设为可选项,借助array_filter可以对每个数组元素进行适当的bool转换。

谢谢,这是目前为止最相关的答案。我会进行优化。 - gremo
@Gremo:我进行了编辑,并添加了一个使用array_filter的“all”函数变体,这也是knittl的一个很好的指针。 - hakre
1
早期退出循环加1分!我认为这是就运行时间和内存而言最好的代码(甚至比array_filter还要好)。我也有类似的想法。顺便说一下,你应该只需要做$result=(bool)$a; foreach($a as $v) { if(!$f($v)) return false; } return $result;,不需要AND所有结果。 - knittl
@knittl:是的,说得好,我改了。有时候当我过于专注于代码时,会忽略一些非常重要的点;) - hakre
对我来说,+1也是如此,尽管许多人认为这是“误导性代码”。我觉得它非常简单易懂。 - gremo

2
您可以使用PHP的array_filter函数,如果没有指定回调函数,它将从数组中删除所有“falsy”值。
$a = array ( true, true, false );
var_dump($a == array_filter($a));

1

PHP中没有true()函数,您应该将值与true进行比较。

尝试

return ($f === $v1) && ($f === $v2);

替代

return $f($v1) && $f($v2);

第一句话让人困惑——在PHP后面是否应该加上句号? - Matt Fenwick

0

我认为这应该可以工作:

function all($f, array $arr)
{
    return empty($arr) ? false : array_reduce($arr, function($v1, $v2) use ($f) {
        return $f($v1) && $f($v2);
    }, true);
}

function isTrue($a)
{
    return true === $a;
}

all("isTrue", $test);

根据需求,可以使用以下代码:function isTrue($a) { return (bool) $a; } - DaveRandom
@Gremo 我认为引用传递到 all() 的参数是相关的。在我的例子中,"isTrue" 是一个字符串,而在你的例子中,true 是一个布尔值。 - James C
@DaveRandom:在PHP中,像&&这样的逻辑运算符不会将操作数转换为布尔值吗? - hakre
@hakre 很好的观点 - 但是当你有一个仅返回唯一参数的函数时,这告诉我可能有更好的方法来完成它... - DaveRandom

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