web-dev-qa-db-fra.com

Les fermetures en PHP ... de quoi s'agit-il précisément et quand auriez-vous besoin de les utiliser?

Je programme donc de manière agréable, moderne et orientée objet. Je me sers régulièrement des divers aspects de OOP que PHP implémente, mais je me demande quand pourrais-je avoir besoin d'utiliser des fermetures. Y a-t-il des experts qui peuvent nous éclairer sur la nécessité de mettre en place des systèmes de fermeture?

74
rg88

PHP supportera les fermetures de manière native en 5.3. Une fermeture est utile lorsque vous souhaitez une fonction locale utilisée uniquement à des fins spécifiques. Le RFC pour les fermetures donne un bon exemple:

function replace_spaces ($text) {
    $replacement = function ($matches) {
        return str_replace ($matches[1], ' ', ' ').' ';
    };
    return preg_replace_callback ('/( +) /', $replacement, $text);
}

Cela vous permet de définir la fonction replacement localement dans replace_spaces(), de sorte que ce ne soit pas:
1) Encombrer l'espace de noms global
2) Faire en sorte que les gens trois ans plus tard se demandent pourquoi une fonction définie globalement est utilisée uniquement dans une autre 

Ça garde les choses organisées. Notez que la fonction elle-même n’a pas de nom, elle est simplement définie et assignée comme référence à $replacement.

Mais rappelez-vous, vous devez attendre PHP 5.3 :)

Vous pouvez également accéder à des variables extérieures à sa portée dans une fermeture à l'aide du mot clé use. Considérons cet exemple.

// Set a multiplier  
 $multiplier = 3;

// Create a list of numbers  
 $numbers = array(1,2,3,4);

// Use array_walk to iterate  
 // through the list and multiply  
 array_walk($numbers, function($number) use($multiplier){  
 echo $number * $multiplier;  
 }); 

Une excellente explication est donnée ici Que sont les lambdas et fermetures php

73
dirtside

Lorsque vous aurez besoin d’une fonction dans le futur qui exécute une tâche que vous avez décidé de faire maintenant.

Par exemple, si vous lisez un fichier de configuration et que l'un des paramètres vous indique que le hash_method de votre algorithme est multiply et non square, vous pouvez créer une fermeture qui sera utilisée chaque fois que vous aurez besoin de hachage.

La fermeture peut être créée dans (par exemple) config_parser(); il crée une fonction appelée do_hash_method() à l'aide de variables locales à config_parser() (à partir du fichier de configuration). Chaque fois que do_hash_method() est appelé, il a accès aux variables de l'étendue locale ofconfig_parser() même s'il n'est pas appelé dans cette étendue.

Un bon exemple hypothétique, espérons-le:

function config_parser()
{
    // Do some code here
    // $hash_method is in config_parser() local scope
    $hash_method = 'multiply';

    if ($hashing_enabled)
    {
        function do_hash_method($var)
        {
            // $hash_method is from the parent's local scope
            if ($hash_method == 'multiply')
                return $var * $var;
            else
                return $var ^ $var;
        }
    }
}


function hashme($val)
{
    // do_hash_method still knows about $hash_method
    // even though it's not in the local scope anymore
    $val = do_hash_method($val)
}
15
Dan Udey

Outre les détails techniques, les fermetures sont une condition préalable fondamentale à un style de programmation appelé programmation orientée fonction. Une fermeture est grossièrement utilisée pour la même chose que vous utilisez un objet pour la programmation orientée objet; Il lie des données (variables) avec du code (une fonction), que vous pouvez ensuite transmettre à un autre endroit. En tant que tels, ils ont un impact sur la manière dont vous écrivez les programmes ou - si vous ne changez pas la façon dont vous écrivez vos programmes - ils n’ont aucun impact.

Dans le contexte de PHP, ils sont un peu bizarres, car PHP pèse déjà lourdement sur le paradigme basé sur les classes, orienté objet, ainsi que sur l'ancien paradigme procédural. Habituellement, les langues qui ont des fermetures ont une portée lexicale complète. Pour maintenir la compatibilité ascendante, PHP ne l'obtiendra pas. Cela signifie donc que les fermetures vont être un peu différentes ici, par rapport aux autres langages. Je pense que nous n'avons pas encore vu exactement comment ils seront utilisés.

15
troelskn

J'aime le contexte fourni par le message de troelskn. Lorsque je veux faire quelque chose comme l'exemple de Dan Udey en PHP, j'utilise le modèle de stratégie OO. À mon avis, cela est bien mieux que d’introduire une nouvelle fonction globale dont le comportement est déterminé au moment de l’exécution.

