在 PHP 中在运行时删除一个函数(没有 runkit 扩展)
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2120044/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Removing a function at runtime in PHP (without the runkit extension)
提问by AlexV
I know this question seems hacky and weird, but is there a way to remove a function at runtime in PHP?
我知道这个问题看起来很奇怪,但是有没有办法在运行时在 PHP 中删除函数?
I have a recursive function declared in a "if" block and want that function to be "valid" only in that "if" block. I don't want this function to be callled outside this block.
我在“if”块中声明了一个递归函数,并希望该函数仅在“if”块中“有效”。我不希望在这个块之外调用这个函数。
I found out runkit_function_removebut runkitisn't enabled on my Web host. Is there another way to do that?
我发现了runkit_function_remove但我的 Web 主机上没有启用runkit。有没有另一种方法可以做到这一点?
BTW I only support PHP 5.1.0.
顺便说一句,我只支持 PHP 5.1.0。
Edit:I knew my question was hacky but here is the exact thing I want to do:
编辑:我知道我的问题很棘手,但这是我想要做的确切事情:
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');
}
Since "stripslashes_deep" will only livewhen Magic Quotes are ON, I wanted to get rid of it when I'm done with it. I don't want people to rely on a function that isn't always there. I hope it's clearer now. Non-hacky solution suggestions are welcome too!
由于“stripslashes_deep”只会活在魔术引号是,我想摆脱它,当我用它做。我不希望人们依赖并不总是存在的功能。我希望现在更清楚了。也欢迎非 hacky 解决方案建议!
采纳答案by Gordon
From the PHP Manual on Functions:
来自PHP 函数手册:
All functions and classes in PHP have the global scope - they can be called outside a function even if they were defined inside and vice versa. [...] PHP does not support function overloading, nor is it possible to undefine or redefine previously-declared functions.
PHP 中的所有函数和类都具有全局作用域 - 即使它们是在函数内部定义的,它们也可以在函数外部调用,反之亦然。[...] PHP 不支持函数重载,也不可能取消或重新定义先前声明的函数。
The exception is through runkit. However, you could define your function as an anonymous functionand unsetit after you ran it, e.g.
例外是通过 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);
}
Some commentors correctly pointed out (but not an issue any longer in PHP nowadays), you cannot call an anonymous function inside itself. By using array_walk_recursiveyou can get around this limitation. Personally, I would just create a regular function and not bother about deleting it. It won't hurt anyone. Just give it a proper name, like stripslashes_gpc_callback.
一些评论者正确指出(但现在在 PHP 中不再是问题),您不能在其内部调用匿名函数。通过使用array_walk_recursive您可以绕过这个限制。就我个人而言,我只会创建一个常规函数,而不会为删除它而烦恼。它不会伤害任何人。只需给它一个适当的名称,例如stripslashes_gpc_callback.
Note: edited and condensed after comments
注:评论后编辑和浓缩
回答by Simon Rigét
As of PHP 5.3 you can use an anonymous function:
从 PHP 5.3 开始,您可以使用匿名函数:
$anonymous_function = function($value){
// do stuff
};
Call it like this:
像这样调用它:
$returned_value = $anonymous_function('some parameter');
To delete the function, just unset the variable:
要删除函数,只需取消设置变量:
unset($anonymous_function);
Here is an example of how to implement your 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);
}
};
anonymous functions has no name. So you can't use array_map, as it will only take a function name as parameter.
匿名函数没有名字。所以你不能使用array_map,因为它只会将函数名称作为参数。
anonymous functions has the variable scope. So you have to declare the variable containing the function as global, to reach it from within a recursive function.
匿名函数具有可变作用域。因此,您必须将包含该函数的变量声明为全局变量,以便从递归函数中访问它。
Unfortunately if you define a regular function inside the anonymous function, it will be globally available, even after you unsetthe variable. (I don't really see the benefit of that. I hope it's a blunder to be corrected later :-)
不幸的是,如果您在匿名函数中定义了一个常规函数,即使您取消设置该变量,它也将是全局可用的。(我真的没有看到这样做的好处。我希望以后能纠正它是一个错误:-)
回答by Chris Caviness
Initial function definition looks like:
初始函数定义如下所示:
// 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';
};
}
if you have a test condition that allows you to rewrite code:
如果您有一个允许您重写代码的测试条件:
// somewhere in your code
if (<replacethefunctioncondition>) {
$GLOBALS['thefunction'] = function() {
echo 'bar';
};
}
if you are overloading in another include that will be loaded before or after the original file:
如果您在另一个将在原始文件之前或之后加载的包含中重载:
// 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';
};
回答by Alix Axel
Simple answer: no.
简单的回答:没有。
However, you can try placing the function inside a namespace, a classor even within another function- but I think that's not what you're looking for.
但是,您可以尝试将函数放置在命名空间、类甚至另一个函数中- 但我认为这不是您想要的。
One other option you have is to use debug_backtrace()inside the said function to check what file / line / etc... is calling it - it's hackish I know, but so is runkit_function_remove().
您拥有的另一种选择是debug_backtrace()在所述函数内部使用来检查正在调用它的文件/行/等......我知道这是hackish,但runkit_function_remove().
Edit - Too bad you don't run PHP 5.3+, otherwise you could just do:
编辑 - 太糟糕了,你没有运行 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);
}
For older versions of PHP you still have this option:
对于旧版本的 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);
}
No functions there, and the code is not that long. =)
那里没有函数,代码也不长。=)
回答by Carson Myers
No. But removing a function definition is silly.
Either you're defining the function differently in an elseblock and need the definition to change based on program state, effectively making your project closer and closer to impossible to debug, or code that calls that function will crash and burn if it didn't happen to get defined at runtime.
不。但是删除函数定义是愚蠢的。
要么您在else块中以不同的方式定义函数,并且需要根据程序状态更改定义,从而有效地使您的项目越来越接近无法调试,要么调用该函数的代码如果没有发生就会崩溃并烧毁在运行时定义。
You should put this function in a class:
你应该把这个函数放在一个类中:
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 */
}
}
or, if you only want the condition tested once,
或者,如果您只想测试一次条件,
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();
}
...
I don't know what you are trying to do or why you want to remove a function definition but hopefully this can help you do it in a cleaner way.
我不知道您要做什么或为什么要删除函数定义,但希望这可以帮助您以更简洁的方式完成此操作。
回答by Pekka
I too see very little reason to let a function "live" or "not live" depending on a condition, but to answer the question, it's sort of possible using anonymous functions. @Gordon already outlined how it's done. Starting with PHP 5.3.0, you can also use anonymous functions as follows. (There is no functional difference to the create_function()approach.)
我也认为没有什么理由让函数根据条件“存活”或“不存活”,但要回答这个问题,使用匿名函数是有可能的。@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);
}
回答by Erdin? ?orbac?
There may be another solution for replacing functions by changing usage of them like this ;
可能有另一种解决方案,可以通过像这样改变函数的用法来替换函数;
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;
Maybe this not for you in this situation as you wanted to destroy the function but i though this is right place to talk about replacement of functions.
在这种情况下,这可能不适合您,因为您想破坏该功能,但我认为这是谈论功能替换的正确地方。
回答by Teekin
It's impossible without runkit_function_remove. Runkit is the extension intended to do things like this.
没有 runkit_function_remove 是不可能的。Runkit 是用于执行此类操作的扩展。
Are you sure that the function lives after the if-block is completed? I would have thought that if it were defined within the if-block, that it would become inaccessible afterward.
您确定该函数在 if 块完成后仍然存在吗?我原以为如果它是在 if 块中定义的,之后它将变得不可访问。
回答by Bret Kuhns
I agree with Alix. You can, however, avoid the function being called from anywhere else by getting rid of the function. Rewrite the recursive function as an iterative loop. You'll have the added benefit of reduce memory usage.
我同意 Alix。但是,您可以通过删除该函数来避免从其他任何地方调用该函数。将递归函数重写为迭代循环。您将获得减少内存使用的额外好处。
UPDATE:with your code example, I'm not sure why you feel the need to prevent this function from being called again. It simply formats some strings in an array recursively... again, you could do this iteratively and avoid having a function in the first place. Otherwise, just leave it there and don't call it again.
更新:对于您的代码示例,我不确定您为什么觉得需要防止再次调用此函数。它只是递归地格式化数组中的一些字符串......同样,您可以迭代地执行此操作并首先避免使用函数。否则,就把它留在那里,不要再调用它。

