views:

96

answers:

3

Is the 'copy' of an array for a foreach (of php5, in this case) an immediate copy with actual overhead, or merely a lazy copy (copy on write) which only produces overhead if it detects a write manipulation?

The alternative, note in several places, is to run foreach over keys($array) -- how can that really be faster?

+1  A: 

PHP uses copy-on-write. It's slower to pass by reference because it has to setup the data structures to maintain the reference.

scribble
That I understand, but what about the foreach statement?
Don
array_keys($array) is slower and will use more memory because it has to generate and return a separate array of all the keys before looping.
scribble
+1  A: 

OK, so I went off and measured it --

Test This                    And This                       And, uh, This      
---------------------------  ----------------------------   ----------------------------
Setup                        Setup                          Setup                     
---------------------------- ----------------------------   ----------------------------
$i = array_fill(0,1000,'1'); $j = array_fill(0,1000,'1');   $j = array_fill(0,1000,'1');
$c = 0;                      $d = 0;                        $e = 0;
---------------------------  ----------------------------   ---------------------------
Code Under Test              Code Under Test                Code Under Test                    
---------------------------  ------------------------------ --------------------------
foreach ($i as $v)           foreach (array_keys($j) as $k) foreach ($i as &$v)
{ $c+= $v; }                 { $d+= $j[$k]; }               { $e+= $v; }    
---------------------------  ------------------------------ -------------------------
Tear Down                    Tear Down                      Tear Down                          
---------------------------  -----------------------------  -------------------------
print "c = $c";             print "d = $d";              print "e = $e";                    
---------------------------- -----------------------------  --------------------------
Test for repetitions.  10000         
---------------------------- -----------------------------  -------------------------
c = 10000000                 d = 10000000                   e = 10000000
---------------------------- -----------------------------  -------------------------
Ran in  1.8540189266205      Ran in 4.0039160251617         Ran in 1.9633851051331
---------------------------  -----------------------------  -------------------------
Winner -0.10936617851257     Looser 2.0405309200287         2nd Best             0
---------------------------  ----------------------------  -------------------------

Looks like foreach ($a as $v) is much better than array_keys and that using &v is in the middle.

Don
Nice one. I did basically that to check what I was telling you but the code wasn't so pretty to paste in.One additional thing I did was add a one-time call to echo memory_get_usage() at the beginning of the array_keys version's loop to confirm the extra memory usage while it was in scope. Using range(1, 1000000) I ran out of memory with memory_limit 128M.BTW, your third column loop should be $e+= so your tear-down is non-zero.
scribble
you have an error in 3rd example: { $c+= $v; } should be: { $e+= $v; }-- that's causing your bad result.
dar7yl
Isn't *FOR* loop faster than *FOREACH* loop in this same example? Try it and tell us.
Ismael
A: 

OK, here is the other requested comparison (what do you think?)

Test This                                 And This                            
---------------------------------------   --------------------------------------
Setup                                     Setup                               
--------------------------------------    --------------------------------------
$k = array_fill(0,1000,'1');              $i = array_fill(0,1000,'1');        
$f = 0;                                   $c = 0;                             
$kMax = count($k);                                                            
--------------------------------------    --------------------------------------
Code Under Test                           Code Under Test                     
--------------------------------------    --------------------------------------
for ($x = 0; $x < kiMax; $x++)            foreach ($i as $v)                  
{ $f+= $k[$x]; }                          { $c+= $v; }                        
--------------------------------------    --------------------------------------
Tear Down                                 Tear Down                           
--------------------------------------    --------------------------------------
print "f = $f";                           print "c = $c";                     
--------------------------------------    --------------------------------------
Test for repetitions:  10,000
--------------------------------------    --------------------------------------
f = 10000000                              c = 10000000
--------------------------------------    --------------------------------------
Ran in 2.8563051223755                    Ran in 1.8667521476746
--------------------------------------    -------------------------------------
2nd best      0.98955297470093            Winner               0
Don