So this one you already found, the matching group numbers of the regular expression pattern were wrong:
foreach ($matches as $match) {
$oldPage = str_replace('"', '', $match[2]);
$newPage = str_replace('"', '', $match[3]);
$redirectRules[$oldPage] = $newPage;
}
The need to be 1
and 2
respectively:
$pattern = '/Redirect 302\s+(?P<expr>[^\s]+)\s+(?P<file>[^\s]+)/';
# | `-----(1)------´ `------(2)-----´|
# `-------------------------(0)----------------------´
Another improvement for the regular expression pattern with preg_match() in your case is to drop the naming of the matching groups as you're not using them:
$pattern = '/Redirect 302\s+([^\s]+)\s+([^\s]+)/';
# | `-(1)--´ `-(2)--´|
# `---------------(0)----------------´
This is a little optimization as well, as PHP will use less memory, the $matches
array then has less items and can safe the memory of two string keys per each match item. Internally this has also the benefit that PHP can optimize such arrays as they are a list (array_is_list()), that means starting with integer key 0
and all following keys are consecutive integers. PHP then can optimize (memory and speed).
$oldPage = str_replace('"', '', $match[1]);
$newPage = str_replace('"', '', $match[2]);
$redirectRules[$oldPage] = $newPage;
This are two str_replace() calls made per each $match that are doing the same search and replace, only the subject is different.
str_replace() can operate on an array of subjects. So the two function calls can be replaced with one:
[$oldPage, $newPage ] = str_replace('"', '', [$match[1], $match[2]]);
$redirectRules[$oldPage] = $newPage;
This is normally an optimization in PHP as function calls are relatively expensive while array creation and destructing is not. But this is on a level you would normally need to run the metrics with your own data and then compare different implementations to each other. So the benefit could not be speed here, but having the pairing better aligned, so more straight forward code that is easier to maintain.
Now then some real optimization trick in PHP (given you don't have an enormous amount of key-collisions):
Looking up the request URI for a potential redirect. In the original code we have a foreach loop (already pretty fast in php) to compare if the array key matches the request URI:
// Check if the requested URI matches any redirect rules
foreach ($redirectRules as $oldPage => $newPage) {
if ($requestURI === $oldPage) {
// Redirect to the new page
header("Location: $newPage", true, 302);
exit;
}
}
As this is basically the lookup of the key in the array ($redirectRules), PHP is faster doing so by directly accessing/querying the item in the array. As PHP internally uses a hash-map for the array keys if there are string keys involved – this is why arrays that are a list can be optimized, no expensive string hashing is required for them, all keys are consecutive integers starting with 0 – directly testing for the array item by its key to test for existence is (most often) faster than looping over the array. the loop is very fast when the first entry matches, but the loop can not benefit from PHPs internal array hashmap, which is much more effective to find the item in the map regardless if it is first or last.
This was much explanation, the key part is that in PHP we can use arrays as maps (string keys, associative array), and the lookup of the key then is an optimization when it can replace a loop.
$newPage = $redirectRules[$requestURI] ?? null
Variable $newPage is only set if a redirect rule for the request uri exist.
As there are two possible outcomes – array has a member for that key or not – we provide the value for the case the key test fails. This works with the null-coalescing operator ("??"). An undefined array entry in PHP emits a warning unless the ?? operator is in use to handle the case and provide a value to use instead.
Here we use the null
value which means that there is a value but its not a value. Hence it pretty much expresses what we're looking for: the not-found entry.
// Check if the requested URI matches any redirect rules
if ($newPage = $redirectRules[$requestURI] ?? null) {
// Redirect to the new page
header("Location: $newPage", true, 302);
exit;
}
This way of writing code is that common in PHP that I have the tendency to just quench it within if-clauses already, that is there is a variable assignment in the if-clause. It depends on context whether that is expected or not, so the assignment could be done before the if and the if then operating on the variable only, perhaps even make it clear that we are looking for a variable that is not empty:
// Check if the requested URI matches any redirect rules
$newPage = $redirectRules[$requestURI] ?? null;
if (!empty($newPage)) {
// Redirect to the new page
header("Location: $newPage", true, 302);
exit;
}
Further: An example of how to store a PHP array on disk an load it back later is here: Answer to: How do I store an array in a file to access as an array later with PHP?