콜러블
콜러블 (Callables)
콜러블은 함수나 메서드에 대한 참조로, 다른 함수에 인자로 전달되어 호출될 수 있는 것을 말해요. 이 페이지에서는 콜러블이 무엇인지, 그리고 콜러블을 만드는 여러 가지 방법을 다뤄요.
본문
콜러블은 다른 함수에 인자로 전달되는 함수나 메서드에 대한 참조예요. 이것들은 callable 타입 선언으로 표현돼요.
<?php
function foo(callable $callback) {
$callback();
}
?>
일부 함수는 콜백 함수를 매개변수로 받는데, 예를 들어 array_map(), usort(), preg_replace_callback() 등이 있어요.
콜러블 만들기 (Creation of callables)
콜러블은 호출될 수 있는 무언가를 나타내는 타입이에요. 콜러블은 콜백 매개변수를 기대하는 함수나 메서드에 인자로 전달될 수도 있고, 직접 호출될 수도 있어요. callable 타입은 클래스 속성의 타입 선언으로는 사용할 수 없어요. 대신 Closure 타입 선언을 사용하세요.
콜러블은 여러 가지 방법으로 만들 수 있어요:
Closure객체- 함수 또는 메서드의 이름을 담은 문자열
- 인덱스 0에 클래스 이름 또는 객체, 인덱스 1에 메서드 이름을 담은 배열
__invoke()매직 메서드를 구현한 객체
Closure 객체는 익명 함수 문법, 화살표 함수 문법, 일급 콜러블 문법, 또는 Closure::fromCallable() 메서드를 사용해서 만들 수 있어요.
참고: 일급 콜러블(first-class callable) 문법은 PHP 8.1.0부터 사용할 수 있어요.
예제 #1 Closure를 사용한 콜백 예제
<?php
// Using anonymous function syntax
$double1 = function ($a) {
return $a * 2;
};
// Using first-class callable syntax
function double_function($a) {
return $a * 2;
}
$double2 = double_function(...);
// Using arrow function syntax
$double3 = fn($a) => $a * 2;
// Using Closure::fromCallable
$double4 = Closure::fromCallable('double_function');
// Use the closure as a callback here to
// double the size of each element in our range
$new_numbers = array_map($double1, range(1, 5));
print implode(' ', $new_numbers) . PHP_EOL;
$new_numbers = array_map($double2, range(1, 5));
print implode(' ', $new_numbers) . PHP_EOL;
$new_numbers = array_map($double3, range(1, 5));
print implode(' ', $new_numbers) . PHP_EOL;
$new_numbers = array_map($double4, range(1, 5));
print implode(' ', $new_numbers);
?>
PHP 8.1에서의 위 예제 출력:
2 4 6 8 10
2 4 6 8 10
2 4 6 8 10
2 4 6 8 10
콜러블은 함수 또는 정적 메서드의 이름을 담은 문자열일 수도 있어요. array(), echo, empty(), eval(), isset(), list(), print 또는 unset() 같은 언어 구조(language constructs)를 제외하면, 어떤 내장 함수나 사용자 정의 함수도 사용할 수 있어요.
정적 클래스 메서드는 해당 클래스의 객체를 인스턴스화하지 않고도 사용할 수 있어요. 인덱스 0에 클래스 이름, 인덱스 1에 메서드 이름을 담은 배열을 만들거나, 'ClassName::methodName'처럼 스코프 해석 연산자 ::를 사용한 특별한 문법을 사용하면 돼요.
인스턴스화된 객체의 메서드도 콜러블이 될 수 있는데, 인덱스 0에 객체, 인덱스 1에 메서드 이름을 담은 배열로 제공하면 돼요.
Closure 객체와 callable 타입의 주요 차이는, Closure 객체는 스코프 독립적(scope-independent)이라 항상 호출할 수 있는 반면, callable 타입은 스코프 의존적(scope-dependent)이라 직접 호출하지 못할 수도 있다는 점이에요. Closure는 콜러블을 만드는 데 선호되는 방법이에요. PHP 8.5.0부터 Closure는 callable의 적절한 하위 타입이에요.
참고:
Closure객체는 생성된 스코프에 바인딩되지만, 클래스 메서드를 문자열이나 배열로 참조하는 콜러블은 호출되는 스코프에서 해석돼요. 클래스 스코프 밖에서 호출할 수 있는 private 또는 protected 메서드의 콜러블을 만들려면 Closure::fromCallable() 또는 일급 콜러블 문법을 사용하세요.
PHP는 콜백 인자로 사용할 수는 있지만 직접 호출할 수는 없는 콜러블 생성도 허용해요. 이것들은 클래스의 상속 계층에 있는 클래스 메서드를 참조하는 컨텍스트 의존적(context-dependent) 콜러블로, 예를 들어 'parent::method' 또는 ["static", "method"] 같은 형태예요.
참고: PHP 8.2.0부터 컨텍스트 의존적 콜러블은 폐기(deprecated)됐어요.
'parent::method'를parent::class . '::method'로 바꾸거나 일급 콜러블 문법을 사용해서 컨텍스트 의존성을 제거하세요.
예제 #2 call_user_func()로 다양한 타입의 콜러블 호출하기
<?php
// An example callback function
function my_callback_function() {
echo 'hello world!', PHP_EOL;
}
// An example callback method
class MyClass {
static function myCallbackMethod() {
echo 'Hello World!', PHP_EOL;
}
}
// Type 1: Simple callback
call_user_func('my_callback_function');
// Type 2: Static class method call
call_user_func(['MyClass', 'myCallbackMethod']);
// Type 3: Object method call
$obj = new MyClass();
call_user_func([$obj, 'myCallbackMethod']);
// Type 4: Static class method call
call_user_func('MyClass::myCallbackMethod');
// Type 5: Static class method call using ::class keyword
call_user_func([MyClass::class, 'myCallbackMethod']);
// Type 6: Relative static class method call
class A {
public static function who() {
echo 'A', PHP_EOL;
}
}
class B extends A {
public static function who() {
echo 'B', PHP_EOL;
}
}
call_user_func(['B', 'parent::who']); // deprecated as of PHP 8.2.0
// Type 7: Objects implementing __invoke can be used as callables
class C {
public function __invoke($name) {
echo 'Hello ', $name;
}
}
$c = new C();
call_user_func($c, 'PHP!');
?>
위 예제의 출력:
hello world!
Hello World!
Hello World!
Hello World!
Hello World!
Deprecated: Callables of the form ["B", "parent::who"] are deprecated in script on line 44
A
Hello PHP!
참고: call_user_func()나 call_user_func_array() 같은 함수로 등록된 콜백은, 이전 콜백에서 잡히지 않은 예외가 발생했다면 호출되지 않을 거예요.