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