Newsgroup: it.comp.www.php
Titolo: Closures

Dopo i Generators, eccomi qua con le closures :)
 
Sul libro "Modern PHP" di Josh Lockart ho trovato questo bell'esempio di
utilizzo delle closures per la gestione del routing in un ipotetico
framework:
 
<?php
 
class App
{
  protected $routes              = array();
  protected $responseStatus      = '200 OK';
  protected $responseContentType = 'text/html';
  protected $responseBody        = 'Hello world';
 
  public function addRoute($routePath, $routeCallback)
  {
    $this->routes[$routePath] = $routeCallback->bindTo($this, __CLASS__);
  }
 
  public function dispatch($currentPath)
  {
    foreach ($this->routes as $routePath => $callback) {
      if ($routePath === $currentPath) {
        $callback();
      }
    }
 
    header('HTTP/1.1 '.$this->responseStatus);
    header('Content-type: '.$this->responseContentType);
    header('Content-length: '.mb_strlen($this->responseBody));
    echo $this->responseBody;
  }
}
$app = new App();
$app->addRoute('/users/josh', function () {
  $this->responseContentType = 'application/json;charset=utf8';
  $this->responseBody        = '{"name": "Josh"}';
});
$app->dispatch('/users/josh');
 
?>
 
È molto interessante come la bindTo() cambi lo scope della closure
permettendole di accedere ai membri protected della classe. Questo
codice ricorda molto Javascript...
 
Ma non è una violazione del principio di incapsulazione?
 
Altra comodità delle closures che uso spesso sono le callback anonime,
per esempio usate in usort o funzioni simili.
 
Ci sono altri ambiti dove usate le closures?
 
-- 
g4b0, linux user n. 369000
http://brosulo.net
 

 
 
Certo. Infatti non ho mai capito tutto questo mischione di concetti OOP e
funzionali, o meglio, mi son fatto l'idea che derivi o dalla malafede o
dall'incompetenza :(
 
In JS usa le closures, e lascia perdere tutti quei trucchi per avere delle
specie d'oggetti, e in PHP usa gli oggetti, e lascia perdere le closures
(o usa le closures e non scrivere nemmeno un oggetto).
 
M2C.
 
Ciao!

 (o usa le closures e non scrivere nemmeno un oggetto).
 
Anche io non sono un grande fan degli "oggetti" in JS, mi sanno più di
accrocchio che di buona programmazione, ma probabilmente mi sbaglio in
quanto non ho mai approfondito un granchè l'argomento.
 
In php, invece, trovo che le closures usate come callback "semplici"
siano un modo decisamente elegante di risolvere determinati problemi.



 
Per avere una callback non c'è bisogno di entrare in closure, basta passare
la funzione.
 
Ciao!

 Ci sono altri ambiti dove usate le closures?
 
Le uso più o meno allo stesso modo in cui le usa PHP: per far 
customizzare il comportamento di certi algoritmi in base a chi li chiama.
 
Per esempio di recente ho implementato un sistema di templating per un 
software di mailing, e il wrapping dei link doveva essere diverso tra la 
preview durante la creazione della mail, durante l'invio per posta e 
durante la visualizzazione "web" della mail stessa. Quindi ho 
semplicemente creato tre funzioni di wrapping che prendevano il tag <a> 
come parametro e ne sostituivano l'href, mantenendo uguale tutto il resto 
dell'engine.
 
Bye.
 
 

 dell'engine.
 
Ma hai usato una closure o una anonfunc semplice per fare questo?


 Ma hai usato una closure o una anonfunc semplice per fare questo?
 
Il bello è che puoi decidere al momento. :)
Nel mio caso ho usato due volta una funzione anonima e una volta una 
closure, ma il motore di template non lo sa. A lui basta che la firma 
della funzione sia la stessa.
 
Mi spiego. Dato $template il motore, da una parte (preview) chiamo:
 
$res = $template->render(function($previewLinks) { ... }):
 
Da un'altra (invio o "vedi online"):
 
$res = $template->render(function($links) use ($user) {...})
 
Il motore di rendering è qualcosa tipo
 
public function render($linkProcessor) {
  foreach ($this->links as $linkId => $link) {
    $this->links[$linkId] = $linkProcessor($link);
  }
  ...
  return $processed;
}
 
Non lo sa che quella funzione in invio ha bisogno dei dati dell'utente 
corrente e in preview no.
 
Bye.