eval — пользовательская функция синтаксического анализа переполнения стека

Я пытаюсь удалить eval из следующей функции. Я пробовал с Sprintf а также $ {} , но все еще не может найти решение.

Здесь функция:

function parseDbString(string $value = 'Looking for a good {{ $pippo }}'){
$pippo='Pizza';
return preg_replace_callback('/{{(.*?)}}/', function($res) use ($pippo) {
// $val=${trim($res[1])}; Returns "Undefined variable: $pippo"$val=@eval("return ".trim($res[1]).";"); // Returns "Looking for a good Pizza"return isset($val) ? $val : $res[0];
},$value);
}

3

Решение

Так да, eval() часто ненавидят как одно из «зол» высшего порядка в php. В большинстве случаев, когда задача поддается решению eval() или переменные-переменные (которые в основном представляют собой плохо упакованные массивы), это является признаком неправильно хранимых / объявленных данных, и часто лучшим вариантом действий является полное переосмысление.

Чтобы решить ваш изолированный вопрос без фундаментальной переписки пользовательской функции, я предложу меньшее «зло» (но, на мой взгляд, все еще «зло», потому что есть риски при его использовании) — GLOBALS & global

Код: (демонстрация)

function parseDbString(string $value = 'Looking for a good {{ $pippo }}'){
global $pippo;                        // declare $pippo as a global variable
$pippo = 'Pizza';
return preg_replace_callback('/{{ \$(.*?) }}/', function($m) use ($pippo) {
echo "Global: " , $GLOBALS['pippo'];
echo "\n{$m[1]}\n";
return $GLOBALS[$m[1]] ?? $m[0];  // null coalescing operator provides fallback
},$value);
}
echo parseDbString();

Выход:

Global: Pizza                    # <-- for demonstraton purposes
pippo                            # <-- for demonstraton purposes
Looking for a good Pizza         # <-- desired output

…так почему этот обходной путь «плохая идея», представьте, что у вас есть строка, которая содержит {{ $db }} — такое общее имя переменной, вероятно, существует в вашем списке глобальных переменных. Так что если {{ variable }} в вашей строке соответствует ЛЮБОЙ из переменных в глобальной области видимости, вы получите ошибочные результаты.


Что теперь должен ты сделаешь? Просто объявите свой $pippo данные в массиве, так что у вас есть ассоциативные отношения для использования. (демонстрация)

function parseDbString(string $value = 'Looking for a good {{ $pippo }}'){
$lookup = ['pippo' => 'Pizza'];
return preg_replace_callback('/{{ \$(.*?) }}/', function($m) use ($lookup) {
return $lookup[$m[1]] ?? $m[0];  // null coalescing operator provides fallback
}, $value);
}
echo parseDbString();

В зависимости от степени контроля над входными данными, теперь вы можете позволить себе удалить $ до pippo в вашей входной строке — что устраняет несколько ненужных символов здесь и там.

И если вы все еще читаете, вы можете очистить все это с strtr() или же str_replace(), (демонстрация)

function parseDbString(string $value = 'Looking for a good {{ $pippo }}'){
$lookup = ['{{ $pippo }}' => 'Pizza'];  // this can be extended all you like!
return strtr($value, $lookup);
}
echo parseDbString();
3

Другие решения

это хорошо работает со мной после возврата значения

function parseDbString(string $value = 'Looking for a good {{$pippo}}') {
$pippo = 'Pizza';
return preg_replace_callback('/{{(.*?)}}/', function($res) use ($pippo) {
// $val=${trim($res[1])}; Returns "Undefined variable: $pippo"$val = @eval("return " . trim($res[1]) . ";"); // Returns "Looking for a good Pizza"return isset($val) ? $val : $res[0];
}, $value);

return $value;
}

но если вы хотите, чтобы он был более динамичным, вы можете использовать функцию под ним, вы можете передать $ data в виде массива, например [‘$ pippo’ => ‘pizza’] и передать строку во втором параметре

function parseDbString2($data , $string) {
$parsed = preg_replace_callback('/{{(.*?)}}/', function ($matches) use ($data) {
list($shortCode, $index) = $matches;

if (isset($data[$index])) {
return $data[$index];
} else {
throw new \Exception("Shortcode {$shortCode} not found ", 1);
}
}, $string);

return $parsed;
}

надеюсь, это поможет вам

2

Чувак, ты используешь какой-то странный код в стиле Perl. Проблема двойная $$ это вызывается PHP. Как только вы урежете один $ прочь это работает.

<?php

function parseDbString(string $value = 'Looking for a good {{ $pippo }}'){
$pippo='Pizza';
return preg_replace_callback('/{{(.*?)}}/', function($res) use ($pippo) {
$val=${substr(trim($res[1]), 1)}; // here trim the $ away from the matched string
return isset($val) ? $val : $res[0];
},$value);
}

echo parseDbString(); // prints "Looking for a good Pizza"

Проверьте вывод http://sandbox.onlinephpfunctions.com/code/86b3f37ac6c315d8e9a757c827455281df21fc89

2

замещать {{}} с другим разделителем.
Например:

class Test {
protected $item1 = 'I`m item-1';
protected $item2 = 'I`m item-2';
public function parseDbString($value = 'Looking for a good 1:$$item1 2:$$item2 5:$$item5 blabla'){
$m = '';
$result = $value;
if( preg_match_all('~\$\$(.+?)\s~s', $value, $m)){
foreach( $m[1] as $var ){
if( property_exists( $this, $var )){
$result = str_replace('$$' .$var, $this->{$var}, $result);
} else {
$result = str_replace('$$' .$var, 'UNDEFINED', $result);
}
}
}
return $result;
}
}
$test = new Test();
var_dump( $test->parseDbString() );
0