php 在 foreach 循环参数中分解数组

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/5861826/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-25 22:43:19  来源:igfitidea点击:

Exploding an array within a foreach loop parameter

phpperformanceforeach

提问by NightHawk

foreach(explode(',' $foo) as $bar) { ... }

vs

对比

$test = explode(',' $foo);
foreach($test as $bar) { ... }

In the first example, does it explodethe $foostring for each iteration or does PHP keep it in memory exploded in its own temporary variable? From an efficiency point of view, does it make sense to create the extra variable $testor are both pretty much equal?

在第一个示例中,它explode$foo每次迭代的字符串还是 PHP 将其保存在内存中并在其自己的临时变量中爆炸?从效率的角度来看,创建额外变量$test是否有意义还是两者几乎相等?

回答by Wiseguy

I could make an educated guess, but let's try it out!

我可以做出有根据的猜测,但让我们尝试一下

I figured there were three main ways to approach this.

我认为有三种主要方法可以解决这个问题。

  1. explode and assign before entering the loop
  2. explode within the loop, no assignment
  3. string tokenize
  1. 在进入循环之前爆炸和分配
  2. 在循环内爆炸,没有赋值
  3. 字符串标记化

My hypotheses:

我的假设:

  1. probably consume more memory due to assignment
  2. probably identical to #1 or #3, not sure which
  3. probably both quicker and much smaller memory footprint
  1. 由于分配,可能会消耗更多内存
  2. 可能与 #1 或 #3 相同,不确定哪个
  3. 可能既快又小得多的内存占用

Approach

方法

Here's my test script:

这是我的测试脚本:

<?php

ini_set('memory_limit', '1024M');

$listStr = 'text';
$listStr .= str_repeat(',text', 9999999);

$timeStart = microtime(true);

/*****
 * {INSERT LOOP HERE}
 */

$timeEnd = microtime(true);
$timeElapsed = $timeEnd - $timeStart;

printf("Memory used: %s kB\n", memory_get_peak_usage()/1024);
printf("Total time: %s s\n", $timeElapsed);

And here are the three versions:

这是三个版本:

1)

1)

// explode separately 
$arr = explode(',', $listStr);
foreach ($arr as $val) {}

2)

2)

// explode inline-ly 
foreach (explode(',', $listStr) as $val) {}

3)

3)

// tokenize
$tok = strtok($listStr, ',');
while ($tok = strtok(',')) {}

Results

结果

explode() benchmark results

explode() 基准测试结果

Conclusions

结论

Looks like some assumptions were disproven. Don't you love science? :-)

看起来有些假设被推翻了。你不爱科学吗?:-)

  • In the big picture, any of these methods is sufficiently fast for a list of "reasonable size" (few hundred or few thousand).
  • If you're iterating over something huge, time difference is relatively minor but memory usage could be different by an order of magnitude!
  • When you explode()inline without pre-assignment, it's a fair bit slower for some reason.
  • Surprisingly, tokenizing is a bit slowerthan explicitly iterating a declared array. Working on such a small scale, I believe that's due to the call stack overhead of making a function call to strtok()every iteration. More on this below.
  • 从总体上看,这些方法中的任何一种对于“合理大小”(几百或几千)的列表都足够快。
  • 如果您正在迭代一些巨大的东西,时间差异相对较小,但内存使用量可能会相差一个数量级!
  • 当您在explode()没有预先分配的情况下内联时,由于某种原因,速度会慢一些。
  • 令人惊讶的是,标记化比显式迭代声明的数组要慢一些。在如此小的规模上工作,我相信这是由于对strtok()每次迭代进行函数调用的调用堆栈开销。更多关于这个下面。

In terms of number of function calls, explode()ing really tops tokenizing. O(1)vs O(n)

就函数调用的数量而言,explode()ing 确实是标记化的佼佼者。O(1)O(n)

I added a bonus to the chart where I run method 1) with a function call in the loop. I used strlen($val), thinking it would be a relatively similar execution time. That's subject to debate, but I was only trying to make a general point. (I only ran strlen($val)and ignored its output. I did notassign it to anything, for an assignment would be an additional time-cost.)

我在运行方法 1) 的图表中添加了一个奖励,并在循环中调用了一个函数。我使用strlen($val),认为这将是一个相对相似的执行时间。这是有争议的,但我只是想提出一个一般性的观点。(我只跑了strlen($val),而忽视它的输出。我并没有把它分配给什么,对于一个任务将是一个额外的时间成本。)

// explode separately 
$arr = explode(',', $listStr);
foreach ($arr as $val) {strlen($val);}

As you can see from the results table, it then becomes the slowest method of the three.

从结果表中可以看出,它随后成为三种方法中最慢的方法。

Final thought

最后的想法

This is interesting to know, but my suggestion is to do whatever you feel is most readable/maintainable. Only if you're really dealing with a significantly large dataset should you be worried about these micro-optimizations.

知道这很有趣,但我的建议是做任何你认为最易读/最可维护的事情。只有当您真正处理非常大的数据集时,您才应该担心这些微优化。

回答by Shamim Hafiz

In the first case, PHP explodes it once and keeps it in memory.

在第一种情况下,PHP 将其分解一次并将其保存在内存中。

The impact of creating a different variable or the other way would be negligible. PHP Interpreter would need to maintain a pointer to a location of next item whether they are user defined or not.

创建不同变量或其他方式的影响可以忽略不计。无论是否是用户定义的,PHP 解释器都需要维护一个指向下一个项目位置的指针。

回答by NikiC

From the point of memory it will not make a difference, because PHP uses the copy on write concept.

从内存的角度来看,它不会有什么不同,因为 PHP 使用了写时复制的概念

Apart from that, I personally would opt for the first option - it's a line less, but not less readable (imho!).

除此之外,我个人会选择第一个选项 - 它少了一行,但不那么易读(恕我直言!)。

回答by Mikhail

Efficiency in what sense? Memory management, or processor? Processor wouldn't make a difference, for memory - you can always do $foo = explode(',', $foo)

什么意义上的效率?内存管理还是处理器?处理器不会有什么不同,对于内存 - 你总是可以做到的$foo = explode(',', $foo)