如何在调用者作用域中设置变量,例如 extract() 函数
我知道直接在调用者范围内设置变量可能不是一个好主意。 然而,PHP extract()
函数正是这样做的!我想编写自己的 extract()
版本,但无法弄清楚如何实际在调用者中设置变量。有什么想法吗? 我最接近的是使用 debug_backtrace()
修改调用者的 args
,但这并不完全相同......
I know that directly setting a variable in the scope of caller is probably not a good idea.
However, the PHP extract()
function does exactly that! I would like to write my own version of extract()
but cannot figure out how to actually go about setting the variables in the caller. Any ideas?
The closest I have come is modifying the caller's args
using debug_backtrace()
, but this is not exactly the same thing...
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
您无法修改父作用域中的局部变量 - PHP 不公开 extract() 使用的方法。
此外,从 debug_stacktrace() 返回的内容并没有神奇地链接到真实的堆栈。您无法修改它,希望您的修改生效!
You can't modify local variables in a parent scope - the method which extract() uses is not exposed by PHP.
Also, what you get back from debug_stacktrace() isn't magically linked to the real stack. You can't modify it and hope your modifications are live!
您只能在 PHP 扩展中执行此操作。如果调用内部 PHP 函数,它将不会在新的 PHP 作用域中运行(即不会创建新的符号表)。因此,您可以通过更改全局
EG(active_symbol_table)
来修改“父作用域”。基本上,该函数的核心将执行类似于
extract
的操作,其核心是:但是,有一些细微差别。请参阅
extract
的实现,但请记住,执行您想要的操作的函数不需要那么复杂;extract
中的大部分代码都是为了处理它接受的几个选项。You could only do it in a PHP extension. If you call an internal PHP function, it will not run in a new PHP scope (i.e., no new symbol table will be created). Therefore, you can modify the "parent scope" by changing the global
EG(active_symbol_table)
.Basically, the core of the function would do something like
extract
does, the core of which is:There are, however, a few nuances. See the implementation of
extract
, but keep in mind a function that did what you wanted wouldn't need to be as complex; most of the code inextract
is there to deal with the several options it accepts.您可以滥用 $GLOBALS 范围从函数的调用者读取和写入变量。请参阅下面的示例函数,该函数从调用者范围读取和写入变量。
是的,我知道滥用 $GLOBAL 范围是肮脏的,但是嘿,我们来这里是为了解决问题不是吗? :)
该函数返回以下输出:
You can abuse the $GLOBALS scope to read and write variables from the caller of your function. See below sample function, which reads and write variables from the caller scope.
And yes, I know its dirty to abuse the $GLOBAL scope, but hey, we're here to fix problems ain't we? :)
The function returns the following output:
这取决于你有多需要这样做。如果只是为了源美,那就另想办法。如果由于某种原因,您确实需要扰乱父作用域,那么总有办法。
解决方案 1
最安全的方法是实际上使用提取本身来完成这项工作,因为它知道这个技巧。假设您想要创建一个提取数组元素的函数,但所有名称都倒着 - 非常奇怪! -,让我们通过简单的数组到数组转换来完成此操作:
这里没有魔法。
解决方案 2
如果您需要的不仅仅是 extract 的功能,请使用 eval 和 var_export。是的,我知道,我知道,请大家冷静下来。不,评估并不邪恶。 Eval 是一种电动工具,如果不小心使用它可能会很危险 - 因此请小心使用。 (如果您只评估 var_export 生成的内容,就不会出错 - 即使您从不受信任的来源将值放入数组中,它也不会提供任何入侵方式。数组元素表现良好。)
这几乎是一样的,只是你可以在 eval 中做更多的事情。当然,它的速度要慢得多。
然而,事实上,没有办法通过一次调用来做到这一点。
It depends on how badly you need to do this. If it's only for source beauty, find another way. If, for some reason, you really need to mess with parent scope, there's always a way.
SOLUTION 1
The safest method would be to actually use extract itself for this job, since it knows the trick. Say you want to make a function that extracts elements of an array but with all the names backwards - pretty weird! -, let's do this with a simple array-to-array transformation:
No magic here.
SOLUTION 2
If you need more than what extract does, use eval and var_export. YES I KNOW I KNOW everybody calm down please. No, eval is not evil. Eval is a power tool and it can be dangerous if you use it without care - so use it with care. (There is no way to go wrong if you only eval something that's been generated by var_export - it doesn't give any way to intrusions even if you put values in your array from an untrusted source. Array elements behave well.)
This is almost the same, except that you can do a lot more in eval. And it's significantly slower, of course.
However, indeed, there is no way to do it with a single call.