仅返回键的 PHP foreach

Posted

技术标签:

【中文标题】仅返回键的 PHP foreach【英文标题】:PHP foreach that returns keys only 【发布时间】: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 【参考方案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) 更短。 :-) 此外,您应该避免潜在的无限循环。

以上是关于仅返回键的 PHP foreach的主要内容,如果未能解决你的问题,请参考以下文章

如果值等于,则从对象返回键和值

PHP PDOStatement:获取一行,作为数组的键的第一列[重复]

foreach 循环内的 while 循环仅返回 1 行

如何仅针对键的子集有效地比较 C++ 中的两个字符串映射

PHP中带键的数组映射

PHP多维数组搜索并获取键的数组[重复]