IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Langage PHP Discussion :

écritures fonctions lambda


Sujet :

Langage PHP

  1. #1
    Membre régulier
    Profil pro
    Inscrit en
    Février 2005
    Messages
    87
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2005
    Messages : 87
    Points : 95
    Points
    95
    Par défaut écritures fonctions lambda
    Bonjour
    J'étudie actuellement les fonctions lambdas/closures dans PHP5.3
    Je compare les écriture possibles suivantes, quand bien meme le resultat produit est le meme :
    (l'usage de echo au lieu de return n'a aucun importance ici)

    1re forme :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    $title = 'hello';
    $sayTitle = function() use($title){
      echo $title;
    };
    $sayTitle();
    cette fonction lambda a une portée locale a la fonction dans laquelle elle est déclarée.
    Elle dépend completement de son cotexte d'appel, de la var locale $title
    Elle ne peut pas vivre en dehors du contexte.
    Le but est certainement de nommer un traitement en particulier
    au lieu de le commenter en amont
    A quoi sert le nouveau mot-clé use alors qu'on peut passer la variable en entrée de fonction
    de maniere classique ?

    2e forme :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    $title = 'hello';
    $sayTitle = function($title){
      echo $title;
    };
    $sayTitle($title);
    forme classique. Indépendance totale vis a vis du contexte d'appel.
    La variable est passée en paramètre. Cette fonction lambda n'a pas grand intéret si ce n'est de nommer un traitement
    au lieu de le commenter en amont

    3e forme :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    $title = 'hello';
    $sayTitle = function(){
      global $title;
      echo $title;
    };
    $sayTitle();
    usage des globales : mauvaise pratique

  2. #2
    Expert éminent
    Avatar de Benjamin Delespierre
    Profil pro
    Développeur Web
    Inscrit en
    Février 2010
    Messages
    3 929
    Détails du profil
    Informations personnelles :
    Âge : 36
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Février 2010
    Messages : 3 929
    Points : 7 762
    Points
    7 762
    Par défaut
    Aha le mot clé use, peu détaillé dans la doc, il m'a fallu pas mal de temps pour comprendre à quoi il sert.

    Concrètement, ce mot clé sert à injecter dans le scope de notre closure des références ou des valeurs. Là dessus je t'entends déjà me dire "mais puisqu'on peut les passer en paramètre quel intérêt ?" Justement, l'intérêt c'est de pouvoir se servir de références qui ne sont pas des paramètres de notre closure.

    Voici un cas d'utilisation:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    function test ($a = null) {
    	static $b = 1;
    	if ($a == 'function')
    		return function ($inc = 1)  use (& $b) {
    			$b += $inc;
    		};
    	else
    		return $b;
    }
     
    echo test(); // affiche 1, l'état initial de notre variable statique $b
     
    $fct = test('function');
    $fct(5);
     
    echo test(); // affiche 6, notre variable statique $b incrémentée de 5
    Cet exemple débile sert à illustrer comment se servir de use pour manipuler le scope de notre fonction lambda, en dehord de la fonction test, la variable $b n'existe pas, mais notre closure peut toujours y faire référence et l'utiliser.

    On peut même aller jusqu'a implémenter de la récursivité comme ça (eh oui, sinon comment les closures peuvent-elles faire référence à elles-mêmes ?)

    Exemple avec de la recursivité:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    $arr = array(
    	'1' => array(
    		'1.1' => array(
    			'1.1.1' => 'hello',
    			'1.1.2' => 'peter',
    		)
    	),
    	'2' => '!'
    );
     
    $rec = function (array $tab, $depth = 0) use (&$rec) {
    	foreach ($tab as $key => $value) {
    		echo str_repeat('|  ', $depth) . "$key : " . (is_array($value) ? 'array' : $value) . "<br />";
    		if (is_array($value))
    			 $rec($value, $depth+1);
    	}
    };
     
    $rec($arr);
    Tu comprends mieux l'intérêt du mot clé use ?

  3. #3
    Membre régulier
    Profil pro
    Inscrit en
    Février 2005
    Messages
    87
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2005
    Messages : 87
    Points : 95
    Points
    95
    Par défaut
    l'exemple de la récursivité est tres parlant (référence a soi meme)

    En revanche ca reste flou pour la fonction test :
    1. pourquoi ne pas mettre la static $b dans la fonction lambda ?

    2. pourquoi créer un dépendance entre test() et la fonction lambda

    3. si fonction lambda est déplacé hors test(), elle continue quand meme d'acceder a la reférence de $b ? c'est pas un peu dangereux (notion de portée, var globale, code spaghetti)

  4. #4
    Expert éminent
    Avatar de Benjamin Delespierre
    Profil pro
    Développeur Web
    Inscrit en
    Février 2010
    Messages
    3 929
    Détails du profil
    Informations personnelles :
    Âge : 36
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Février 2010
    Messages : 3 929
    Points : 7 762
    Points
    7 762
    Par défaut
    C'est juste pour démontrer comment les fonctions lambda peuvent accéder à un autre scope que celui dans lequel elles sont crées. ça peut parfois être utile.

    Et il n'est pas moins dangereux d'employer une closure pour manipuler $b que de retourner sa référence par test() par exemple.

  5. #5
    Membre régulier
    Profil pro
    Inscrit en
    Février 2005
    Messages
    87
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2005
    Messages : 87
    Points : 95
    Points
    95
    Par défaut
    employer une closure pour exploiter $b oui c'est tres bien
    tant que la closure existe dans test().
    Dans la mesure où la closure n'est accessible qu'a l'intérieur de test(), pourquoi utiliser use(&$b), un global $b suffirait non ?

  6. #6
    Expert éminent
    Avatar de Benjamin Delespierre
    Profil pro
    Développeur Web
    Inscrit en
    Février 2010
    Messages
    3 929
    Détails du profil
    Informations personnelles :
    Âge : 36
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Février 2010
    Messages : 3 929
    Points : 7 762
    Points
    7 762
    Par défaut
    Les globales sont à éviter car elles nécéssitent implicitement que le développeur se souvienne de tous leurs noms... En utilisant use, on évite ce problème de collisions:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    function test () {
    	static $a = 1;
    	if (func_num_args())
    		return $a = func_get_arg(0);
    	else
    		return function () use (& $a) { echo $a; };
    }
     
    $a = 3;
     
    $fct = test();
    $fct(); // 1
     
    echo $a; // 3
     
    test(2);
    $fct(); // 2
     
    echo $a; // 3
    Dans l'exemple ci-dessus, $a est une variable statique qui n'existe que dans le contexte de test() (on aurait aussi pu mettre une propriété d'objet ou quelque chose dans le genre) ce qui n'empêche pas la closure de manipuler sa référence, peu importe le fait que la colsure se balade dans un autre scope.

    Si on avait utilisé des variables globales, les deux références seraient entrées en collision.

  7. #7
    Membre régulier
    Profil pro
    Inscrit en
    Février 2005
    Messages
    87
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2005
    Messages : 87
    Points : 95
    Points
    95
    Par défaut
    ce qui n'empêche pas la closure de manipuler sa référence, peu importe le fait que la closure se balade dans un autre scope
    qu'appelle tu un autre scope :
    déplacer la closure en dehors de la fonction test() ?

  8. #8
    Expert éminent
    Avatar de Benjamin Delespierre
    Profil pro
    Développeur Web
    Inscrit en
    Février 2010
    Messages
    3 929
    Détails du profil
    Informations personnelles :
    Âge : 36
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Février 2010
    Messages : 3 929
    Points : 7 762
    Points
    7 762
    Par défaut
    Déjà, il ne faut pas confondre la définiton de la closure et sa référence. Ce que j'ai voulu dire, c'est qu'une fois la closure crée, peu importe le scope (ou portée en français - voir http://php.net/manual/en/language.variables.scope.php) où la référence de la closure est utilisée, elle conserve les références actives du scope où elle à été définie grâce au mot clé use. ça permet par exemple de faire "sortir" des objets d'un scope, comme par exemple des membres protégés (comme c'est à peu près le cas avec notre variable statique $a).

    Dans notre cas, la closure est crée dans le scope de test() et sa référence est utilisée dans le scope racine (donc en dehors de test()) mais cela ne l'empêche pas d'utiliser des variables définies dans le scope de test() comme $a même si une autre variable de même nom existe dans le scope racine. En fait on travaille avec des références donc peu importe le nom des objets qu'on manipule, contrairement aux variables globales où le nom à une importance ce qui est donc moins pratique, moins flexible et passablement plus dangereux.

Discussions similaires

  1. Réponses: 0
    Dernier message: 17/12/2012, 09h38
  2. fonction "lambda" dans commande bouton
    Par Farmer64 dans le forum Tkinter
    Réponses: 7
    Dernier message: 19/07/2012, 22h37
  3. Fonction lambda en paramètre d'une fonction
    Par Kaluza dans le forum Langage
    Réponses: 7
    Dernier message: 05/12/2011, 16h25
  4. [C++11] Templates variadiques et fonctions lambdas
    Par Steph_ng8 dans le forum Langage
    Réponses: 2
    Dernier message: 06/10/2011, 18h10
  5. les fonction lambda
    Par yan dans le forum Langage
    Réponses: 18
    Dernier message: 28/02/2011, 17h02

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo