PHP'de geri aramayı nasıl uygularım?


181

PHP'de geri aramalar nasıl yazılır?


1
Başka bir soruyu buna bağlayacağım , çünkü bir kapanış çağırmaya çalışıyordum.
akinuri

Yanıtlar:


173

Bu el kitabı "geri çağrı" ve "çağrılabilir" terimlerini birbirinin yerine kullanır, ancak "geri çağrı" geleneksel olarak gelecekteki çağrı için bir işlev veya sınıf yöntemini referans alan bir işlev işaretçisi gibi davranan bir dize veya dizi değeri anlamına gelir . Bu PHP 4 beri fonksiyonel programlama bazı unsurları izin verdi.

$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');

Bu, genel olarak çağrılabilir değerleri kullanmanın güvenli bir yoludur:

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);
}

Modern PHP sürümleri, yukarıdaki ilk üç biçimin doğrudan olarak çağrılmasını sağlar $cb(). call_user_funcve call_user_func_arrayyukarıdakilerin tümünü destekleyin.

Bkz. Http://php.net/manual/en/language.types.callable.php

Notlar / Uyarılar:

  1. İşlev / sınıf ad aralıklıysa, dize tam olarak nitelenmiş adı içermelidir. Örneğin['Vendor\Package\Foo', 'method']
  2. call_user_func referans ile nesne olmayan geçişleri desteklemediğinden, call_user_func_array daha sonraki PHP sürümlerinde geri çağrıyı bir var'a kaydedebilir ve doğrudan sözdizimini kullanabilirsiniz $cb():;
  3. Nesneleri __invoke() yöntemle (anonim işlevler dahil) "çağrılabilir" kategorisine girer ve aynı şekilde kullanılabilir, ancak ben şahsen bunları eski "geri arama" terimiyle ilişkilendirmiyorum.
  4. Eski create_function()bir global işlev oluşturur ve adını döndürür. Bu bir sarıcıdır eval()ve bunun yerine anonim işlevler kullanılmalıdır.

Aslında, işlevi kullanmak, bunu yapmanın uygun yoludur. Bir değişkeni kullanırken ve sonra sadece çağırırken, kabul edilen cevapta önerildiği gibi, çirkin ve kodla iyi ölçeklenmez.
icco

4
Kabul edilen cevap değiştirildi. Yorumlarla hemfikir, bu harika bir cevap.
Nick Stinemates

Python programlamasından gelen okuyucuların cevapta 'someGlobalFunction'gerçekten tanımlanmış bir işlev olduğunu belirtmeleri faydalı olacaktır .
TMOTTM

1
PHP 5.3'ten itibaren kapaklar var, Bart van Heukelom'un cevabına bakınız . Tüm bu eski karmaşadan çok daha basit ve "standart".
reallynice

