Je vais lier une autre question à celle-ci, parce que j'essayais d'appeler une fermeture.
akinuri
Réponses:
173
Le manuel utilise les termes "callback" et "callable" de manière interchangeable, cependant, "callback" se réfère traditionnellement à une valeur de chaîne ou de tableau qui agit comme un pointeur de fonction , référençant une fonction ou une méthode de classe pour un appel futur. Cela a permis certains éléments de 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');
C'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);
}
Les versions modernes de PHP permettent aux trois premiers formats ci-dessus d'être appelés directement en tant que $cb(). call_user_funcet call_user_func_arraysoutenez tout ce qui précède.
Si la fonction / classe a un espace de noms, la chaîne doit contenir le nom complet. Par exemple['Vendor\Package\Foo', 'method']
call_user_funcne supporte pas le passage des non-objets par référence, vous pouvez utiliser call_user_func_arrayou, dans les versions PHP plus tard, enregistrez le rappel à un var et utiliser la syntaxe directe: $cb();
Les objets avec une __invoke()méthode (y compris les fonctions anonymes) entrent dans la catégorie "appelable" et peuvent être utilisés de la même manière, mais personnellement je ne les associe pas au terme "rappel" 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.
En effet, utiliser la fonction est la bonne façon de le faire. En utilisant une variable et en l'appelant, comme suggéré dans la réponse acceptée, c'est cool, c'est moche et ne s'adapte pas bien au code.
icco
4
Réponse acceptée modifiée. D'accord avec les commentaires, c'est une excellente réponse.
Nick Stinemates
Il serait utile aux lecteurs issus de la programmation Python de souligner dans la réponse qu'il 'someGlobalFunction's'agit bien d'une fonction définie.
TMOTTM
1
Depuis PHP 5.3, il y a des fermetures, voir la réponse de Bart van Heukelom . C'est beaucoup plus simple et "standard" que tout ce désordre hérité.
reallynice
Oui, je mentionne des fonctions anonymes dans ma réponse, mais l'OP a demandé un «rappel» (en 2008) et ces rappels de style ancien sont toujours très utilisés dans des tonnes de bases de code PHP.
Steve Clay
75
Avec PHP 5.3, vous pouvez maintenant faire ceci:
functiondoIt($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.
// This function uses a callback function. functiondoIt($callback)
{
$data = "this is my data";
$callback($data);
}
// This is a sample callback function for doIt(). functionmyCallback($data)
{
print'Data is: ' . $data . "\n";
}
// Call doIt() and pass our sample callback function's name.
doIt('myCallback');
Il existe plusieurs autres façons de le faire, comme indiqué ci-dessus. J'ai vraiment pensé la même chose.
Nick Stinemates
3
@Nick Retallack, je ne vois pas ce qu'il y a de si horrible à ce sujet. Pour les langages que je connais, tels que JavaScript et C #, ils peuvent tous structurer leur fonction de rappel dans un tel modèle. Venant de JavaScirpt et C #, je ne suis vraiment pas habitué à call_user_func (). Cela me donne l'impression de devoir m'adapter à PHP, au lieu de l'inverse.
Antony
4
@Antony Je m'opposais au fait que les chaînes sont des pointeurs de fonction dans ce langage. J'ai posté ce commentaire il y a trois ans, donc j'y suis assez habitué maintenant, mais je pense que PHP est le seul langage que je connaisse (autre que le script shell) où c'est le cas.
Nick Retallack
1
@Antony Je préfère utiliser la même syntaxe que j'utilise en javascript. Donc je ne comprends même pas pourquoi les gens veulent utiliser call_user_func()Quand ils ont une syntaxe qui leur permet d'appeler dynamiquement des fonctions et de faire des rappels. Je suis d'accord avec toi!
botenvouwer
9
Une astuce astucieuse que j'ai récemment trouvée est d'utiliser PHP create_function()pour créer une fonction anonyme / lambda pour une utilisation ponctuelle. Il est utile pour les fonctions PHP comme array_map(), preg_replace_callback()ou usort()que callbacks utilisation pour le traitement personnalisé. Cela ressemble à peu près à un eval()sous les couvertures, mais c'est toujours une belle façon fonctionnelle d'utiliser PHP.
Malheureusement, le garbage collector ne joue pas très bien avec cette construction produisant des fuites de mémoire potentielles. Si vous êtes à la recherche de performances, évitez create_function ().
fuxia
Pourriez-vous mettre à jour la réponse avec la version PHP 7.4 (fonctions fléchées) et ajouter un avertissement concernant les obsolètes create_function()?
Dharman
7
eh bien ... avec 5.3 à l'horizon, tout ira mieux, car avec 5.3, on aura des fermetures et avec elles des fonctions anonymes
Vous voudrez vérifier quel que soit votre appel est valide. Par exemple, dans le cas d'une fonction spécifique, vous voudrez vérifier et voir si la fonction existe:
Et si le rappel n'est pas une fonction, mais un tableau contenant un objet et une méthode?
d -_- b
3
ou plutôtis_callable( $callback )
Roko C. Buljan
1
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 le fait d'appeler quelque chose qui n'existait pas causant un décès. J'ai rendu la réponse plus générale
SeanDowney
5
create_functionn'a pas fonctionné pour moi dans une classe. Je devais utiliser call_user_func.
La classe Dispatcher ne nécessite-t-elle pas un attribut pour que $ this-> callback = $ callback fonctionne?
James P.
@james poulson: PHP est un langage dynamique, donc ça marche. Mais j'étais paresseux. Je déclare généralement des propriétés, facilite la vie de tout le monde. Votre question m'a fait revoir ce code et repérer une erreur de syntaxe, toi. Merci
goliatone
Je ne savais pas que c'était possible. Merci d'avoir répondu :) .
James P.
Ne serait-il pas plus sûr de déclarer la fonction do_callback avant de créer l'objet Dispatcher et d'appeler la méthode async?
ejectamenta
3
Je grince des dents à chaque fois que j'utilise create_function()en php.
Les paramètres sont une chaîne séparée par des virgules, tout le corps de la fonction dans une chaîne ... Argh ... Je pense qu'ils n'auraient pas pu le rendre plus laid même s'ils avaient essayé.
Malheureusement, c'est le seul choix lorsque la création d'une fonction nommée ne vaut pas la peine.
Et, bien sûr, c'est eval de chaîne d'exécution, donc il n'est pas vérifié pour la syntaxe valide ou quoi que ce soit d'autre au moment de la compilation.
hobbs
Cette réponse est dépassée depuis 2 ans. create_function()est désormais obsolète et ne doit pas être utilisé.
Dharman
2
Pour ceux qui ne se soucient pas de rompre la compatibilité avec PHP < 5.4, je suggère d'utiliser l'indication de type pour créer une implémentation plus propre.
Réponses:
Le manuel utilise les termes "callback" et "callable" de manière interchangeable, cependant, "callback" se réfère traditionnellement à une valeur de chaîne ou de tableau qui agit comme un pointeur de fonction , référençant une fonction ou une méthode de classe pour un appel futur. Cela a permis certains éléments de 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');
C'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); }
Les versions modernes de PHP permettent aux trois premiers formats ci-dessus d'être appelés directement en tant que
$cb()
.call_user_func
etcall_user_func_array
soutenez tout ce qui précède.Voir: http://php.net/manual/en/language.types.callable.php
Remarques / mises en garde:
['Vendor\Package\Foo', 'method']
call_user_func
ne supporte pas le passage des non-objets par référence, vous pouvez utilisercall_user_func_array
ou, dans les versions PHP plus tard, enregistrez le rappel à un var et utiliser la syntaxe directe:$cb()
;__invoke()
méthode (y compris les fonctions anonymes) entrent dans la catégorie "appelable" et peuvent être utilisés de la même manière, mais personnellement je ne les associe pas au terme "rappel" hérité.create_function()
crée une fonction globale et renvoie son nom. C'est un wrapper poureval()
et des fonctions anonymes devraient être utilisées à la place.la source
'someGlobalFunction'
s'agit bien d'une fonction définie.Avec PHP 5.3, vous pouvez maintenant faire ceci:
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.
la source
L'implémentation d'un callback se fait comme ceci
// 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
la source
call_user_func()
Quand ils ont une syntaxe qui leur permet d'appeler dynamiquement des fonctions et de faire des rappels. Je suis d'accord avec toi!Une astuce astucieuse que j'ai récemment trouvée est d'utiliser PHP
create_function()
pour créer une fonction anonyme / lambda pour une utilisation ponctuelle. Il est utile pour les fonctions PHP commearray_map()
,preg_replace_callback()
ouusort()
que callbacks utilisation pour le traitement personnalisé. Cela ressemble à peu près à uneval()
sous les couvertures, mais c'est toujours une belle façon fonctionnelle d'utiliser PHP.la source
create_function()
?eh bien ... avec 5.3 à l'horizon, tout ira mieux, car avec 5.3, on aura des fermetures et avec elles des fonctions anonymes
http://wiki.php.net/rfc/closures
la source
Vous voudrez vérifier quel que soit votre appel est valide. Par exemple, dans le cas d'une fonction spécifique, vous voudrez vérifier et voir si la fonction existe:
function doIt($callback) { if(function_exists($callback)) { $callback(); } else { // some error handling } }
la source
is_callable( $callback )
create_function
n'a pas fonctionné pour moi dans une classe. Je devais utilisercall_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!" ); } } }
Ensuite, pour utiliser:
<?php include_once('Dispatcher.php'); $d = new Dispatcher( 'do_callback' ); $d->asynchronous_method(); function do_callback( $data ){ print 'Data is: ' . $data . "\n"; } ?>
[Edit] Ajout d'une parenthèse manquante. De plus, j'ai ajouté la déclaration de rappel, je la préfère ainsi.
la source
Je grince des dents à chaque fois que j'utilise
create_function()
en php.Les paramètres sont une chaîne séparée par des virgules, tout le corps de la fonction dans une chaîne ... Argh ... Je pense qu'ils n'auraient pas pu le rendre plus laid même s'ils avaient essayé.
Malheureusement, c'est le seul choix lorsque la création d'une fonction nommée ne vaut pas la peine.
la source
create_function()
est désormais obsolète et ne doit pas être utilisé.Pour ceux qui ne se soucient pas de rompre la compatibilité avec PHP
< 5.4
, je suggère d'utiliser l'indication de type pour créer 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"
la source
create_function()
est obsolète depuis PHP 7.2.0. Il est fortement déconseillé de se fier à cette fonction.