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.