2008-09-08 7 views

Répondre

157

Le manuel utilise les termes « rappel » « callback » et « appelable » de façon interchangeable, mais, traditionnellement fait référence à une valeur de chaîne ou de tableau qui agit comme function pointer, faisant référence à une fonction ou à une méthode de classe pour un appel ultérieur. Cela a permis à certains éléments de la programmation fonctionnelle depuis PHP 4. Les saveurs sont:

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

Ceci est un moyen sûr d'utiliser des valeurs appelables en général:

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

versions PHP modernes permettent aux trois premiers formats ci-dessus pour être appelé directement $cb(). call_user_func et call_user_func_array support tout ce qui précède.

Voir: http://php.net/manual/en/language.types.callable.php

Notes/Avertissements:

  1. Si la fonction/classe est un espace de noms, la chaîne doit contenir le nom complet. Par exemple. ['Vendor\Package\Foo', 'method']
  2. call_user_func ne supporte pas le passage de non-objets par référence, donc vous pouvez soit utiliser call_user_func_array ou, dans les versions ultérieures de PHP, enregistrer le rappel à un var et utiliser la syntaxe directe: $cb();
  3. Les objets avec une méthode __invoke() (y compris les fonctions anonymes) entrent dans la catégorie "callable" et peuvent être utilisés de la même manière, mais personnellement, je ne les associe pas au terme "callback" hérité.L'héritage create_function() crée une fonction globale et renvoie son nom. C'est un wrapper pour eval() et des fonctions anonymes devraient être utilisées à la place.
+1

C'est largement mieux que l'auto-réponse acceptée par OP. – chaos

+0

En effet, l'utilisation de la fonction est la bonne façon de le faire. Alors que l'utilisation d'une variable, puis simplement l'appeler, comme suggéré dans la réponse acceptée est cool, c'est moche et ne sera pas bien à l'échelle avec le code. – icco

+3

Changé réponse acceptée. D'accord avec les commentaires, c'est une excellente réponse. –

26

La mise en œuvre d'un rappel est fait comme tant

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

Affiche: Les données sont: ce sont mes données

+16

Oh mon dieu. Est-ce la norme? C'est terrible! –

+0

Il existe d'autres façons de le faire, comme indiqué ci-dessus. J'ai vraiment pensé la même chose. –

+0

Wow, cela ajoute de nouveaux rebondissements à la programmation conventionnelle. –

9

Une bonne astuce que j'ai récemment trouvé est d'utiliser create_function() PHP pour créer un anonyme/Fonction lambda pour une utilisation unique. Il est utile pour les fonctions PHP telles que array_map(), preg_replace_callback() ou usort() qui utilisent des rappels pour un traitement personnalisé. Il ressemble beaucoup à un eval() sous les couvertures, mais c'est quand même un bon moyen fonctionnel d'utiliser PHP.

+6

Malheureusement, le garbage collector ne joue pas très bien avec cette construction produisant des fuites de mémoire potentielles. Si vous souhaitez améliorer vos performances, évitez create_function(). – fuxia

+1

Ouch. Merci pour l'information. – yukondude

3

Je grince chaque fois que j'utilise create_function() en php.

Les paramètres sont une chaîne séparée par des virgules, le corps de la fonction entière dans une chaîne ... Argh ... Je pense qu'ils ne pourraient pas l'avoir rendu plus laid même s'ils ont essayé.

Malheureusement, c'est le seul choix lorsque créer une fonction nommée ne vaut pas le coup.

+0

Et, bien sûr, c'est la chaîne d'exécution eval, donc elle n'est pas vérifiée pour la syntaxe valide ou quoi que ce soit d'autre au moment de la compilation. – hobbs

7

Vous voulez vérifier ce que votre appel est valable. Par exemple, dans le cas d'une fonction spécifique, vous voulez vérifier et voir si la fonction existe:

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

Que faire si le callback n'est pas une fonction mais un objet et une méthode contenant un tableau? –

+0

ou plutôt 'is_callable ($ callback)' –

+0

Les deux sont de bonnes suggestions - Il sera nécessaire de vérifier votre propre implémentation particulière de la façon dont vous effectuez un rappel. J'espérais mettre en garde contre l'appel de quelque chose qui n'existait pas causant un décès. J'ai fait la réponse plus générale – SeanDowney

4

create_function ne fonctionnait pas pour moi dans une classe. Je devais utiliser 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!"); 
     } 
    } 

} 

Puis, à utiliser:

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

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

[Modifier] Ajout d'une parenthèse manquante de. En outre, ajouté la déclaration de rappel, je le préfère de cette façon.

+1

La classe Dispatcher ne nécessite-t-elle pas un attribut pour que $ this-> callback = $ callback fonctionne? –

+0

@james poulson: PHP est un langage dynamique, donc ça marche. Mais j'étais paresseux. Je déclare généralement les propriétés, rend la vie de tout le monde plus facile. Votre question m'a fait regarder à nouveau ce code et repérer une erreur de syntaxe, tu. Merci – goliatone

+0

Je ne savais pas que c'était possible. Merci d'avoir répondu :) . –

59

Avec PHP 5.3, vous pouvez le faire:

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

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

Enfin une belle façon de le faire. Un excellent ajout à PHP, car les rappels sont géniaux.

+4

assez soigné, c'est très utile – Ulterior

1

Pour ceux qui ne se soucient pas de rompre la compatibilité avec PHP < 5.4, je suggérerais d'utiliser l'indication de type pour faire une implémentation plus propre.

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" 
Questions connexes