PHP에서 콜백을 어떻게 구현합니까?


181

콜백은 PHP로 어떻게 작성됩니까?


1
클로저를 호출하려고했기 때문에 다른 질문 을이 질문 에 연결 하려고합니다.
akinuri

답변:


173

매뉴얼에서는 "콜백"과 "호출 가능"이라는 용어를 서로 바꿔서 사용할 수 있지만 "콜백"은 일반적으로 함수 호출 처럼 작동하는 문자열 또는 배열 값을 나타내며 , 나중에 호출하기 위해 함수 또는 클래스 메서드를 참조합니다. 이것은 PHP 4부터 기능 프로그래밍의 일부 요소를 허용했습니다.

$cb1 = 'someGlobalFunction';
$cb2 = ['ClassName', 'someStaticMethod'];
$cb3 = [$object, 'somePublicMethod'];

// this syntax is callable since PHP 5.2.3 but a string containing it
// cannot be called directly
$cb2 = 'ClassName::someStaticMethod';
$cb2(); // fatal error

// legacy syntax for PHP 4
$cb3 = array(&$object, 'somePublicMethod');

이것은 일반적으로 호출 가능한 값을 사용하는 안전한 방법입니다.

if (is_callable($cb2)) {
    // Autoloading will be invoked to load the class "ClassName" if it's not
    // yet defined, and PHP will check that the class has a method
    // "someStaticMethod". Note that is_callable() will NOT verify that the
    // method can safely be executed in static context.

    $returnValue = call_user_func($cb2, $arg1, $arg2);
}

최신 PHP 버전에서는 위의 처음 세 가지 형식을로 직접 호출 할 수 있습니다 $cb(). call_user_func그리고 call_user_func_array위의 모든을 지원합니다.

참조 : http://php.net/manual/en/language.types.callable.php

메모 /주의 사항 :

  1. 함수 / 클래스가 네임 스페이스 인 경우 문자열에는 정규화 된 이름이 포함되어야합니다. 예 :['Vendor\Package\Foo', 'method']
  2. call_user_func비 객체를 참조로 전달하는 것을 지원하지 않으므로 call_user_func_array나중에 PHP 버전에서 콜백을 var에 저장하고 직접 구문을 사용할 수 있습니다 $cb().
  3. __invoke()메소드 (익명 함수 포함)가 있는 객체는 "호출 가능"범주에 속하며 같은 방식으로 사용할 수 있지만 개인적으로 기존 "콜백"용어와 연관시키지 않습니다.
  4. 레거시 create_function()는 전역 함수를 작성하고 이름을 리턴합니다. 래퍼 eval()이므로 익명 함수를 대신 사용해야합니다.

실제로 기능을 사용하는 것이 올바른 방법입니다. 허용 된 답변에서 제안 된 것처럼 변수를 사용하고 변수를 호출하는 동안 추악하고 코드로 확장 할 수 없습니다.
icco

4
수락 된 답변이 변경되었습니다. 의견에 동의하면 이것은 좋은 대답입니다.
Nick Stinemates

파이썬 프로그래밍에서 온 독자에게는 'someGlobalFunction'실제로 정의 된 함수 라는 답을 지적하는 것이 도움이 될 것 입니다.
TMOTTM

1
PHP 5.3부터 클로저가 있습니다. Bart van Heukelom의 답변을 참조하십시오 . 이 모든 레거시 혼란보다 훨씬 간단하고 "표준"입니다.
reallynice

예, 대답에 익명 함수가 언급되어 있지만 OP는 "콜백"(2008 년)을 요청했으며 이러한 이전 스타일의 콜백은 여전히 ​​많은 PHP 코드베이스에서 많이 사용되고 있습니다.
Steve Clay

74

PHP 5.3을 사용하면 다음과 같이 할 수 있습니다.

function doIt($callback) { $callback(); }

doIt(function() {
    // this will be done
});

마지막으로 좋은 방법입니다. 콜백이 훌륭하기 때문에 PHP에 추가되었습니다.


1
이것이 최고의 답변이되어야합니다.
GROVER.

30

콜백 구현은 다음과 같이 수행됩니다

// This function uses a callback function. 
function doIt($callback) 
{ 
    $data = "this is my data";
    $callback($data); 
} 


// This is a sample callback function for doIt(). 
function myCallback($data) 
{ 
    print 'Data is: ' .  $data .  "\n"; 
} 


// Call doIt() and pass our sample callback function's name. 
doIt('myCallback');

표시 : 데이터는 : 이것은 내 데이터입니다


21
세상에. 이것이 표준입니까? 끔찍 해요!
Nick Retallack

위에 표시된 것처럼 몇 가지 다른 방법이 있습니다. 나는 정말로 같은 생각을했다.
Nick Stinemates

3
@ Nick Retallack, 나는 그것이 끔찍한 것을 보지 못했습니다. JavaScript 및 C #과 같이 내가 아는 언어의 경우 모두 콜백 함수를 이러한 패턴으로 구성 할 수 있습니다. JavaScirpt 및 C #에서 왔으므로 실제로는 user_func ()를 호출하는 데 익숙하지 않습니다. 다른 방법 대신 PHP에 적응해야한다고 생각합니다.
Antony

4
@Antony 문자열 이이 언어의 함수 포인터라는 사실에 반대했습니다. 나는 3 년 전에 그 의견을 게시 했으므로 지금은 그것에 익숙해 져 있지만 PHP가 내가 알고있는 유일한 언어라고 생각합니다 (쉘 스크립팅 제외).
Nick Retallack

