简体   繁体   English

在 PHP 中在运行时删除一个函数(没有 runkit 扩展)

[英]Removing a function at runtime in PHP (without the runkit extension)

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.我在“if”块中声明了一个递归函数,并希望该函数仅在“if”块中“有效”。 I don't want this function to be callled outside this block.我不希望在这个块之外调用这个函数。

I found out runkit_function_remove but runkit isn't enabled on my Web host.我发现了runkit_function_remove但我的 Web 主机上没有启用runkit Is there another way to do that?有没有另一种方法可以做到这一点?

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 live when Magic Quotes are ON, I wanted to get rid of it when I'm done with it.由于“stripslashes_deep”只会在魔术引号是,我想摆脱它,当我用它做。 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!也欢迎非 hacky 解决方案建议!

From the PHP Manual on user-defined 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 中的所有函数和类都具有全局作用域 - 即使它们是在函数内部定义的,它们也可以在函数外部调用,反之亦然。 [...] PHP does not support function overloading, nor is it possible to undefine or redefine previously-declared functions. [...] PHP 不支持函数重载,也不可能取消或重新定义先前声明的函数。

The exception is through runkit .例外是通过runkit However, you could define your function as an anonymous function and unset it after you ran it, eg但是,您可以将函数定义为匿名函数并在运行后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.一些评论者正确指出(但现在在 PHP 中不再是问题),您不能在其内部调用匿名函数。 By using array_walk_recursive you can get around this limitation.通过使用array_walk_recursive您可以绕过这个限制。 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 .给它一个合适的名字,比如stripslashes_gpc_callback

Note: edited and condensed after comments注:评论后编辑和浓缩

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 unset the variable.不幸的是,如果您在匿名函数中定义了一个常规函数,即使您取消设置该变量,它也将是全局可用的。 (I don't really see the benefit of that. I hope it's a blunder to be corrected later :-) (我真的没有看到这样做的好处。我希望以后能纠正它是一个错误:-)

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

Simple answer: no.简单的回答:没有。

However, you can try placing the function inside a namespace, a class or 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()也是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.那里没有函数,代码也不长。 =) =)

No. But removing a function definition is silly.不。但是删除函数定义是愚蠢的。
Either you're defining the function differently in an else block 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.我不知道您要做什么或为什么要删除函数定义,但希望这可以帮助您以更简洁的方式完成此操作。

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. @Gordon 已经概述了它是如何完成的。 Starting with PHP 5.3.0, you can also use anonymous functions as follows.从 PHP 5.3.0 开始,您还可以使用匿名函数,如下所示。 (There is no functional difference to the create_function() approach.) (与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);
}

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.在这种情况下,这可能不适合您,因为您想破坏该功能,但我认为这是谈论功能替换的正确地方。

It's impossible without runkit_function_remove.没有 runkit_function_remove 是不可能的。 Runkit is the extension intended to do things like this. Runkit 是用于执行此类操作的扩展。

Are you sure that the function lives after the if-block is completed?您确定该函数在 if 块完成后仍然存在吗? I would have thought that if it were defined within the if-block, that it would become inaccessible afterward.我原以为如果它是在 if 块中定义的,之后它将变得不可访问。

I agree with Alix.我同意 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.您将获得减少内存使用的额外好处。

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.否则,就把它留在那里,不要再调用它。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM