Rozbudowujemy DirectiveParser tak, aby można było przekazywać funkcje jako replacement. Uczymy się preg_replace_callback. Do dzieła!
Zacznijmy od klasy Spoofer, która będzie mieć jedną metodę i tym razem zwracać tekst, nie wyświetlać:
class Spoofer {
public static function method($method){
return '<input type="hidden" id="_method" name="_method" value="' . $method . '"/>';
}
}
Teraz wypróbujmy preg_replace_callback:
$txt = "@METHOD('PUT')";
$out = preg_replace_callback(
"/@METHOD\('*(.*?)'*\)/i",
function($m) {
print_r($m);
return '';
},
$txt);
// Array ( [0] => @METHOD('PUT') [1] => PUT )
Jak widać w $m (od matches) pod 0 mamy całość, zaś pod 1 zawartość naszej capture group. Nic więcej nie potrzebujemy:
$txt = "@METHOD('PUT')";
$out = preg_replace_callback(
"/@METHOD\('*(.*?)'*\)/i",
function($m) {
return Spoofer::method($m[1]);
},
$txt);
echo htmlspecialchars($out);
//<input type="hidden" id="_method" name="_method" value="PUT"/>
Caputre group 1 jest przekazywane do metody method spoofera i zwraca nam replacement. Spróbujmy to ulepszyć:
$action = fn($met) => Spoofer::method($met);
$txt = "@METHOD('PUT')";
$out = preg_replace_callback(
"/@METHOD\('*(.*?)'*\)/i",
function($m) use($action) {
return $action($m[1]);
},
$txt);
echo htmlspecialchars($out);
//<input type="hidden" id="_method" name="_method" value="PUT"/>
To teraz nic prostszego niż dodać to do naszej klasy:
<?php
class Spoofer {
public static function method($method){
return '<input type="hidden" id="_method" name="_method" value="' . $method . '"/>';
}
}
class DirectiveParser {
protected static $patterns = [
[
"pattern" => "/@METHOD\('*(.*?)'*\)/i",
"replace" => array('Spoofer', 'method')
]
];
public static function searchAndReplace($source){
foreach(self::$patterns as $pattern ){
$action = $pattern['replace'];
$source = preg_replace_callback(
$pattern['pattern'],
function($m) use($action) {
return $action($m[1]);
},
$source);
}
return $source;
}
}
$txt = "@METHOD('PUT')";
echo htmlspecialchars(DirectiveParser::searchAndReplace($txt));
//<input type="hidden" id="_method" name="_method" value="PUT"/>
Możemy pozbyć się spoofera i metodę method dołączyć do klasy DirectiveParser:
class DirectiveParser {
protected static $patterns = [
[
"pattern" => "/@METHOD\('*(.*?)'*\)/i",
"replace" => array(__CLASS__, 'method')
]
];
public static function method($method){
return '<input type="hidden" id="_method" name="_method" value="' . $method . '"/>';
}
public static function searchAndReplace($source){
foreach(self::$patterns as $pattern ){
$action = $pattern['replace'];
$source = preg_replace_callback(
$pattern['pattern'],
function($m) use($action) {
return $action($m[1]);
},
$source);
}
return $source;
}
}
$txt = "@METHOD('PUT')";
echo htmlspecialchars(DirectiveParser::searchAndReplace($txt));
//<input type="hidden" id="_method" name="_method" value="PUT"/>