如何退出PHP中的数组迭代函数(array_reduce)

如何退出PHP中的数组迭代函数(array_reduce),php,arrays,loops,array-reduce,Php,Arrays,Loops,Array Reduce,我有一个array_reduce函数,当满足特定条件时,我愿意退出该函数 $result = array_reduce($input, function($carrier, $item) { // do the $carrier stuff if (/* god was one of us */) { break; //some break analogue } return $carrier; }); 我如何做到这一点?还是应该改用foreach?array\u re

我有一个array_reduce函数,当满足特定条件时,我愿意退出该函数

$result = array_reduce($input, function($carrier, $item) {
  // do the $carrier stuff
  if (/* god was one of us */) {
    break; //some break analogue
  }
  return $carrier;
});

我如何做到这一点?还是应该改用foreach?

array\u reduce
用于编写始终在整个数组上迭代的函数式代码。您可以重写以使用常规的foreach循环来实现短路逻辑,也可以简单地返回未修改的当前
$carrier
。这仍然会在整个数组中进行迭代,但不会改变结果(正如您所说,这更类似于
continue

根据类似的答案。

完成此任务的最佳和最差方法是例外。 不建议采用这种方式,但这种方式可以解决您的问题:

try {
    $result = array_reduce( $input, function ( $carrier, $item ) {
        // do the $carrier stuff
        $condition = true;
        if ( $condition ) {
            throw new Exception;
        }

        return $carrier;
    } );
} catch ( Exception $exception ) {
    echo 'Break';
}
我解决问题的方法 我将创建一个全局函数或编写PHP扩展并添加一个函数

关于编写PHP扩展,有一个很好的答案:

但破坏实现也有一个问题。 需要检测哪种情况不起作用。 在实现下面,
array\u reduce\u 2
检查回调是否返回。 如果是这样,则中断执行

这种方法允许通过检查值的返回类型来检查执行是否中断

array\u reduce\u 2实现 根据@wordragon通知,实现了将关联数组作为param传递的功能

function array_reduce_2( $array, $callback, $initial = null ) {
    $len   = count( $array );
    $index = 0;

    if ( $len == 0 && count( func_get_args() ) == 1 ) {
        return null;
    }

    $values = array_values( $array );
    $result = $initial ?? $values[ $index ++ ];
    foreach ( $values as $value ) {
        $result = $callback( $result, $value );

        if ( ! is_callable( $result ) ) {
            continue;
        }

        // break;
        return $result;
    }

    return $result;
}
我使用了JS实现的思想,并相应地重写了PHP

检测是否发生中断 重要的是要注意!
这个
array\u reduce\u 2
实现只有在您不需要返回正常值作为回调时才能正常工作。

首先,让我说array\u reduce可能是我最喜欢的函数之一-我很出名(嗯,在一个很小的圈子里)获取40行清晰编写的代码,并将其替换为4行更难理解的10行数组。\u减少执行相同操作的调用

遗憾的是,PHP数组函数似乎注定要完成它们的任务。再加上无法生成递归的未命名函数,使得这种常见情况难以处理。我不想在我的代码中加入太多难看的for循环,我倾向于将它们埋在另一个函数中(参见下面的reduce),就像前面的海报一样

值得指出的是,这远不如使用数组函数有效,而且在大多数情况下,最好让数组reduce函数使用“done”标志快速旋转不需要的值。无论如何,这与array_reduce类似(求值函数使用null返回表示其已完成)。目标是将数组中的数字相加,直到得到4

<?php

$init = 0;
$arr = [1,2,3,4,5,6,7,8,9,0];

$func = function($c, $it) {
            if ($it == 4) return null;
            return $c + $it;
        };

function reduce($arr, $f, $init) {
    for ($c = $init; count($arr); ) {
        $newc = $f($c, array_shift($arr));
        if (!isset($newc)) break;
        $c = $newc;
    }
    return $c;
}

echo reduce($arr, $func, $init) . "\n";   // 6

易碎数组\u reduce()

function breakable\u array\u reduce(数组$array,可调用$callback,$initial=null){
$result=$initial;
foreach($array作为$value){
$ret=$callback($result,$value);
如果(false==$ret){
返回$result;
}否则{
$result=$ret;
}
}
返回$result;
}
用法

//10个值的数组
$arr=[
1.
1.
1.
1.
1.
1.
1.
1.
1.
1.
];
//值>=5时停止的回调函数
$sum_until_five=函数($initial,$value){
如果($initial>=5){
返回false;
}否则{
返回$initial+$value;
}
};
//使用$sum_until_five()计算$arr的总和
$sum=易碎阵列减少($arr,$sum\u直到第五个);
//产出:5
echo$sum;
解释

breakable\u array\u reduce()
将像
array\u reduce()
一样工作,除非/直到callback
$callback
返回
bool(false)

使用数组键的替代实现:


易碎数组\u减少键控()

function breakable\u array\u reduce\u keyed(数组$array,可调用$callback,$initial=null){
$result=$initial;
foreach($key=>$value的数组){
$ret=$callback($result,$value,$key);
如果(false==$ret){
返回$result;
}否则{
$result=$ret;
}
}
返回$result;
}
用法

//值数组
$arr=[
‘foo’=>1,
'bar'=>1,
‘baz’=>1
];
//当$key=='baz'时停止的回调函数
$sum_until_baz=函数($initial,$value,$key){
如果('baz'==$key){
返回false;
}否则{
返回$initial+$value;
}
};
//使用$sum_until_baz()计算$arr的总和
$sum=易碎阵列减少($arr,$sum_直到_baz);
//产出:2
echo$sum;

另外,我刚刚编写并在本地进行了全面测试。

我建议改用
foreach
循环。不使用
array\u reduce
的原因如下:

合理理由:
  • 它不是静态类型检查的。因此,如果输入或回调参数中存在任何类型错误,则代码检查不会显示类型错误
  • 它返回
    mixed
    ,因此如果您误用结果,检查不会显示错误,如果您正确使用,检查可能会显示假阳性
  • 你不能打破
  • 自以为是的理由:
  • 这对眼睛更难。拥有一个
    $result
    并将其添加到循环中(或您所做的任何事情)要比理解某个内容是
    返回的
    ed,然后在下一次调用中作为
    $carry
    累加器传递容易得多
  • 它使我懒得正确地提取函数。如果我将一个操作提取到回调中,那么我可能会发现代码足够短,无法将整个数组操作提取到一个函数中,而这个函数实际上应该首先完成
  • 如果您使用一个条件来中断,很可能有一天您需要该回调函数的其他参数。在回调签名被修复的情况下,您必须传递参数w
    $input  = [ 'test', 'array', 'god was one of us' ];
    $result = array_reduce_2( $input, function ( $carrier, $item ) {
        // do the $carrier stuff
        if ( $item === 'god was one of us' ) {
            return function () {
                return 'god was one of us';
            };
        }
    
        return $carrier;
    } );
    
    $is_break = is_callable( $result );
    if ( $is_break ) {
        echo $result();
        exit;
    }
    
    <?php
    
    $init = 0;
    $arr = [1,2,3,4,5,6,7,8,9,0];
    
    $func = function($c, $it) {
                if ($it == 4) return null;
                return $c + $it;
            };
    
    function reduce($arr, $f, $init) {
        for ($c = $init; count($arr); ) {
            $newc = $f($c, array_shift($arr));
            if (!isset($newc)) break;
            $c = $newc;
        }
        return $c;
    }
    
    echo reduce($arr, $func, $init) . "\n";   // 6