2010-07-25 7 views
5

Come posso utilizzare le chiusure PHP 5.3 come Utilizziamo i blocchi in Ruby. Non ho mai usato 'for' Loop in Ruby a causa dell'uso di Blocks con 'each' 'find_all' 'inject' Methods.Come posso utilizzare le chiusure PHP 5.3 come Utilizziamo i blocchi in Ruby

Come posso usare PHP 5.3 Chiusure come Ruby Blocchi e dire bye-bye a 'per il' Loop :)

come tra {e} è una chiusura (o di blocco o anonimo Function)

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

lo faccio in PHP questo modo,

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

c'è un modo per fare questo il modo in cui utilizzano rubino Chiusure PHP come PHP 5.3 supporta.

+0

Non si possono insegnare nuovi trucchi al vecchio cane. PHP ha ottenuto tutte le caratteristiche "fantasiose" (OO, namespace, chiusure) nel tempo, ma non è stato progettato correttamente all'inizio - il che significa che tutte le funzionalità linguistiche sono presenti ora, ma non sempre quelle utili e convenienti per uso. Come puoi vedere dalle risposte, è ancora più semplice ed elegante utilizzare funzioni di array predefinite. –

+0

Oh, un'altra cosa importante: le chiusure non sono le stesse delle funzioni anonime. Le chiusure devono mantenere l'ambiente in cui sono state definite, per chiamarle chiusure.Le funzioni anonime non devono. E, tecnicamente, i blocchi di Ruby non sono funzioni, sono piuttosto un costrutto linguistico. Ma possono essere facilmente convertiti in funzioni, ad esempio anteponendoli con 'lambda'. –

+0

Rohit, puoi spiegare perché ai programmatori di Ruby non piacciono i loop "for"? A me sembra che la maggior parte del tempo che usano un blocco è fare esattamente la stessa cosa di un ciclo "for" (o "foreach" in php), ma sembra che li odino davvero. Ho chiesto prima e non ho mai ottenuto una buona risposta. – James

risposta

5

Se si sta utilizzando lambda per iterare su un array PHP, ci sono alcune funzioni che è possibile utilizzare per ottenere ciò. Meglio illustrarlo, ho usato una 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; } 
    ); 

Detto questo, le chiusure in PHP non sono destinate a sostituire il ciclo for non si comportano come i blocchi rubino.

+0

Grazie, credo array_map() e array_walk() un aspetto migliore per questo scopo –

+0

@Rohit Sì, volevo solo rendere più facile per voi di relazionarsi con rubino. Tra l'altro ho aggiunto il metodo 'inject()'. – quantumSoup

0

Non penso che una funzione anonima sia un sostituto di un ciclo for, né penso che sia necessario sostituire i loop con essi.

Ciò che è utile è una richiamata. Prendete questo esempio: (sì, è uno zoppo bubble sort, ma è un esempio)

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

chiusure non sono un sostituto per i cicli for in un linguaggio di programmazione procedurale come PHP. Sicuro che tu stia usando la lisp o lo schema, ma è per necessità.

Puoi scriverli in questo modo, tutto quello che farai davvero è creare una funzione anonima con un ciclo for all'interno. Penso che la ricorsione non sarebbe necessaria se l'attività è altrettanto facile con un ciclo for, e quindi non ti stai baciando per i ciao addio.

Le funzioni anonime sono molto utili anche nella programmazione guidata da eventi, quando si desidera semplicemente definire un metodo di callback molto veloce.

+0

In Clojure Language (evoluto da Scheme) sembra che stia usando chiusure al posto dei cicli "for". Credo che in PHP sua non è possibile :) Grazie molto –

0

Risposta semplice: non è così. Ruby non è privo di cicli for(), semplicemente mascherano la parola "per" e cambiano leggermente la sintassi. Se volessi usare una chiusura, sarebbe solo una chiusura con un ciclo al suo interno, o una chiusura ricorsiva brutta (e meno efficiente).

E le chiusure NON sono la stessa cosa dei blocchi. Le chiusure sono paragonabili alle funzioni in JavaScript, ovvero possono essere memorizzate in variabili e inviate come argomenti.

+0

Grazie sì penso che ha ragione, chiusure e blocchi sono diversi in molti modi –

+1

1. Rubino _is_ privo di 'loop for' (sintatticamente,' esiste for', ma blocchi lo rendono del tutto superfluo, non "cambiando la sintassi un po '", ma essendo una caratteristica del linguaggio utile e onnipresente). 2. Blocchi di rubino _ sono chiusure. Possono essere memorizzati in variabili e inviati come argomenti. –

2

Penso che array_map() e array_walk() abbiano un aspetto migliore come sostituzione RubyBlocks.