`$this` 在范围内的行为是否从 PHP 5.3.29 更改为 5.5.24?

Did the behavior of `$this` in a scope change from PHP 5.3.29 to 5.5.24?

简短问题:范围内 $this 的行为是否从 PHP 5.3.29 更改为 5.5.24?我在 PHP 5 Changelog.

中找不到任何相关更改

详情: 在 中,我认为我的问题有解决方案(在 PHPUnit 中,期望以数组作为参数的方法调用)。这是我的解决方案

public function test_actionUpload_v10MasterdataFile()
{
    /*
     * Create a stub to disable the original constructor.
     * Exposing data and rendering are stubbed.
     * All other methods behave exactly the same as in the real Controller.
     */
    $sut = $this->getMockBuilder('MasterdataController')
                ->setMethods(array('exposeAndSaveDataLines', 'render'))
                ->disableOriginalConstructor()
                ->getMock();

    $sut->expects($this->once())
        ->method('exposeAndSaveDataLines')
        ->will($this->returnCallback(function($lines) {
            $expectedLines = include ($this->dataDir() . 'ExpectedLines.php');
            PHPUnit_Framework_Assert::assertTrue($this->similar_arrays($lines, $expectedLines));
        }));

    // Execute the test
    $sut->actionUpload();
}

它在我的本地环境(PHP 5.5.24,Zend Engine v2.5.0)上运行,但是当我将代码复制到我们的测试服务器(PHP 5.3.29,Zend引擎 v2.3.0),这不起作用,因为这一行:

$expectedLines = include ($this->dataDir() . 'ExpectedLines.php');

错误是:

Using $this when not in object context

这可能是由于 PHP 版本,还是我应该去别处寻找它在一台服务器上失败但在另一台服务器上失败的原因?

原因是您当时更改了范围。我也不确定发生了什么变化,但是您的代码应该 不会 起作用,至少 PHP 范围规则的定义方式是这样。以下是您解决该问题的代码:

$sut->expects($this->once())
    ->method('exposeAndSaveDataLines')
    ->will($this->returnCallback(function($lines) {
        $expectedLines = include ($this->dataDir() . 'ExpectedLines.php');
        PHPUnit_Framework_Assert::assertTrue($this->similar_arrays($lines, $expectedLines));
    }));

returnCallback 函数内部,技术上你仍然是 'inside' class,但你需要从外部 导入 变量作用域(PHP 中的这种行为不同于其他语言,例如 Javascript 不需要这种行为)。它应该是这样工作的:

$self = $this; // Not necessary after PHP 5.4 where you can just use($this)
$sut->expects($this->once())
        ->method('exposeAndSaveDataLines')
        ->will($this->returnCallback(function($lines) use($self) {
            $expectedLines = include ($self->dataDir() . 'ExpectedLines.php');
            PHPUnit_Framework_Assert::assertTrue($self->similar_arrays($lines, $expectedLines));
        }));

是的,5.4中引入了一个重要的区别:

  • Added closure $this support back.

意思是,在 5.3 中,匿名函数中的 $this 没有引用任何东西,周围的上下文没有被保留。 5.4 添加了对 this 的支持(返回),因此匿名函数中的 $this 引用周围上下文中的 $this。之前的解决方法是:

$_this = $this;
function () use ($_this) {
    $_this->foo();
};