2

我知道直接在调用者范围内设置变量可能不是一个好主意。然而,PHPextract()函数正是这样做的!我想编写自己的版本,extract()但无法弄清楚如何实际设置调用者中的变量。有任何想法吗?我最接近的是修改调用者的argsusing debug_backtrace(),但这并不完全相同......

4

4 回答 4

3

您不能修改父作用域中的局部变量 - extract() 使用的方法不会被 PHP 公开。

此外,您从 debug_stacktrace() 返回的内容并没有神奇地链接到真正的堆栈。您无法修改它,希望您的修改生效!

于 2010-06-27T15:42:14.033 回答
1

您只能在 PHP 扩展中执行此操作。如果调用内部 PHP 函数,它将不会在新的 PHP 范围内运行(即不会创建新的符号表)。因此,您可以通过更改全局EG(active_symbol_table).

基本上,函数的核心会做类似 dos 的事情extract,其核心是:

if (!EG(active_symbol_table)) {
    zend_rebuild_symbol_table(TSRMLS_C);
}
//loop through the given array
ZEND_SET_SYMBOL_WITH_LENGTH(EG(active_symbol_table),
    Z_STRVAL(final_name), Z_STRLEN(final_name) + 1, data, 1, 0);

但是,有一些细微差别。请参阅 的实现extract,但请记住,执行您想要的功能的功能不需要那么复杂;中的大部分代码extract用于处理它接受的几个选项。

于 2010-06-27T16:56:40.060 回答
1

您可以滥用 $GLOBALS 范围从函数的调用者读取和写入变量。请参见下面的示例函数,该函数从调用者范围读取和写入变量。

是的,我知道滥用 $GLOBAL 范围很脏,但是,嘿,我们是来解决问题的,不是吗?:)

function set_first_name($firstname) {
    /* check if $firstname is defined in caller */
    if(array_key_exists('firstname', $GLOBALS)) {
        $firstname_was = $GLOBALS['firstname'];
    } else {
        $firstname_was = 'undefined';
    }   

    /* set $firstname in caller */
    $GLOBALS['firstname'] = $firstname;

    /* show onscreen confirmation for debugging */
    echo '<br>firstname was ' . $firstname_was . ' and now is: ' . $firstname;
}  

set_first_name('John');

set_first_name('Michael');

该函数返回以下输出:

    <br>firstname was undefined and now is: John
    <br>firstname was John and now is: Michael
于 2012-08-25T21:26:13.013 回答
0

这取决于您需要执行此操作的程度。如果只是为了源美,那就另辟蹊径。如果出于某种原因,您真的需要弄乱父范围,总有办法。

解决方案 1

最安全的方法是实际使用 extract 本身来完成这项工作,因为它知道诀窍。假设您想创建一个函数来提取数组元素但所有名称都向后 - 很奇怪!-,让我们通过一个简单的数组到数组的转换来做到这一点:

function backwardNames($x) {
    $out = [];
    foreach($x as $key=>$val) {
        $rev = strrev($key);
        $out[$rev] = $val;
    }
    return $out;
}

extract(backwardNames($myArray));

这里没有魔法。

解决方案 2

如果您需要的不仅仅是extract,请使用evalvar_export。是的,我知道我知道,请大家冷静下来。不, eval 不是邪恶的。Eval 是一种电动工具,如果不小心使用它可能会很危险 - 所以要小心使用。(如果您只评估由 var_export 生成的内容,则不会出错 - 即使您将来自不受信任来源的值放入数组中,它也不会为入侵提供任何途径。数组元素表现良好。

function makeMyVariables() {
    $vars = [
        "a" => 4,
        "b" => 5,
    ];
    $out = var_export($vars,1);
    $out = "extract(".$out.");";
    return $out;
}

eval(makeMyVariables());   // this is how you call it
// now $a is 4, $b is 5

这几乎是一样的,只是你可以在 eval 中做更多的事情。当然,它的速度要慢得多。

然而,事实上,没有办法通过一次调用来做到这一点。

于 2017-07-18T15:49:01.960 回答