【问题标题】:PHP foreach that returns keys only仅返回键的 PHP foreach
【发布时间】:2012-09-03 00:51:15
【问题描述】:

可能没有任何意义的理论问题,但也许有一个聪明的答案。

我想遍历数组并获取它的键和它们的一些东西。我所做的一个简单的例子:

foreach($array as $key => $value) {
    $other_array[$key] = 'something';
}

现在,PHP Mess Detector 尖叫着$value 在此范围内未使用。因此,我在想,也许这不是访问我的array 中的keys 的最佳方式。

知道如何在不不必要地从我的array 中取出values 的情况下做到这一点吗?它是否对性能有任何重大影响......或者我只是偏执并且应该继续而不用愚蠢的问题浪费任何人的时间:)。

【问题讨论】:

  • 这很正常。但是你可以使用这个: $keys = array_key ($array); foreach($keys as $key) { $other_array[$key] = 'something'; }
  • 您可以抑制混乱探测器的警告,例如:phpmd.org/documentation/suppress-warnings.html

标签: php arrays foreach


【解决方案1】:

你可以这样做

foreach(array_keys($array) as $key) {
 // do your stuff
}

这将使 foreach 迭代一个由数组中的键组成的数组,而不是实际的数组。请注意,从性能的角度来看,它可能并不好。

【讨论】:

  • 我相信这里的每次迭代都会调用 array_keys(),所以这可能不是最聪明的举动?
  • 没有,我记得如果评估一次,则进入 foreach 的数组。就像 foreach(array("a", "b", "c") as $letters) 不会在每次迭代时创建一个新数组。如果这不正确,那么可以肯定,在 foreach 之前创建一个 $keys 变量...您有任何参考指向 foreach 在每次迭代中评估数组的事实吗?
  • 据我所知,foreach() 是使用迭代器实现的,因此只调用返回数组一次的函数。然后它使用指向现有结果集的迭代器继续处理每个项目。所以 foreach(array_keys() ... 是完全安全的
  • @inquam 感谢您的洞察力!这来自我的 JavaScript 经验,在每次迭代中执行 for (var i = 0; i < abc.indexOf('aa'); i++) 会调用 indexOf。我想我的想法是所有语言都会以同样的方式做到这一点 - 我很高兴他们没有!
  • 我做了一些测试,foreach(array_keys($arr) as $key)foreach($arr as $key => $val) 慢了大约 50% 到 60%。但这是正确的,你把array_keys($arr)放在哪里没有区别。 (使用 php 5.6.0 测试了一个包含 255 个元素和 100000 轮的数组)
【解决方案2】:

请忽略此消息。

在 PHP 中,您使用 foreach 的方式是最快的。正确的是,您应该避免使用未使用的变量,但在这种情况下,您无法避免它,而不会损失一些性能。

例如foreach(array_keys($arr) as $key) 大约慢 50% 到 60%
foreach($arr as $key => $notUsed).

这个问题的phpmd已经上报here,也已经有pull request了here

在phpmd更新之前你也可以使用this little hack

collectVariables(..) 方法中的文件 /src/main/php/PHPMD/Rule/UnusedLocalVariable.php 中(在我的例子中是第 123 行)替换

if ($this->isLocal($variable))

通过

if ($this->isLocal($variable) && !($this->isChildOf($variable, 'ForeachStatement') && $variable->getName() === '$notUsed'))

这将阻止 phpmd 在 foreach 循环内报告 $notUsedanywhere

更新: 上面的建议假设 PHP 5.6(撰写此答案时的相关版本)。但是时间过去了,现在使用 PHP 7.2 似乎正好相反。与往常一样,这取决于具体的用例,但对于少于 100.000 个键的关联数组,将 array_keys($arr) 存储在变量中并在 foreach 循环中使用它会更快。

【讨论】:

    【解决方案3】:

    这是有效的 PHP 代码,不要修复代码,而是修复 PHP MD。 PHP MD 2.2 中有一个配置 并且需要这条规则:

    <properties>
        <property
            name="allow-unused-foreach-variables"
            description="Allow unused variables in foreach language constructs."
            value="false" />
    </properties>
    

    【讨论】:

    • 呃,这些行放在哪里??
    • @OlleHärstedt 在您正在使用的配置文件中,例如 ruleset.xml,然后是 phpmd codebase/ some_output_format rulesets.xml
    • 下面有一个提供上下文的答案。如果其他人想知道。
    【解决方案4】:

    18C 破解 :-)

    在构造as $key=&gt;$value中,$value首先在PHP中分配,然后再分配$key。

    $array=[1,3,6,10];
    
    foreach($array as $k => $k) 
       print($k.'<br/>');
    

    对于您的代码:

    foreach($array as $key => $key) 
    {
        $other_array[$key] = 'something';
    }
    

    顺便说一句。不要使用:foreach($array as $k =&gt; &amp;$k)。它可能会破坏您的阵列。

    【讨论】:

    • 你依赖于内部行为。这可能会结束。
    • @finder2 我同意。他们可以在未来的版本中更改此行为,并且该错误将难以跟踪。我会考虑foreach ($array as $key =&gt; $_)
    【解决方案5】:

    如果您想将所有键设置为某个值,您可以这样做:

    $array = array(
            'foo'=> 'oldval1',
            'bar'=> 'oldval2',
            'baz'=> 'oldval3'
    );
    
    $other_array = array_fill_keys(array_keys($array), 'something');
    print_r($other_array);
    

    这将产生:

    Array
    (
        [foo] => something
        [bar] => something
        [baz] => something
    )
    

    【讨论】:

    • +1 的想法虽然这不是我的想法 - 示例过于简单:)。无论如何谢谢 - 学习新东西:)
    【解决方案6】:

    如果您使用的是 XML 规则集:

        <rule ref="rulesets/unusedcode.xml/UnusedLocalVariable">
            <properties>
                <property name="allow-unused-foreach-variables" value="true" />
            </properties>
        </rule>
    

    【讨论】:

      【解决方案7】:

      循环以避免 foreach 在一段时间内。

      $a = ['1','A','B','12','ui'];
      
       while(true) { sleep(1);
          $b = next($a) ? current($a): reset($a);
          echo key($a) , ':' , $b , PHP_EOL;
       }
      

      【讨论】:

      • while(3) 更短。 :-) 此外,您应该避免潜在的无限循环。
      猜你喜欢
      • 2012-12-23
      • 2015-10-10
      • 2022-10-14
      • 2017-07-15
      • 1970-01-01
      • 2011-06-30
      • 2017-11-27
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多