<?php
class Foo
{
private $greeting;
public function greet(callable $callback)
{
return $callback->call($this); // KEY POINT
}
public function getGreeting()
{
return $this->greeting;
}
public function setGreeting($greeting)
{
$this->greeting = $greeting;
}
}
class Bar
{
public function sayHello()
{
$foo = new Foo();
return $foo->greet(function () {
// `$this` is not object `Bar` any more
// object `Foo` was bound to the closure scope
$this->setGreeting('Hello Foo');
return $this->getGreeting();
});
}
}
$bar = new Bar();
echo $bar->sayHello(); // Hello Foo
<?php // http://php.net/manual/kr/closure.bindto.php
class A {
function __construct($val) {
$this->val = $val;
}
function getClosure() {
//returns closure bound to this object and scope
return function() { return $this->val; };
}
}
$ob1 = new A(1);
$ob2 = new A(2);
$cl = $ob1->getClosure();
echo $cl(); // 1
$cl = $cl->bindTo($ob2); // KEY POINT
echo $cl(); // 2
<?php // Laravel Example
class FooController
{
private $finder;
private $mutator;
public function __construct(ModelFinder $finder, ModelMutator $mutator)
{
$this->finder = $finder;
$this->mutator = $mutator;
}
public function updateFoo(Request $request, int $id)
{
$dto = $request->getDto();
$foo = $this->finder->findById($id);
$self = $this; // Cache `$this` to `$self`
\DB::transaction(function () use ($dto, $foo, $self) { // KEY POINT
$self->mutator->mutateFooByDto($dto);
$foo->save();
});
return new JsonResponse(null, Response::HTTP_NO_CONTENT);
}
}
\DB::transaction( 에 전달되는 callback안에서 $self === $this 입니다.
위에 두 예제는 명시적으로 바인딩한 반면, 여기서는 바인딩이 없는 이상 $this는 함수 외부의 scope을 따라가는 것 같아요.
http://php.net/manual/en/functions.anonymous.php
As of PHP 5.4.0, when declared in the context of a class, the current class is automatically bound to it, making $this available inside of the function's scope. If this automatic binding of the current class is not wanted, then static anonymous functions may be used instead.5.3 까지는 $this 바인딩을 지원 안했던 것 같고요. 5.4부터는 자동 바인딩되는군요.
7.1에서는 동일한 변수명을 사용할 수 없는 제약 조건이 생기기도 했고요.
Anonymous functions may not close over superglobals, $this, or any variable with the same name as a parameter.