Reputation: 10348
I have noticed a strange behaviour of a str_replace function. Can you tell me why instead of number 3 in no_2 i get no_4 ?
Here is the case:
$pattern = array(1,2,3);
$change = array(1,3,4);
$sql = "SELECT * FROM %s WHERE no_1 IN (%s) AND no_2 IN (%s) AND no_3 IN (%s)";
$test_multiply[] = str_replace($pattern, $change, $sql);
Which gives:
Array ( [0] => SELECT * FROM %s WHERE no_1 IN (%s) AND no_4 IN (%s) AND no_4 IN (%s) )
Can you tell me what should I do to receive no_3 instead of no_2?
Upvotes: 1
Views: 915
Reputation: 655129
If you use str_replace
with an array of needles, every needle is replaced in a separate str_replace
call. You can imagine that something like this happens internally:
for ($i=0, $n=min(count($pattern),count($change)); $i<$n; $i++) {
$sql = str_replace($pattern[$i], $change[$i], $sql);
}
So in the first iteration all 1
are replaced by 1
, then all 2
are replaced by 3
, and then all 3
is replaced by 4
:
SELECT * FROM %s WHERE no_1 IN (%s) AND no_2 IN (%s) AND no_3 IN (%s)
SELECT * FROM %s WHERE no_1 IN (%s) AND no_3 IN (%s) AND no_3 IN (%s)
SELECT * FROM %s WHERE no_1 IN (%s) AND no_4 IN (%s) AND no_4 IN (%s)
To do a simultaneous replacement, you can use preg_replace_callback
and call a mapping function for each matched pattern:
function str_replacep(array $search, array $replace, $subject, &$count=0) {
$combinedPattern = '/(?:'.implode('|', array_map(function($str) { return preg_quote($str, '/'); }, $search)).')/';
$map = array_combine($search, $replace);
$mapping = function($match) use ($map, $count) {
$count++;
return $map[$match[0]];
};
return preg_replace_callback($combinedPattern, $mapping, $subject);
}
I used anonymous function in this example but it will also work with create_function
.
With this the order of the replacement doesn’t matter. You can even exchange two values:
var_dump(str_replacep(array(1,2), array(2,1), "12")); // string(2) "21"
Upvotes: 3
Reputation: 48091
Because once you replace 2 with 3 the next replace will always replace 3 with 4
Upvotes: 0
Reputation: 1281
First, you're replacing 1 with 1, so thats fine
SELECT * FROM %s WHERE no_1 IN (%s) AND no_2 IN (%s) AND no_3 IN (%s)
Then, replacing 2 with 3, to get
SELECT * FROM %s WHERE no_1 IN (%s) AND no_3 IN (%s) AND no_3 IN (%s)
Then replacing 3 with 4, resulting in
SELECT * FROM %s WHERE no_1 IN (%s) AND no_4 IN (%s) AND no_4 IN (%s)
Maybe you should replace 2 with another value (not 3), which you can replace again later.
Upvotes: 1
Reputation: 400922
The documentation for str_replace()
says (quoting) :
Because str_replace() replaces left to right, it might replace a previously inserted value when doing multiple replacements.
I believe you are precisely in this situation :
no_2
gets replaced to no_3
-- because of the second item in your $pattern
and $change
arraysno_3
gets replaced to no_4
-- because of the thid item in your $pattern
and $change
arrays$pattern = array(3, 2, 1);
$change = array(4, 3, 1);
And you'd get the following result :
SELECT * FROM %s WHERE no_1 IN (%s) AND no_3 IN (%s) AND no_4 IN (%s)
Upvotes: 7