views:

42

answers:

4

I was working a bit with preg_replace over the weekend and I was reading the Php preg_replace documentation when I saw something odd.

Example #2 from the docs shows that when given the following php code

<?php
$string = 'The quick brown fox jumped over the lazy dog.';
$patterns[0] = '/quick/';
$patterns[1] = '/brown/';
$patterns[2] = '/fox/';
$replacements[2] = 'bear';
$replacements[1] = 'black';
$replacements[0] = 'slow';
echo preg_replace($patterns, $replacements, $string);
?>

the output will be

"The bear black slow jumped over the lazy dog."

and in order to generate what (in my opinion) should be output by default I would need to call ksort() beforehand. like this:

<?php
ksort($patterns);
ksort($replacements);
echo preg_replace($patterns, $replacements, $string);
?>

Isn't this really a work-around for a bug in php's preg_replace()? Why does php behave this way? Is there some idiosyncrasy with the arrays declared here that I am missing?

+4  A: 

the docs also say:

the keys are processed in the order they appear in the array

So the reason it happens is that simple foreach-type iteration is used and not index access.

SilentGhost
A: 

preg_replace() behaves like if it would be executing code like this

reset($patterns);
reset($replacements);

$pattern = current($patterns);
$replacement = current($replacements);

do {
  // Replace the pattern, if found.
  $pattern = next($patterns);
  $replacement = next($replacements);
} while ($pattern !== FALSE);

I would have preferred the function would have worked without to call ksort().

kiamlaluno
+2  A: 

Sadly, all arrays in PHP are associative arrays.

$replacements[2] = 'bear';
$replacements[1] = 'black';
$replacements[0] = 'slow';

Is stored as 2 -> bear, 1 -> black, 0 -> slow

Instead of the typical blocks of

slow | black | bear

MindStalker
Another solution is to first runarray_fill(0,3,NULL)which creates the array0->NULL,1->NULL,2->NULL,3->NULLAny edits (to those elements) in the future will maintain this order. But in general ksort is probably the best option.
MindStalker
+1  A: 

Array indices are just that, indices, they don't dictate where in memory the values are stored, functions like next() and current() which i imagine preg_replace uses when passed arrays, iterate over the array from the starting memory address to the last for efficiency.

As with alot of things in php, this array iteration is built for speed, anything else is quite rightly up to the developer, which is why you have to add a couple more lines to do slightly more work.

Question Mark