strtr() performs best with straight character replacements. Longer strings give str_replace() the edge.
For example, the code below yields the following results on my (shared web hosting) system:
Execution timings on PHP 7.0.6:
test_strtr(): 0.37670969963074; result: Lorem ipsum dolor sit amet\, \tconsectetur adipiscing elit\, \nsed do eiusmod \%tempor \'incididunt\' ut labore et DELIMITER dolore\; trunc8 \\magna \"aliqua\".
test_str_ireplace(): 0.73557734489441; result: Lorem ipsum dolor sit amet, \tconsectetur adipiscing elit, \\nsed do eiusmod \%tempor \'incididunt\' ut labore et de-limiter dolore\; trunc8 \\magna \"aliqua\".
test_str_replace(): 0.28119778633118; result: Lorem ipsum dolor sit amet, \tconsectetur adipiscing elit, \\nsed do eiusmod \%tempor \'incididunt\' ut labore et DELIMITER dolore\; trunc8 \\magna \"aliqua\".
When we take out 'delimiter' and 'truncate', results become:
Execution timings on PHP 7.0.6:
test_strtr(): 0.14877104759216; result: Lorem ipsum dolor sit amet\, \tconsectetur adipiscing elit\, \nsed do eiusmod \%tempor \'incididunt\' ut labore et DELIMITER dolore\; truncate \\magna \"aliqua\".
test_str_ireplace(): 0.58186745643616; result: Lorem ipsum dolor sit amet, \tconsectetur adipiscing elit, \\nsed do eiusmod \%tempor \'incididunt\' ut labore et DELIMITER dolore\; truncate \\magna \"aliqua\".
test_str_replace(): 0.20531725883484; result: Lorem ipsum dolor sit amet, \tconsectetur adipiscing elit, \\nsed do eiusmod \%tempor \'incididunt\' ut labore et DELIMITER dolore\; truncate \\magna \"aliqua\".
So, as of PHP 7.0.6, strtr() suffers a considerable penalty with longer replacements. The code:
const LOOP = 333;
const SQL_ESCAPE_MAP = array( // see https://www.owasp.org/index.php/SQL_Injection_Prevention_Cheat_Sheet#MySQL_Escaping
"\x00" => '\x00', // NUL
"\n" => '\n', // LF
"\r" => '\r', // CR
"\\" => '\\\\', // backslash
"'" => "\'", // single quote
'"' => '\"', // double quote
"\x1a" => '\x1a', // SUB or \Z (substitute for an invalid character)
"\t" => '\t', // TAB
"\x08" => '\b', // BS
'%' => '\%', // Percent
'_' => '\_', // Underscore
';' => '\;', // Semicolon
',' => '\,', // Comma
'delimiter' => 'de-limiter', // SQL delimiter keyword
'truncate' => 'trunc8', // SQL truncate keyword
);
const SQL_SEARCH = array("\x00", "\n", "\r", "\\", "'", '"', "\x1a", "\t", "\x08", "%", ";", 'delimiter', 'truncate');
const SQL_REPLACE = array('\x00','\n','\r','\\\\',"\'",'\"', '\x1a', '\t', '\b', '\%', '\;', 'de-limiter', 'trunc8');
const TEST_STRING = "Lorem ipsum dolor sit amet, \tconsectetur adipiscing elit, \nsed do eiusmod %tempor 'incididunt' ut labore et DELIMITER dolore; truncate \magna \"aliqua\".";
function test_strtr() {
for($i= 0; $i < LOOP; $i++) {
$new_string = strtr(TEST_STRING, SQL_ESCAPE_MAP);
}
return $new_string;
}
function test_str_ireplace() {
for($i= 0; $i < LOOP; $i++) {
$new_string = str_ireplace(SQL_SEARCH, SQL_REPLACE, TEST_STRING);
}
return $new_string;
}
function test_str_replace() {
for($i= 0; $i < LOOP; $i++) {
$new_string = str_replace(SQL_SEARCH, SQL_REPLACE, TEST_STRING);
}
return $new_string;
}
$timings = array(
'test_strtr' => 0,
'test_str_ireplace' => 0,
'test_str_replace' => 0,
);
for($i= 0; $i < LOOP; $i++) {
foreach(array_keys($timings) as $func) {
$start = microtime(true);
$$func = $func();
$timings[$func] += microtime(true) - $start;
}
}
echo '<pre>Execution timings on PHP ' . phpversion('tidy') . ":\n";
foreach(array_keys($timings) as $func) {
echo $func . '(): ' . $timings[$func] . '; result: ' . $$func . "\n";
}
echo "</pre>\n";
Note:
This sample code is not meant as a production alternative to mysqli::real_escape_string in lieu of a DB connection (there are issues around binary/multi-byte encoded input).
Clearly, the differences are minor. For mnemonic reasons (how matches and replacements are organized) I prefer the associative array that strtr takes natively. (Not that it can't be achieved with array_keys() for str_replace.) The differences in this case are definitely within the realm of micro-optimizations, and can be very different with different inputs. If you need to process huge strings thousands of times per second, benchmark with your specific data.