Подтвердить что ты не робот

Удаление функции во время выполнения в PHP

Я знаю, что этот вопрос кажется взломанным и странным, но есть ли способ удалить функцию во время выполнения на PHP?

У меня есть рекурсивная функция, объявленная в блоке "if", и хочу, чтобы эта функция была "действительной" только в этом блоке "if". Я не хочу, чтобы эта функция вызывалась вне этого блока.

Я узнал runkit_function_remove, но runkit isn 't включен на моем веб-хосте. Есть ли другой способ сделать это?

BTW Я поддерживаю только PHP 5.1.0.

Изменить: Я знал, что мой вопрос был взломан, но вот то, что я хочу сделать:

if (function_exists('get_magic_quotes_gpc') && @get_magic_quotes_gpc())
{
    function stripslashes_deep($value)
    {
        return is_array($value) ? array_map('stripslashes_deep', $value) : stripslashes($value);
    }

    $_POST = array_map('stripslashes_deep', $_POST);
    $_GET = array_map('stripslashes_deep', $_GET);
    $_COOKIE = array_map('stripslashes_deep', $_COOKIE);
    $_REQUEST = array_map('stripslashes_deep', $_REQUEST);

    //runkit_function_remove('stripslashes_deep');
}

Так как "stripslashes_deep" будет жить только тогда, когда Magic Quotes включены, я хотел бы избавиться от него, когда покончу с этим. Я не хочу, чтобы люди полагались на функцию, которая не всегда существует. Надеюсь, теперь это станет яснее. Предложения, не связанные с хаккой, тоже приветствуются!

4b9b3361

Ответ 1

Из Руководство по функциям PHP:

Все функции и классы в PHP имеют глобальную область действия - их можно вызывать вне функции, даже если они были определены внутри и наоборот. [...] PHP не поддерживает перегрузку функций, а также невозможно определить или переопределить ранее объявленные функции.

Исключение - через runkit. Однако вы можете определить свою функцию как анонимную функцию и unset после запуска, например

if (function_exists('get_magic_quotes_gpc') && @get_magic_quotes_gpc())
    $fn = create_function('&$v, $k', '$v = stripslashes($v);'); 
    array_walk_recursive(array(&$_GET, &$_POST, &$_COOKIE, &$_REQUEST), $fn);
    unset($fn);
}

Некоторые комментаторы правильно указали (но уже не проблема в PHP в настоящее время), вы не можете вызвать анонимную функцию внутри себя. Используя array_walk_recursive, вы можете обойти это ограничение. Лично я бы просто создал регулярную функцию и не беспокоился об ее удалении. Это никому не повредит. Просто дайте ему собственное имя, например stripslashes_gpc_callback.

Примечание: отредактировано и сжато после комментариев

Ответ 2

Начиная с PHP 5.3 вы можете использовать анонимную функцию:

$anonymous_function = function($value){
  // do stuff
};

Назовите его следующим образом:

$returned_value = $anonymous_function('some parameter');

Чтобы удалить функцию, просто отключите переменную:

unset($anonymous_function);

Вот пример того, как реализовать вашу функцию:

$stripslashes_deep = function (&$object){
  global $stripslashes_deep;
  if(is_array($object)) 
    foreach($object as &$value){ 
      if(is_array($value)) 
        $stripslashes_deep($value);
      else
        $value = stripslashes($value);
    }
};

анонимные функции не имеют имени. Таким образом, вы не можете использовать array_map, так как он будет использовать только имя функции в качестве параметра.

анонимные функции имеют переменную область. Таким образом, вы должны объявить переменную, содержащую функцию глобальную, для ее получения из рекурсивной функции.

К сожалению, если вы определите регулярную функцию внутри анонимной функции, она будет доступна в глобальном масштабе, даже после того, как вы отмените переменную. (Я не вижу в этом ничего хорошего. Надеюсь, что ошибка будет исправлена ​​позже:-)

Ответ 3

Простой ответ: нет.

Однако вы можете попробовать разместить функцию внутри пространства имен, класса или даже внутри другой функции, но я думаю, что не то, что вы ищете.

Еще одна опция, которую вы используете, - это использовать debug_backtrace() внутри указанной функции, чтобы проверить, какой файл/строка/etc... вызывает ее - это хакерское я знаю, но это также runkit_function_remove().


Изменить - Слишком плохо, что вы не запускаете PHP 5.3+, иначе вы могли бы просто сделать:

if (get_magic_quotes_gpc())
{
    $_GET = json_decode(stripslashes(json_encode($_GET, JSON_HEX_APOS)), true);
    $_POST = json_decode(stripslashes(json_encode($_POST, JSON_HEX_APOS)), true);
    $_COOKIE = json_decode(stripslashes(json_encode($_COOKIE, JSON_HEX_APOS)), true);
    $_REQUEST = json_decode(stripslashes(json_encode($_REQUEST, JSON_HEX_APOS)), true);
}