1
@Antony 나는 자바 스크립트에서 사용하는 것과 동일한 구문을 사용하는 것을 선호합니다. 그래서 사람들이 call_user_func()동적으로 함수를 호출하고 콜백을 할 수있는 구문이있을 때 사람들이 왜 사용하고 싶어하는지 이해조차하지 못합니다 . 동의합니다!
botenvouwer

9

내가 최근에 찾은 멋진 트릭은 PHP create_function()를 사용하여 원샷 용 익명 / 람다 함수를 만드는 것입니다. array_map(), 같은 PHP 함수 preg_replace_callback()또는 usort()사용자 정의 처리에 콜백을 사용하는 경우에 유용합니다 . 그것은 eval()덮개 아래에서 하는 것처럼 거의 보이지만 여전히 PHP를 사용하는 좋은 기능 스타일의 방법입니다.


6
불행히도 가비지 콜렉터는 잠재적 인 메모리 누수를 생성하는이 구성에서 잘 작동하지 않습니다. 성능이 떨어지는 경우 create_function ()을 피하십시오.
fuxia

1
아야. 헤드 업 주셔서 감사합니다.
yukondude

PHP 7.4 버전 (화살표 기능)으로 답변을 업데이트하고 더 이상 사용되지 않는 것에 대한 경고를 추가 create_function()하시겠습니까?
Dharman


7

당신은 당신의 전화가 유효한 것을 확인하고 싶을 것입니다. 예를 들어, 특정 기능의 경우 기능이 존재하는지 확인하고 확인하려고합니다.

function doIt($callback) {
    if(function_exists($callback)) {
        $callback();
    } else {
        // some error handling
    }
}

콜백이 함수가 아니라 객체와 메소드를 보유하는 배열 인 경우 어떻게해야합니까?
d -_- b

3
또는 오히려is_callable( $callback )
Roko C. Buljan

1
둘 다 좋은 제안입니다. 콜백을 수행하는 방법에 대한 특정 구현을 확인해야합니다. 나는 치명적인 원인이되지 않은 것을 부르는 것에 대해 경고하기를 바랐다. 나는 더 일반적인 답변을했다
SeanDowney

5

create_function수업 내에서 나를 위해 일하지 않았다. 나는을 사용해야했다 call_user_func.

<?php

class Dispatcher {
    //Added explicit callback declaration.
    var $callback;

    public function Dispatcher( $callback ){
         $this->callback = $callback;
    }

    public function asynchronous_method(){
       //do asynch stuff, like fwrite...then, fire callback.
       if ( isset( $this->callback ) ) {
            if (function_exists( $this->callback )) call_user_func( $this->callback, "File done!" );
        }
    }

}

그런 다음 사용하십시오.

<?php 
include_once('Dispatcher.php');
$d = new Dispatcher( 'do_callback' );
$d->asynchronous_method();

function do_callback( $data ){
   print 'Data is: ' .  $data .  "\n";
}
?>

[편집] 누락 된 괄호가 추가되었습니다. 또한 콜백 선언을 추가하여 그렇게 선호합니다.


1
Dispatcher 클래스가 작동하기 위해 $ this-> callback = $ callback에 대한 속성이 필요하지 않습니까?
James P.

@ james poulson : PHP는 동적 언어이므로 작동합니다. 그러나 나는 게으르고 있었다. 나는 일반적으로 속성을 선언하여 모든 사람의 삶을 편하게 만듭니다. 귀하의 질문으로 해당 코드를 다시보고 구문 오류를 발견했습니다. 감사합니다
goliatone

나는 이것이 가능하다는 것을 몰랐다. 답변 해주셔서 감사합니다 :) .
James P.

Dispatcher 오브젝트를 작성하고 비동기 메소드를 호출하기 전에 do_callback 함수를 선언하는 것이 더 안전하지 않습니까?
ejectamenta

3

create_function()PHP에서 사용할 때마다 울었습니다 .

매개 변수는 쉼표로 구분 된 문자열이며 문자열의 전체 함수 본문입니다 ... Argh ... 나는 시도했지만 더 못 생겼다고 생각합니다.

불행히도, 명명 된 함수를 생성 할 때 문제가되지 않는 유일한 선택입니다.


1
물론 런타임 문자열 평가판이므로 컴파일 타임에 유효한 구문이나 다른 항목이 있는지 확인하지 않습니다.
홉스

이 답변은 지난 2 년간 구식입니다. create_function()더 이상 사용되지 않으며 사용해서는 안됩니다.
Dharman

2

PHP와의 호환성을 깨뜨리는 것에 신경 쓰지 않는 사람들을 위해 < 5.4유형 힌트를 사용하여보다 깔끔하게 구현하는 것이 좋습니다.

function call_with_hello_and_append_world( callable $callback )
{
     // No need to check $closure because of the type hint
     return $callback( "hello" )."world";
}

function append_space( $string )
{
     return $string." ";
}

$output1 = call_with_hello_and_append_world( function( $string ) { return $string." "; } );
var_dump( $output1 ); // string(11) "hello world"

$output2 = call_with_hello_and_append_world( "append_space" );
var_dump( $output2 ); // string(11) "hello world"

$old_lambda = create_function( '$string', 'return $string." ";' );
$output3 = call_with_hello_and_append_world( $old_lambda );
var_dump( $output3 ); // string(11) "hello world"

create_function()PHP 7.2.0부터 경고 가 더 이상 사용되지 않습니다. 이 기능에 의존하지 않는 것이 좋습니다.
Dharman
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.