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?
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();
?>
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;
});
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.