Для более старых версий PHP у вас все еще есть эта опция:

if (get_magic_quotes_gpc()) {
    $process = array(&$_GET, &$_POST, &$_COOKIE, &$_REQUEST);
    while (list($key, $val) = each($process)) {
        foreach ($val as $k => $v) {
            unset($process[$key][$k]);
            if (is_array($v)) {
                $process[$key][stripslashes($k)] = $v;
                $process[] = &$process[$key][stripslashes($k)];
            } else {
                $process[$key][stripslashes($k)] = stripslashes($v);
            }
        }
    }
    unset($process);
}

Никаких функций нет, и код не так длинный. =)

Ответ 4

Определение начальной функции выглядит следующим образом:

// includes/std_functions.php
if (! function_exists('the_function')) {
  function the_function() {
    global $thefunction;
    return call_user_func_array($thefunction, func_get_args());
  }
  $GLOBALS['thefunction'] = function() {
    echo 'foo';
  };
}

если у вас есть условие проверки, которое позволяет вам переписать код:

// somewhere in your code
if (<replacethefunctioncondition>) {
  $GLOBALS['thefunction'] = function() {
    echo 'bar';
  };
}

если вы перегружаете другой, включите, который будет загружен до или после исходного файла:

// includes/custom_functions.php
if (! function_exists('the_function')) {
  function the_function() {
    global $thefunction;
    return call_user_func_array($thefunction, func_get_args());
  }
}
$GLOBALS['thefunction'] = function() {
  echo 'bar';
};

Ответ 5

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

Вы должны поместить эту функцию в класс:

class foo {

    public function bar() {

        if( /* some condition */ ) {
            $this->baz();
        } else {
            $this->bazzer();
        }

    }

    private function baz() {

        /* if the if condition was met */

    }

    private function bazzer() {

        /* if the if condition failed */

    }

}

или, если вы хотите, чтобы одно только условие было проверено,

class foo {

    private $bar_function = NULL;

    public function __construct() {

        if( /* some condition */ ) {
            $this->bar_function = baz;
        } else {
            $this->bar_function = bazzer;
        }

    }

    public function bar() {

        $this->$bar_function();

    }
        ...

Я не знаю, что вы пытаетесь сделать или почему вы хотите удалить определение функции, но, надеюсь, это может помочь вам сделать это более чистым способом.

Ответ 6

Я тоже вижу очень мало причин, чтобы функция "живая" или "не живая" в зависимости от состояния, но чтобы ответить на вопрос, это вроде возможно использование анонимных функций. @Gordon уже рассказал, как это делается. Начиная с PHP 5.3.0, вы также можете использовать анонимные функции следующим образом. (Функциональная разница с подходом create_function() отсутствует.)

if (function_exists('get_magic_quotes_gpc') && @get_magic_quotes_gpc())
{
    $stripslashes_deep = function($value)
    {
        return is_array($value) ? array_map('stripslashes_deep', $value) : stripslashes($value);
    }

    $_POST = array_map($stripslashes_deep, $_POST);
    $_GET = array_map($stripslashes_deep, $_GET);
    $_COOKIE = array_map($stripslashes_deep, $_COOKIE);
    $_REQUEST = array_map($stripslashes_deep, $_REQUEST);

    unset ($stripslashes_deep);
}

Ответ 7

Это невозможно без runkit_function_remove. Runkit - это расширение, предназначенное для выполнения таких действий.

Вы уверены, что функция сохраняется после завершения if-блока? Я бы подумал, что если бы он был определен в if-блоке, то он стал бы недоступен впоследствии.

Ответ 8

Я согласен с Аликс. Однако вы можете избежать вызова функции из любого места, избавляясь от функции. Перепишите рекурсивную функцию как итеративный цикл. У вас будет дополнительное преимущество сокращения использования памяти.

UPDATE: с вашим примером кода, я не уверен, почему вы чувствуете необходимость предотвратить повторное вызов этой функции. Он просто форматирует некоторые строки в массиве рекурсивно... опять же, вы можете сделать это итеративно и не иметь функции в первую очередь. В противном случае просто оставьте его и не вызывайте его снова.

Ответ 9

Может быть другое решение для замены функций путем изменения их использования следующим образом:

function function1(){
 echo "1";
}

function function2(){
 echo "2";
}

if(FUNCTION_CHOOSER_CONDITION) $the_function = "function2";
else $the_function="function1";
$the_function(); //  displays 2 if condition is TRUE;

Возможно, это не для вас в этой ситуации, так как вы хотели уничтожить функцию, но я, хотя это подходящее место, чтобы говорить о замене функций.