create_function() - области видимости внутри метода класса и вне класса

Placido

Наблюдаю
Вопрос такой, как передать значение в тело функции внутри create_function()?
Два варианта кода
PHP:
$string = 'series 3-4';
$pattern = 'series[ ]*(\d+)[ ]*-[ ]*(\d+)';
$modifiers = 'um';
$replacement = 
'$match[2] == $match[1] + 1 ? "series $match[1] and $match[2]" : "series $match[1]-$match[2]"';
$newString = preg_replace_callback(
        '#' . $pattern . '#' . $modifiers,
        create_function('$match', '
        global $replacement;
        echo $replacement . "<br/>";
        return eval(\'return \' . $replacement . \';\');
         '),
        $string);
echo $newString;
//все в порядке, получаем
//$match[2] == $match[1] + 1 ? "series $match[1] and $match[2]" : "series $match[1]-$match[2]"
//series 3 and 4
и тот же код внутри метода класса, например
PHP:
Class A
{
    public function check()
    {
        $string = 'series 3-4';
        $pattern = 'series[ ]*(\d+)[ ]*-[ ]*(\d+)';
        $modifiers = 'um';
        $replacement = 
        '$match[2] == $match[1] + 1 ? "series $match[1] and $match[2]" : "series $match[1]-$match[2]"';
        $newString = preg_replace_callback(
             '#' . $pattern . '#' . $modifiers,
             create_function('$match', '
             global $replacement;
             echo $replacement;
             return eval(\'return \' . $replacement . \';\');
             '),
            $string);
        echo $newString;
    }
}

$a = new A;
$a->check();//пусто
в этом случае "echo $replacement;" внутри create_function() не выдает ничего, соответственно, "echo $newString;" тоже ничего не выдает.
Если в create_function() использовать свойство класса, то получаем ошибку
PHP:
...
create_function('$match', 
'return eval(\'return \' . $this->replacement . \';\');')
...
//Fatal error: Using $this when not in object context
Как решить эту проблему?
З.Ы. Об опасности использования eval() речь не идет - входящие данные будут тщательно проверяться.
 

Placido

Наблюдаю
Проблема решена, подсказали на stackoverflow. В качестве коллбека использовать отдельный метод:
PHP:
Class A
{
    private $replacement;
    public function check()
    {
        $string = 'series 3-4';
        $pattern = 'series[ ]*(\d+)[ ]*-[ ]*(\d+)';
        $this->replacement = '$match[2] == $match[1] + 1 ? "series $match[1] and $match[2]" : "series $match[1]-$match[2]"';
        $modifiers = 'um';
        $newString = preg_replace_callback(
                            '#' . $pattern . '#' . $modifiers,
                            array($this, 'replacementCallback'),
                            $string);
        echo $newString;
    }

    private function replacementCallback($match)
    {
        return eval('return ' . $this->replacement . ';');
    }
}

$a = new A;
$a->check();
 

fixxxer

К.О.
Партнер клуба
eval тут совершенно ни к чему. Что мешает написать код по нормальному в replacementCallback()?
 

fixxxer

К.О.
Партнер клуба
С евалом не так то, что его никогда не надо использовать.

Почему бы не написать так?
PHP:
Class A
{
    public function check()
    {
        $string = 'series 3-4';
        $pattern = 'series[ ]*(\d+)[ ]*-[ ]*(\d+)';
        $modifiers = 'um';
        $newString = preg_replace_callback(
                            '#' . $pattern . '#' . $modifiers,
                            array($this, 'replacementCallback'),
                            $string);
        echo $newString;
    }

    private function replacementCallback($match)
    {
        return $match[2] == $match[1] + 1 ? "series $match[1] and $match[2]" : "series $match[1]-$match[2]";
    }
}
 

Placido

Наблюдаю
С евалом не так то, что его никогда не надо использовать.[/php]
Другого способа я не нашел. Мне нужно, чтобы через форму на сайте можно было ввести код callback функции, которая затем использовалась бы в preg_replace_callback.
$match[2] == $match[1] + 1 ? "series $match[1] and $match[2]" : "series $match[1]-$match[2]
вводится пользователем через форму на сайте и может быть любой (с определенными ограничениями) callback-функцией.
 

Вурдалак

Продвинутый новичок
Проблема решена, подсказали на stackoverflow
— вот, кстати, если там так подсказали, то это то, о чем говорил Фанат. Это же чистый говнокод, create_function вообще давно морально устарела с появлением замыканий.
 

Placido

Наблюдаю
— вот, кстати, если там так подсказали, то это то, о чем говорил Фанат. Это же чистый говнокод, create_function вообще давно морально устарела с появлением замыканий.
Если вы видели мой вопрос на stackoverflow (ник такой же), то должны были заметить, что я изначально и использовал замыкания, но, поскольку на хостинге, где я тестирую код, до PHP 5.3 еще не дошли, возникла необходимость в использовании create_function.
 

Placido

Наблюдаю
Онлайн редактор с использованием регулярных выражений и callback-функций. Например, есть текст (телепрограмма), которую нужно отформатировать согласно определенным правилам. Скажем (пример реальный) есть множество строк, в которых обозначение серий вида (1-2 с.) нужно привести к единому формату. Смежные серии (1-2, 3-4, 112-113 и т.д.) нужно привести к виду 1 и 2 с., 3 и 4 с. и т.д., а не смежные оставить как есть. Регулярным выражением - практически нереально (можно, но выражение будет километровое, если учесть, что есть сериалы с сотнями и тысячами серий), а коллбеком - элементарно:
PHP:
echo preg_replace_callback('#(\d+)[ ]*-[ ]*(\d+) (серии|с)\.#', 
                           '$match[2] == $match[1] + 1 ? "$match[1] и $match[2] с." : "$match[1]-$match[2] с."',
                           $text);
Но формат программы может меняться и коллбек-функции необходимо вводить прямо через форму на сайте.
 

fixxxer

К.О.
Партнер клуба
Ок, а если пользователь туда введет shell_exec("rm -rf /") ?
 

Placido

Наблюдаю
Ок, а если пользователь туда введет shell_exec("rm -rf /") ?
Пока право добавлять callback-функции есть только у меня, никто не внесет. Позже добавлю проверку на наличие запрещенных слов и выражений, куда войдет и shell_exec, eval и т.д. Возможно, callback-функции будут вводиться не напрямую, а с помощью мини-языка, в котором можно будет использовать только ограниченный набор конструкций и функций, которые необходимы для обработки текстов (например, только функции для работы со строками, логические операторы и математические функции), и которые после ввода будут преобразовываться в код.
 

fixxxer

К.О.
Партнер клуба
Позже добавлю проверку на наличие запрещенных слов и выражений, куда войдет и shell_exec, eval и т.д
Любой такого рода черный список можно обойти.
Возможно, callback-функции будут вводиться не напрямую, а с помощью мини-языка, в котором можно будет использовать только ограниченный набор конструкций и функций, которые необходимы для обработки текстов (например, только функции для работы со строками, логические операторы и математические функции), и которые после ввода будут преобразовываться в код.
Вот это правильное решение. Но в зависимости от необходимого набора инструкций, возможно, удобнее будет не генерировать php-код, а интерпретировать этот мини-язык. Это и безопаснее будет.
 

Placido

Наблюдаю
С евалом не так то, что его никогда не надо использовать.
Почему бы не написать так...
Спасибо! Действительно, eval() здесь не нужен. Вчера уставший был, и не понял смысл ответа.
PHP:
Class A
{
    private $replacement;
    public function check()
    {
        $string = 'series 3-4';
        $pattern = 'series[ ]*(\d+)[ ]*-[ ]*(\d+)';
        $this->replacement = '$match[2] == $match[1] + 1 ? "series $match[1] and $match[2]" : "series $match[1]-$match[2]"';
        $modifiers = 'um';
        $newString = preg_replace_callback(
                            '#' . $pattern . '#' . $modifiers,
                            create_function('$match', 'return ' . $this->replacement . ';'),
                            $string);
        echo $newString;
    }
}

$a = new A;
$a->check();//series 3 and 4
 

Вурдалак

Продвинутый новичок
Вот опять-таки, если данные в произвольном формате, что приходится составлять какие-то регулярки для обработки, то встаёт вопрос: откуда вообще эти данные? Если они предназначены для тебя, то почему нельзя их представить в таком формате, который было бы удобно обрабатывать?
 

Placido

Наблюдаю
Данные - телевизионные программы, которые присылают телеканалы. У разных телеканалов формат разный, причем он периодически меняется. А нужно привести к единому виду, чтобы разместить эти телепрограммы у себя на сайте.
 

Placido

Наблюдаю
Да, я понимаю, что в данном контексте это одно и то же. Просто код стал короче.
 
Сверху