Can you use $ this in a callback to get the protected properties of a mocked class in phpunit?

Can you use $ this inside a callback to get the protected properties of a mocked class in phpunit? Or is there another way to achieve this?

$mock = $this->getMock('A', array('foo')); $mock->expects($this->any())->method('foo')->will( $this->returnCallback(function() { return $this->bar; })); 

This can be really useful if you are thinking about introducing mocking objects. Sometimes a class has a hard-coded dependency for another class, but it creates it using a method that you could theoretically scoff at creating and mocking an object instead of a hard-coded object. Take a look at another example.

 class A { protected $bar = "bar"; public function foo () { $b = new B(); return $b->fizz($this->bar); } } class B { public function fizz ($buzz) { return $buzz; } } 

But let's say class B does something bad, and I would like to replace it with a layout.

  $mockB = $this->getMock('B'); // (...) - and probably mock other things $mockA = $this->getMock('A', array('foo')); $mockA->expects($this->any())->method('foo')->will( $this->returnCallback(function() use ($mockB) { return $mockB->fizz($this->bar); })); 

As much as possible?

Of course, without any surprise, at present, if I do this as above, I get the error:

 PHP Fatal error: Using $this when not in object context in (...) 

Using the use keyword, I can inherit $ mockA from the parent scope:

  $mockB = $this->getMock('B'); // (...) - and probably mock other things $mockA = $this->getMock('A', array('foo')); $mockA->expects($this->any())->method('foo')->will( $this->returnCallback(function() use ($mockA, $mockB) { return $mockB->fizz($mockA->bar); })); 

but in this way I try to open the access panel as public, and I get:

 PHP Fatal error: Cannot access protected property (...) 
+7
source share
3 answers

As other answers pointed out, $this can be used in Closures with PHP 5.4. A lesser known fact is that you can bind a closure to arbitrary objects and actually make their private properties available. You need bindTo() , which returns a new closure with a different context.

 $cb = function() { return $this->bar; }; $cb = $cb->bindTo($mockA); 

Or, more precisely, your example would look like this:

  $mockB = $this->getMock('B'); // (...) - and probably mock other things $mockA = $this->getMock('A', array('foo')); $fooCallback = function() use (&$mockB) { return $mockB->fizz($this->bar); }; $mockA->expects($this->any())->method('foo')->will( $this->returnCallback($fooCallback->bindTo($mockA))); 
+7
source

As dev-null-dweller pointed out, in PHP 5.4 you can use $ this in closure as if you were working normally in this method.

In 5.3, you can simulate this behavior by doing:

 public function getCallback(B $b) { $self = $this; return function() use($b, $self) { return $b->fizz($self->bar); }; } 
+1
source

Since php 5.4 you can use $this in closure, but you must return this callback from an object that contains these protected properties:

 class A { protected $bar = "bar"; public function foo () { $b = new B(); return $b->fizz($this->bar); } public function getCallback(B $b) { return function() use($b) { return $b->fizz($this->bar); }; } } class B { public function fizz ($buzz) { return $buzz; } } $mockA = new A; $mockB = new B; $callBack = $mockA->getCallback($mockB); var_dump($callBack() === $mockA->foo()); 

However, if you need to get the value of the protected properties, you must define a public getter for it. So the test will also work in php 5.3

0
source

All Articles