如何从eval范围中删除$ this?

时间:2013-06-13 02:06:42

标签: php eval

我正在编写简单的模板引擎和带有问题的堆栈:$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值的情况下避免这种情况?

4 个答案:

答案 0 :(得分:5)

我建议您创建unbound closure,其中$this无法访问或可能被替换。

注意:

    自从PHP 5.3.0开始,
  1. Closure可以使用,因为提到了@ invisal
  2. Closure::bindTo自PHP 5.4.0以来可用。
  3. PHP 5.3.0中的
  4. Anonymous functions不应从执行上下文继承$this。它从PHP 5.4.0开始启用。只需从PHP 5.3.0中的示例中删除$evUl = $evUl->bindTo(null);,它就可以按预期工作。
  5. 示例:

    <?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是一个伪变量,不能取消设置。

http://php.net/manual/en/language.oop5.basic.php

答案 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__;'

的测试确认