2010-07-25 10 views
5

Comment puis-je utiliser PHP 5.3 comme Closures Nous utilisons blocs Ruby. Je n'ai jamais utilisé 'for' Boucle dans Ruby en raison de l'utilisation de Blocs avec 'each' 'find_all' 'inject' Méthodes.Comment puis-je utiliser PHP 5.3 comme Closures Nous utilisons blocs Ruby

Comment puis-je utiliser PHP 5.3 comme Ruby Closures blocs et dire adieu à 'pour' boucles :)

Comme entre {et} est une fermeture (ou bloc ou Anonymous Fonction)

fruit = %w[apple banana orange] 
fruit.each { |f| print "#{f}, " } 

je le fais en PHP cette façon,

$fruit = array('apple', 'banana', 'orange'); 
foreach ($fruit as $f) 
{ 
print "$f, "; 
} 

est-il un moyen de faire ce Ruby manière en utilisant PHP comme Closures PHP 5.3 supporte.

+0

Vous ne pouvez pas enseigner de nouvelles figures au vieux chien. PHP a obtenu toutes les fonctionnalités "fantaisistes" (OO, namespaces, fermetures) au fil du temps, mais il n'a pas été conçu correctement au tout début - ce qui signifie que toutes les fonctionnalités linguistiques sont là maintenant, mais pas toujours utile et pratique utilisation. Comme vous pouvez le voir dans les réponses, il est toujours plus facile et plus élégant d'utiliser des fonctions de tableau prédéfinies. –

+0

Oh, une autre chose importante: les fermetures ne sont pas les mêmes que les fonctions anonymes. Les fermetures doivent maintenir l'environnement dans lequel elles ont été définies, afin de les appeler des fermetures.Les fonctions anonymes n'ont pas besoin de le faire. Et, techniquement, les blocs Ruby ne sont pas des fonctions, ils sont plutôt une construction de langage. Mais ils peuvent facilement être convertis en fonctions, en les ajoutant par exemple 'lambda'. –

+0

Rohit, pouvez-vous expliquer pourquoi les programmeurs Ruby n'aiment pas les boucles "for"? Il me semble que la plupart du temps ils utilisent un bloc pour faire exactement la même chose qu'une boucle "for" (ou "foreach" en php) mais ils semblent vraiment les détester. J'ai déjà demandé et jamais obtenu une bonne réponse. – James

Répondre

5

Si vous êtes à la recherche à l'aide lambdas à itérer sur un tableau PHP, il y a certaines fonctions que vous pouvez utiliser pour y parvenir. Mieux illustrer, j'ai utilisé une classe wrapper enum:

class enum { 
    public $arr; 

    function __construct($array) { 
     $this->arr = $array; 
    } 

    function each($lambda) { 
     array_walk($this->arr, $lambda); 
    } 

    function find_all($lambda) { 
     return array_filter($this->arr, $lambda); 
    } 

    function inject($lambda, $initial=null) { 
     if ($initial == null) { 
      $first = array_shift($this->arr); 
      $result = array_reduce($this->arr, $lambda, $first); 
      array_unshift($this->arr, $first); 

      return $result; 
     } else { 
      return array_reduce($this->arr, $lambda, $initial); 
     } 
    } 

} 


$list = new enum(array(-1, 3, 4, 5, -7)); 
$list->each(function($a) { print $a . "\n";}); 

// in PHP you can also assign a closure to a variable 
$pos = function($a) { return ($a < 0) ? false : true;}; 
$positives = $list->find_all($pos); 

// inject() examples 
$list = new enum(range(5, 10)); 

$sum = $list->inject(function($sum, $n) { return $sum+$n; }); 
$product = $list->inject(function($acc, $n) { return $acc*$n; }, 1); 

$list = new enum(array('cat', 'sheep', 'bear')); 
$longest = $list->inject(function($memo, $word) { 
     return (strlen($memo) > strlen($word)) ? $memo : $word; } 
    ); 

Cela dit, les fermetures en PHP ne sont pas destinés à remplacer la boucle ni ne se comportent comme des blocs de rubis.

+0

Merci, je pense que array_map() et array_walk() ont l'air mieux à cet effet –

+0

@Rohit Oui, je voulais juste vous faciliter la relation avec ruby. En passant, j'ai ajouté la méthode 'inject()'. – quantumSoup

0

Je ne pense pas une fonction anonyme est un substitut pour une boucle, et je ne pense qu'il est nécessaire de remplacer les boucles avec eux.

Ce pour quoi il est utile est un rappel. Prenez ceci par exemple: (oui, il est une sorte de bulle boiteux, mais il est un exemple)

<?php 

function bubble_sort($sort_rule, $elements) { 
    do { 
     $swapped = false; 
     for ($i = 0; $i < count($elements) - 1; $i++) { 
      if ($sort_rule($elements[$i], $elements[$i + 1])) { 
       $elements[$i] ^= $elements[$i + 1]; 
       $elements[$i + 1] ^= $elements[$i]; 
       $elements[$i] ^= $elements[$i + 1]; 
       $swapped = true; 
      } 
     } 
    } while($swapped); 
    return $elements; 
} 

print_r(bubble_sort(function ($a, $b) { if ($a > $b) return true; else return false; } 
,array(1,6,3,7,42,-1,0,6))); 
?> 

fermetures ne sont pas un remplacement pour les boucles dans un langage de programmation procédural comme php. Bien sûr, si vous utilisez un lisp ou un schéma, ils le sont, mais c'est par nécessité.

Vous pouvez les écrire de cette façon, tout ce que vous allez vraiment être en train de faire est de créer une fonction anonyme avec une boucle à l'intérieur. Je pense que la récursivité serait juste inutile si la tâche est aussi facilement accomplie avec une boucle for, et donc vous n'êtes pas embrasser pour les boucles au revoir.

Les fonctions anonymes sont très utiles dans la programmation événementielle ainsi, lorsque vous voulez simplement définir une méthode de rappel très rapide.

+0

En langage Clojure (issu de Scheme), il semble utiliser des fermetures à la place des boucles «for». Je pense en PHP ce n'est pas possible :) Merci beaucoup –

0

Réponse simple: ce n'est pas le cas. Ruby n'est pas dépourvu de boucles for(), elles masquent juste le mot "for" et changent un peu la syntaxe. Si vous vouliez utiliser une fermeture, ce serait juste une fermeture avec une boucle à l'intérieur, ou une fermeture récursive laide (et moins efficace).

Et les fermetures ne sont PAS la même chose que les blocs. Les fermetures sont comparables aux fonctions de JavaScript, c'est-à-dire qu'elles peuvent être stockées dans des variables et envoyées en tant qu'arguments.

+0

Merci oui je pense que vous avez raison, les fermetures et les blocs sont différents à bien des égards –

+1

1. Ruby _is_ dépourvu de boucles for (syntaxiquement, 'for' existe, mais bloque entièrement rendre superflu, non pas en «changeant un peu la syntaxe», mais en étant utile et omniprésent. 2. Ruby bloque _are_ fermetures. Ils peuvent être stockés dans des variables et envoyés en tant qu'arguments. –

2

Je pense array_map() et array_walk() mieux sous la forme de remplacement RubyBlocks.