http://en.wikipedia.org/wiki/Strategy_pattern

Vous pouvez également appeler des fonctions et des méthodes à l'aide d'une variable contenant le nom de la méthode en PHP, ce qui est très bien. donc une autre prise sur l'exemple de Dan serait quelque chose comme ceci:

class ConfigurableEncoder{
        private $algorithm = 'multiply';  //default is multiply

        public function encode($x){
                return call_user_func(array($this,$this->algorithm),$x);
        }

        public function multiply($x){
                return $x * 5;
        }

        public function add($x){
                return $x + 5;
        }

        public function setAlgorithm($algName){
                switch(strtolower($algName)){
                        case 'add':
                                $this->algorithm = 'add';
                                break;
                        case 'multiply':        //fall through
                        default:                //default is multiply
                                $this->algorithm = 'multiply';
                                break;
                }
        }
}

$raw = 5;
$encoder = new ConfigurableEncoder();                           // set to multiply
echo "raw: $raw\n";                                             // 5
echo "multiply: " . $encoder->encode($raw) . "\n";              // 25
$encoder->setAlgorithm('add');
echo "add: " . $encoder->encode($raw) . "\n";                   // 10

bien sûr, si vous voulez qu'il soit disponible partout, vous pouvez tout rendre statique ...

10
grossvogel

Une fermeture est essentiellement une fonction pour laquelle vous écrivez la définition dans un contexte mais exécutez-le dans un autre contexte. Javascript m'a beaucoup aidé à les comprendre, car ils sont utilisés partout en JavaScript.

En PHP, ils sont moins efficaces qu'en JavaScript, en raison de différences dans la portée et l'accessibilité des variables "globales" (ou "externes") à partir de fonctions. Cependant, à partir de PHP 5.4, les fermetures peuvent accéder à l’objet $ this lorsqu’elles sont exécutées dans un objet, ce qui les rend beaucoup plus efficaces.

C’est ce que sont les fermetures, et cela devrait suffire à comprendre ce qui est écrit ci-dessus.

Cela signifie qu'il devrait être possible d'écrire une définition de fonction quelque part et d'utiliser la variable $ this dans la définition de fonction, puis d'affecter la définition de fonction à une variable (d'autres ont donné des exemples de syntaxe), puis de transmettre cette variable à un objet. et l'appeler dans le contexte de l'objet, la fonction peut alors accéder à l'objet et manipuler celui-ci via $ this comme s'il s'agissait d'une autre méthode, alors qu'en réalité, il n'est pas défini dans la définition de classe de cet objet, mais ailleurs.

Si ce n'est pas très clair, ne vous inquiétez pas, cela deviendra clair une fois que vous aurez commencé à les utiliser.

2
Rolf

En gros, Closure sont les fonctions internes qui ont accès aux variables externes et sont utilisées en tant que fonction de rappel pour les fonctions anonymes (fonctions sans nom).

 <?php
      $param='ironman';
      function sayhello(){
          $param='captain';
          $func=function () use ($param){
                $param='spiderman';
          };
       $func();
       echo  $param;
       }
      sayhello();
?>

//output captain

//and if we pass variable as a reference as(&$param) then output would be spider man;
1
Harsh Gehlot

Voici des exemples de fermetures en php

// Author: [email protected]
// Publish on: 2017-08-28

class users
{
    private $users = null;
    private $i = 5;

    function __construct(){
        // Get users from database
        $this->users = array('a', 'b', 'c', 'd', 'e', 'f');
    }

    function displayUsers($callback){
        for($n=0; $n<=$this->i; $n++){
            echo  $callback($this->users[$n], $n);
        }
    }

    function showUsers($callback){
        return $callback($this->users);

    }

    function getUserByID($id, $callback){
        $user = isset($this->users[$id]) ? $this->users[$id] : null;
        return $callback($user);
    }

}

$u = new users();

$u->displayUsers(function($username, $userID){
    echo "$userID -> $username<br>";
});

$u->showUsers(function($users){
    foreach($users as $user){
        echo strtoupper($user).' ';
    }

});

$x = $u->getUserByID(2, function($user){

    return "<h1>$user</h1>";
});

echo ($x);

Sortie:

0 -> a
1 -> b
2 -> c
3 -> d
4 -> e
5 -> f

A B C D E F 

c
0
Hisham Dalal