익명 함수는 클로저라고도 하며, 이름이 없는 함수입니다. 값이 와야 하는 자리에 function ($param) { ... }를 씁니다. 변수에 대입하거나, 다른 함수에 넘기거나, 반환합니다. use ($var)로 주변 코드의 변수를 가지고 다닐 수 있습니다.
모든 익명 함수는 내장 클래스 Closure의 객체이므로 저장하고, 전달하고, 나중에 $greet(...)로 호출할 수 있습니다.
use 키워드는 값으로 캡처한다
클로저는 스스로 바깥 변수를 볼 수 없습니다. use ($x)는 클로저가 실행될 때가 아니라 만들어지는 순간에 $x의 값을 클로저 안으로 복사합니다.
참조로 use: &$var
use (&$x)는 복사본이 아니라 변수 자체를 클로저에 줍니다. 클로저 안의 변경이 바깥에서 보이고, 바깥의 변경도 안에서 보입니다. 콜백이 합계를 더하거나 카운터를 유지하는 방법이 이것입니다.
makeCounter()를 호출할 때마다 새 $count가 만들어지고, 반환된 클로저가 함수가 반환된 뒤에도 그것을 살려 둡니다. "클로저"라는 이름이 바로 이것을 가리킵니다. 함수가 필요한 변수를 감싸 둡니다.
클로저를 콜백으로 넘기기
array_map(), array_filter(), usort(), array_walk() 같은 함수는 함수를 인수로 받습니다. 클로저를 쓰면 그 자리에서 필요한 만큼의 문장으로 작성할 수 있습니다.
본문이 표현식 하나라면 fn($p) => $p['price'] 같은 화살표 함수가 더 짧고 use도 필요 없습니다.
callable: 함수 이름, 메서드, strlen(...)
callable 타입의 매개변수는 클로저 이상을 받습니다. 함수 이름이 든 문자열, 객체와 메서드 이름이 든 배열, 클래스 이름과 정적 메서드 이름이 든 배열도 모두 해당합니다. PHP 8.1부터 일급 callable 문법 strlen(...)은 이 중 무엇이든 바로 Closure로 바꿉니다.
(...) 형태는 그 줄이 실행될 때 검사되므로 오타가 있으면 그 자리에서 Error를 던집니다. 'strtoupr' 같은 문자열은 누군가 호출하려 하기 전까지 그냥 문자열일 뿐입니다.
클래스 안의 클로저: $this와 static
메서드 안에서 만든 클로저는 $this가 자동으로 바인딩되므로 객체의 속성을 쓸 수 있습니다. $this가 필요 없다면 static function으로 표시하세요. 그러면 클로저가 객체를 붙잡아 두는 일도 막습니다.
use 빠뜨리기
가장 흔한 클로저 버그는 바깥 변수를 use에 나열하지 않고 쓰는 것입니다. 클로저 안에서는 그 변수가 존재하지 않습니다.
$minAge = 18;
$adults = array_filter($people, function ($p) {
return $p['age'] >= $minAge; // $minAge is not in use (...)
});
PHP prints: Warning: Undefined variable $minAge
안에서 $minAge는 null이고, 어떤 나이든 >= null 비교는 true이므로 모든 사람이 필터를 통과합니다. 경고를 숨기는 서버에서는 아무것도 알려 주지 않습니다. 변수를 use에 추가하세요.
자주 묻는 질문
PHP의 클로저는 무엇인가요?
function (...) { ... }로 만들어 변수에 저장하거나 인수로 넘기는 이름 없는 함수입니다. PHP는 이를 Closure 클래스의 객체로 표현합니다. 만들어진 스코프의 변수를 use (...)에 나열해 가지고 다닐 수 있습니다.
PHP 클로저에서 use 키워드는 무엇을 하나요?
use ($x)는 클로저가 만들어질 때 바깥 변수 $x를 클로저 안으로 복사합니다. 나중에 바깥에서 $x를 바꿔도 보이지 않습니다. 대신 변수를 공유해 양쪽으로 변경이 전달되게 하려면 use (&$x)로 쓰세요.
PHP에서 callable은 무엇인가요?
PHP가 호출할 수 있는 모든 것입니다. 클로저, 문자열로 된 함수 이름('strtoupper'), 배열 [$object, 'method']나 [ClassName::class, 'staticMethod'], __invoke()가 있는 객체입니다. 이 중 무엇이든 받으려면 callable 타입을, 확인하려면 is_callable()을 쓰세요.
PHP에서 strlen(...)은 무엇을 뜻하나요?
PHP 8.1의 일급 callable 문법입니다. strlen(...)은 함수를 호출하지 않고 Closure를 만듭니다. 메서드($obj->method(...))와 정적 메서드(Foo::bar(...))에도 동작하며, 문자열 이름과 달리 그 줄이 실행될 때 검사됩니다.
익명 함수 뒤에 세미콜론이 필요한가요?
대입할 때는 필요합니다. $f = function () { ... };는 대입문이므로 ;로 끝납니다. 빠뜨리면 구문 에러입니다. 인수로 바로 넘기는 클로저에는 자체 세미콜론이 필요 없습니다.