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

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

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

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

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

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

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» включены, я хотел бы избавиться от него, когда покончу с этим. Я не хочу, чтобы люди полагались на функцию, которая не всегда существует . Надеюсь, теперь все ясно. Также приветствуются предложения, не связанные с взломом!

Из руководства по функциям 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); } с 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 .

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

Начиная с 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 , так как в качестве параметра оно будет принимать только имя функции.

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

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

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

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

Еще один вариант, который вы используете, – это использовать 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); } с 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); } с 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); } 

Никаких функций нет, и код не так уж длинный. знак равно

Определение начальной функции выглядит так:

 // 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'; }; 

Нет. Но удаление определения функции глупо.
Либо вы определяете функцию по-другому в блоке 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(); } ... 

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

Я тоже вижу очень мало причин позволять функции «жить» или «не жить» в зависимости от состояния, но, чтобы ответить на вопрос, это возможно использование анонимных функций. @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); } 

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

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

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

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

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

 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; 

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