Evet, cevabımda anonim işlevlerden bahsediyorum, ancak OP "geri arama" (2008'de) istedi ve bu eski tarz geri aramalar tonlarca PHP kod bazında hala kullanılıyor.
Steve Clay

74

PHP 5.3 ile artık bunu yapabilirsiniz:

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

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

Sonunda bunu yapmanın güzel bir yolu. PHP için harika bir ek, çünkü geri aramalar harika.


1
Bu en iyi cevap olmalı.
GROVER.

30

Geri arama uygulaması bu şekilde yapılır

// 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');

Görüntüler: Veriler: bu benim verilerim


21
Aman Tanrım. Standart mı bu? Bu korkunç!
Nick Retallack

Yukarıda gösterildiği gibi bunu yapmanın birkaç yolu daha vardır. Ben de aynısını düşündüm.
Nick Stinemates

3
@Nick Retallack, bu konuda neyin korkunç olduğunu görmüyorum. JavaScript ve C # gibi bildiğim diller için hepsi geri arama işlevlerini bu şekilde yapılandırabilir. JavaScirpt ve C # dan gelince, gerçekten call_user_func () için alışkın değilim. Kendimi başka bir yol yerine PHP'ye adapte etmem gerekiyor gibi hissettiriyor.
Antony

4
@Antony: Dizelerin bu dilde işlev işaretçileri olduğu gerçeğine karşı çıkıyordum. Bu yorumu üç yıl önce yayınladım, bu yüzden şimdiye kadar oldukça alışkınım, ancak PHP'nin bildiğim tek dil olduğunu düşünüyorum (kabuk komut dosyası dışında) bu durumda.
Nick Retallack

1
@Antony Javascript ile aynı sözdizimini kullanmayı tercih ederim. Bu yüzden insanların neden kullanmak istediklerini bile anlamıyorum call_user_func(). İşlevlerini dinamik olarak aramalarını ve geri arama yapmalarını sağlayan bir sözdizimi olduğunda. Size katılıyorum!
botenvouwer

9

Son zamanlarda bulduğum bir şık hile, tek seferlik kullanım create_function()için anonim / lambda işlevi oluşturmak için PHP'leri kullanmaktır. Sanki PHP fonksiyonları için yararlıdır array_map(), preg_replace_callback()ya da usort()özel işleme kullanan geri aramaları. eval()Kapakların altında olduğu gibi görünüyor , ancak hala PHP'yi kullanmanın güzel bir işlevsel tarzı yolu.


6
Ne yazık ki, çöp toplayıcı potansiyel bellek sızıntıları üreten bu yapı ile çok iyi oynamıyor. Performans için dışarıdaysanız, create_function () işlevinden kaçının.
fuxia

1
Ahh. Söylediğin için teşekkürler.
yukondude

Cevabı PHP 7.4 sürümü (ok fonksiyonları) ile güncellemek ve kullanımdan kaldırılmış hakkında bir uyarı eklemek ister misiniz create_function()?
Dharman


7

Aramanızın geçerli olduğunu doğrulamak isteyeceksiniz. Örneğin, belirli bir işlev durumunda, işlevin var olup olmadığını kontrol etmek ve görmek istersiniz:

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

Geri arama bir işlev değil, bir dizi tutma nesnesi ve yöntemi ise ne olur?
d -_- b

3
ya da daha doğrusuis_callable( $callback )
Roko C. Buljan

1
Her ikisi de iyi önerilerdir - Nasıl geri arama yaptığınıza dair kendi özel uygulamanızı kontrol etmeniz gerekecektir. Ölümcül olmayan var olmayan bir şeyi aramaya karşı uyarmayı umuyordum. Cevabı daha genel yaptım
SeanDowney

5

create_functionbir sınıf içinde benim için çalışmadı. Kullanmak zorunda kaldım 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!" );
        }
    }

}

Ardından, kullanmak için:

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

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

[Düzenle] Eksik bir parantez eklendi. Ayrıca, geri arama bildirimi ekledi, ben bu şekilde tercih ederim.


1
Dispatcher sınıfı $ this-> callback = $ callback'in çalışması için bir öznitelik gerektirmez mi?
James P.

@james poulson: PHP dinamik bir dildir, bu yüzden çalışır. Ama tembel oluyordum. Genellikle özellikleri beyan ederim, herkesin hayatını kolaylaştırır. Sorunuz bana bu koda tekrar bakmamı ve bir sözdizimi hatası bulmamı sağladınız. Teşekkürler
goliatone

Bunun mümkün olduğunu bilmiyordum. Cevap için teşekkürler :) .
James P.

Dispatcher nesnesini oluşturmadan ve async yöntemini çağırmadan önce do_callback işlevini bildirmek daha güvenli değil mi?
ejectamenta

3

Ben create_function()php her kullandığınızda cringe .

Parametreler koma ile ayrılmış bir dizedir, bir dize içindeki tüm fonksiyon gövdesi ... Argh ... Bence deneseler bile daha çirkin olamazlardı.

Ne yazık ki, adlandırılmış bir işlev oluştururken sorun olmaya değmez tek seçenek budur.


1
Ve tabii ki, çalışma zamanı dizesi eval, bu yüzden derleme zamanında geçerli sözdizimi veya başka bir şey için kontrol edilmez.
hobbs

Bu yanıt son 2 yıldır modası geçmiş. create_function()artık kullanımdan kaldırılmıştır ve kullanılmamalıdır.
Dharman

2

PHP ile uyumluluğu bozmayı umursamayanlar < 5.4için, daha temiz bir uygulama yapmak için tip ipucu kullanmanızı öneririm.

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"

Uyarı create_function() PHP 7.2.0'dan itibaren DEPRECATED. Bu işleve güvenmek kesinlikle önerilmez.
Dharman
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.