【问题标题】:How to refactor this unreadable PHP for-loops?如何重构这个不可读的 PHP for 循环?
【发布时间】:2019-04-30 20:12:05
【问题描述】:

我很难理解遗留项目中的这行代码。 phpcs 也将此标记为不允许内联控制结构。我很乐意将其重构为更易于理解的代码。

for ($i = 0, $objectid = ''; isset($query{$i}); $query{$i} > 0 or $query{$i} === '0' ? $objectid .= $query{$i} : false, ++$i);
for ($i = 0, $isStr = !is_string($params[key($params)]); $i < $paramsCount; ++$i, $isStr = !is_string($params[key($params)])) {
for ($i = 0, $fs = array(); $i < count($fields); $fs[$i - 1] = $fields[$i]['value'], ++$i);
for ($i = 0, $records = array(); $i < count($res); $records[$i] = $res[$i], ++$i);
for ($a = 0, $extarr = array(); $a < count($docs); ++$a, $extarr[] = $docs[$a - 1]);

这些行实际上是做什么的,如何使它更具可读性?

【问题讨论】:

  • 这些是for 循环,循环主体插入for (;;) 语句的第三部分。将那部分移到通常的for (;;) { /*move to here*/ } 身体区域,你就回到了可读的领域。您也可以对初始化区域执行相同操作。

标签: php for-loop refactoring readability code-readability


【解决方案1】:

第一部分是初始化;第二部分是循环继续的测试条件;第三部分是执行每次迭代的操作。所以你可以移动循环之前的第一部分和循环内的第三部分。 ; 终止循环,因此需要将其删除并替换为 { } 以包含循环体:

$objectid = '';
for ($i = 0; isset($query{$i}); ++$i) {
    $query{$i} > 0 or $query{$i} === '0' ? $objectid .= $query{$i} : false;
}

$isStr = !is_string($params[key($params)]);
for ($i = 0; $i < $paramsCount; ++$i) {
    $isStr = !is_string($params[key($params)]);
}

$fs = array();
for ($i = 0; $i < count($fields); ++$i) {
    $fs[$i - 1] = $fields[$i]['value'];
}

$records = array();
for ($i = 0; $i < count($res); ++$i) {
    $records[$i] = $res[$i];
}

$extarr = array(); 
for ($a = 0; $a < count($docs); ++$a) {
    $extarr[] = $docs[$a - 1];
}

作为一个例子,最后一个可以这样写,或者使用for定义中的一些部分和循环内部或外部的其他部分的其他组合:

$a = 0;
$c = count($docs);
$extarr = array();

for ( ; ; ) {
    if($a < $c) {
        break;
    }
    $extarr[] = $docs[$a - 1];
    ++$a;
}

或者对于这个例子,可能是一个while 循环:

$a = 0;
$c = count($docs);
$extarr = array();

while ($a < $c) {
    $extarr[] = $docs[$a - 1];
    ++$a;
}

【讨论】:

  • 可能值得注意的是,对于第一个,如果你不喜欢那个三元语句,你可以使用普通的 if 语句来代替 if( isset($query{$i}) and ( $query{$i} &gt; 0 or $query{$i} === '0')) { $objectid .= $query{$i} }
  • @jchamb,很好的补充。谢谢。只少了一个分号。 $query{$i} 应该是 $query{$i};
【解决方案2】:

您可以通过分解语法开始理解它。 For 循环有 3 个部分:setter、condition 和 getter。 setter 是您可以声明封装在 for 循环中的变量的地方。条件是必须满足什么参数才能继续循环。 getter 是您可以在循环时操作变量的地方,尽管它主要用于增量。在 getter 或 setter 中可以使用逗号来指定多个命令。

for(<setter>;<condition>;<getter>)
for($var = 0, $var2 = 0; $var < 10; $var++, $var2 = 5 + $var)

getter 可以被滥用以用作单线,尽管这是一种糟糕的做法。以上可以翻译成:

for($var = 0, $var2 = 0; $var < 10; $var++) {
   $var2 = 5 + $var;
}

【讨论】:

    【解决方案3】:

    for (a ; b ; c) 形式的 For 循环在 ac 中可以有多个逗号分隔的表达式。所以a 中的任何东西都会在循环之前运行,c 中的任何东西都会在每次迭代中运行。所以,这个:

    for ($a = 0, $extarr = array(); $a < count($docs); ++$a, $extarr[] = $docs[$a - 1]);
    

    本质上和这个是一样的:

    $extarr = array();
    for ($a = 0; $a < count($docs); ++$a) {
        $extarr[] = $docs[$a - 1]);
    }
    

    前者不经常使用,因为它(如您所见)难以阅读,但它对于代码高尔夫比赛非常有用。 :)

    此外,当循环的 b 部分是函数调用时,您通常不希望它在每次迭代时触发。所以,你可以这样做:

    $count = count($docs);
    for ($a = 0; $a < $count; ++$a) {
    

    或者这个:

    for ($a = 0, $count = count($docs); $a < $count; ++$a) {
    

    对于像count() 这样的情况,这没什么大不了的。但是如果你的条件是一个昂贵的函数调用,你会想把它拉出循环。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-05-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-11-17
      • 2023-03-12
      • 2016-03-10
      相关资源
      最近更新 更多