PHP Fatal error: Cannot use $this as parameter

2019-02-20 05:19发布

I've the following PHP method which is part of the codebase which was working fine:

<?php
class HooksTest extends DrupalTestCase {
  public function testPageAlterIsLoggedIn() {
    $this->drupal->shouldReceive('userIsLoggedIn')
      ->once()
      ->andReturn(TRUE);
    $this->drupal->shouldReceive('drupalPageIsCacheable')
      ->once()
      ->andReturnUsing(function ($this) {
        return $this;
      });
    $page = [];
    $cacheable = $this->object->pageAlter($page);
    $this->assertFalse($cacheable);
  }
}

The code was passing all the CI tests before (using phpunit).

However now when I'm invoking the file via php HooksTest.php, I've got the following error:

PHP Fatal error: Cannot use $this as parameter in HooksTest.php on line 11

Fatal error: Cannot use $this as parameter in HooksTest.php on line 11

I've tested with PHP 7.1, 7.2 and same issue. I believe it was working in PHP 5.6.

How can I convert above code to have the same meaning?

Does removing $this from the function parameter should be enough?

3条回答
仙女界的扛把子
2楼-- · 2019-02-20 06:10

Yeah, as previously stated by aynber, you can't pass in $this as a function param. By doing so, you're basically redeclaring it. You should just remove it as a function param.

查看更多
smile是对你的礼貌
3楼-- · 2019-02-20 06:16

If you want it to work the same way it did before, you should not remove $this as a parameter. You should change the name of the parameter to something else, and change the corresponding variable name in the closure.

Through PHP 5.6, using $this as a parameter in a closure in a class method would mask the $this referring to the parent object. For example:

class Example
{
    public function test ($param) {
        $closure = function ($whatever) {      // $this not used as parameter
            return $this;                      // $this refers to the Example object
        };
        return $closure($param);
    }

    public function test2 ($param) {
        $closure = function($this) {          // $this used as parameter
            return $this;                     // $this no longer refers to Example object
        };
        return $closure($param);
    }

}

$ex = new Example;
$not_masked = $ex->test('foo');
$masked = $ex->test2('foo');

var_dump($not_masked, $masked);

Working example on 3v4l.org

In PHP 5.6, $masked would be the string 'foo', not the $ex object.

According to the output for the different versions that you can see at the 3v4l.org link, there was a brief period from 7.0.0-7.0.6 where the $this parameter would apparently be disregarded in favor of the object self-reference. I assume they disallowed using $this as a parameter in later versions to avoid the ambiguity of what $this actually referred to in the closure scope.

It looks like this was just confusing naming in the original code. In order to make it work as before:

->andReturnUsing(function ($anyOtherName) {
    return $anyOtherName;
});
查看更多
萌系小妹纸
4楼-- · 2019-02-20 06:19

Just skip $this argument, change

function ($this) {
    return $this;
}

to

function () {
    return $this;
}

Look at Example #5 Automatic binding of $this on Anonymous functions page:

<?php
class Test
{
    public function testing()
    {
        return function() {
            var_dump($this);
        };
    }
}
$object = new Test;
$function = $object->testing();
$function();
?>
查看更多
登录 后发表回答