我正在编写简单的模板引擎和带有问题的堆栈:$this
即使在取消设置后也会进入eval范围。
class foo
{
public function method()
{
$code = 'var_dump(isset($this));';
unset($this);
var_dump(isset($this)); // produce: boolean false
eval($code); // produce: boolean true
}
}
$foo = new foo;
$foo ->method();
如何在不修改$code
值的情况下避免这种情况?
答案 0 :(得分:5)
我建议您创建unbound closure
,其中$this
无法访问或可能被替换。
注意:强> 的
Closure
可以使用,因为提到了@ invisal 。Closure::bindTo
自PHP 5.4.0以来可用。Anonymous functions
不应从执行上下文继承$this
。它从PHP 5.4.0开始启用。只需从PHP 5.3.0中的示例中删除$evUl = $evUl->bindTo(null);
,它就可以按预期工作。示例:的
<?php
header('Content-Type: text/plain');
class foo {
public function method() {
$code = 'var_dump(isset($this));';
$evUl = function()use($code){ eval($code); };
$evUl = $evUl->bindTo(null);
$evUl();
}
}
$foo = new foo();
$foo->method();
?>
节目:
bool(false)
答案 1 :(得分:2)
$this
可以取消设置。
Zend_Framework 1.x有一个实例,他们在Zend_Service_WindowsAzure_Storage_Batch
类
注意,这不会取消设置实例,只会引用函数范围内的实例。
尽管有文档记录,这是自php 5.1.6以来观察到的行为。
我唯一猜测为什么这不适用于eval是它必须创建一个新的执行上下文,其中$ this被恢复到当前范围。该样本展示了这种行为。
class A {
public function test(){
print "Before Unset\n";
print_r($this);
unset($this);
print "After Unset\n";
print_r($this);
print "Evaled\n";
eval("print_r(\$this);");
print "After Eval\n";
print_r($this);
}
}
$a = new A();
$a->test();
输出为:
Before Unset
A Object
(
)
After Unset
PHP Notice: Undefined variable: this in /home/cgray/q.php on line 9
PHP Stack trace:
PHP 1. {main}() /home/cgray/q.php:0
PHP 2. A->test() /home/cgray/q.php:17
Evaled
A Object
(
)
After Eval
A Object
(
)
您可以回避此问题的一种方法是在评估的上下文中取消设置$this
。
class foo
{
public function method()
{
$code = 'var_dump(isset($this));';
unset($this);
var_dump(isset($this));
eval("unset(\$this);".$code);
}
$foo = new foo;
$foo->method();
更新
似乎include
函数范围内的文件也将恢复$this
答案 2 :(得分:1)
$this
是一个伪变量,不能取消设置。
答案 3 :(得分:1)
似乎unset($this)
只能在函数范围内工作。我已通过测试确认。
class foo
{
public function method()
{
unset($this);
var_dump(isset($this));
}
public function method2() {
var_dump(isset($this));
}
}
在函数eval中运行的$code
不在函数method
内运行。通过$code = 'echo __FUNCTION__;'