il pattern di zend framework 2
DESCRIPTION
Questo seminario web, originariamente ideato da Matthew Weier O'Phinney, Team Leader del progetto Zend Framework, fornisce una panoramica di questi pattern, li identifica e tratta le interfacce coinvolte e i casi d'uso concreti. Enrico Zimuel, Senior PHP Architect italiano, che recentemente si è unito al team di sviluppo dello Zend Framework, mostrerà come sia possibile creare le proprie implementazioni e come effettuarne lo slip-stream nelle applicazioni. Fra i pattern discussi: eventi, broker e dispatcher.TRANSCRIPT
© All rights reserved. Zend Technologies, Inc.
Zend Framework 2
presenta Enrico Zimuel ([email protected])
Senior Software Engineer, Zend TechnologiesZend Framework Core Team
© All rights reserved. Zend Technologies, Inc.
Sommario
● Breve storia del progetto Zend Framework
● Zend Framework 2.0
● I pre-requisiti di ZF 2
● Miglioramento delle performance
● Nuove funzionalità e design patterns
▶ Event Manager▶ Dependency Injection▶ Service Locator
© All rights reserved. Zend Technologies, Inc.
Zend Framework
© All rights reserved. Zend Technologies, Inc.
Breve storia di ZF
● October 2005: Annuncio del progetto
● March 2006: Prima versione (pulic review), 0.1.0
● Fall 2006: Riscrittura dell'MVC
● July 2007: Prima release stabile 1.0
● March 2008: Prima minor release 1.5.0
▶ Zend_Form, Zend_Layout
● September 2008: 1.6.0
▶ Integrazione con Dojo, PHPUnit scaffolding
● November 2008: 1.7.0
▶ Supporto AMF, miglioramento delle performance
© All rights reserved. Zend Technologies, Inc.
Breve storia di ZF (2)● April 2009: 1.8.0
▶ Zend_Tool, Zend_Application● August 2009: 1.9.0
▶ Aggiunta di Zend_Feed_Reader
▶ Supporto di PHP 5.3● January 2010: 1.10.0
▶ Aggiunta di Zend_Feed_Writer, refactoring di Zend_Feed▶ Cambio della documentazione: adozione di PhD per la
generazione del manuale utente, aggiunta dei commenti, nuova sezione “Learning Zend Framework section”
● November 2010: 1.11.0
▶ Supporto dispositivi mobile tramiteZend_Http_UserAgent▶ Simple Cloud API tramite Zend_Cloud
© All rights reserved. Zend Technologies, Inc.
© All rights reserved. Zend Technologies, Inc.
Zend Framework 2.0● Nuova major release
▶ Ci ha permesso di non dover tener conto della retro-compatibilità
▶ Prerequisiti: PHP 5.3 e superiore
● Attenzione posta su:▶ Consistenza▶ Performance▶ Documentazione▶ Produttività utente
© All rights reserved. Zend Technologies, Inc.
Primi passi verso ZF 2.0
● Conversione del codice da prefissi gestiti a mano (es. “Zend_Foo”) ai namespace nativi di PHP 5.3
● Refactoring delle Eccezioni
● Cambio di ZF per essere solo autoload
● Miglioramento e standardizzazione del sistema di plugin
© All rights reserved. Zend Technologies, Inc.
ZF 2.0 (dev3)
● Il 14 giugno è stata rilasciata la versione dev3 di Zend Framework 2.0
● Tra le funzionalità già implementate:
▶ Refactoring di Zend\Tool e CodeGenerator
▶ Migrazione e refactoring dei servizi LiveDocx ▶ EventManager ▶ Dependency Injection
● Maggiori info: http://bit.ly/lptIpN
© All rights reserved. Zend Technologies, Inc.
“Riscrivere il codice solo se ha senso”
© All rights reserved. Zend Technologies, Inc.
ZF2 in una slide
● Miglioramenti:
▶ Namespace (supporto nativo di PHP)▶ Exception▶ Autoloading▶ MVC▶ Plugin▶ Documentazione▶ Performance
● Nuove funzionalità:
▶ Event Manager▶ Dependency Injection / Service Locator▶ Supporto di nuovi servizi cloud▶ Molto altro ancora...
© All rights reserved. Zend Technologies, Inc.
Namespace
© All rights reserved. Zend Technologies, Inc.
L'approccio di ZF2 ai namespace
● Formalizzare i prefissi utilizzati in ZF1
▶ Separatore di namespace correllato con il separatore di directory
● Aiutare ad identificare le dipendenze (imports)
▶ Abilitare il refactoring utilizzazando diverse implementazioni
▶ Facilitare il sistema di packaging
© All rights reserved. Zend Technologies, Inc.
Namespace
namespace Zend\EventManager;
use Zend\Stdlib\CallbackHandler;
class EventManager implements EventCollection{ /* ... */}
namespace Zend\EventManager;
use Zend\Stdlib\CallbackHandler;
class EventManager implements EventCollection{ /* ... */}
© All rights reserved. Zend Technologies, Inc.
Namespace● Interfacce come namespace
▶ I nomi d'interfaccia sono aggettivi o sostantivi
▶ Implementazione concreta in sub-namespace denominati dopo l'interfaccia
▶ Paradigma Contract-Oriented
© All rights reserved. Zend Technologies, Inc.
Interfacce come Namespace
Zend/Session|-- Storage.php`-- Storage |-- ArrayStorage.php `-- SessionStorage.php
namespace Zend\Session;interface Storage { /* ... */}
namespace Zend\Session;interface Storage { /* ... */}
namespace Zend\Session\Storage;use ArrayObject, Zend\Session\Storage, Zend\Session\Exception;class ArrayStorage extends ArrayObject implements Storage{ /* ... */ }
namespace Zend\Session\Storage;use ArrayObject, Zend\Session\Storage, Zend\Session\Exception;class ArrayStorage extends ArrayObject implements Storage{ /* ... */ }
© All rights reserved. Zend Technologies, Inc.
ZF2 approccio ai namespace
● Ogni file di classe dichiara un namespace
● Un namespace per file
● Ogniclasse utilizzata che non fa parte del namespace attuale è importata (tipicamante tramite un alias)
● L'uso di riferimenti globali di classe è scoraggiato, eccetto nel caso di classi referenziate tramite stringhe
© All rights reserved. Zend Technologies, Inc.
Autoloading
© All rights reserved. Zend Technologies, Inc.
ZF2 Autoloading● Non più chiamate require_once!● Differenti approcci:
▶ Stile ZF1 con include_path autoloader▶ Per-namespace/prefix autoloading▶ Class-map autoloading
© All rights reserved. Zend Technologies, Inc.
Stile ZF1 di autoloading
require_once 'Zend/Loader/StandardAutoloader.php';$loader = new Zend\Loader\StandardAutoloader(array( 'fallback_autoloader' => true,));$loader->register();
require_once 'Zend/Loader/StandardAutoloader.php';$loader = new Zend\Loader\StandardAutoloader(array( 'fallback_autoloader' => true,));$loader->register();
© All rights reserved. Zend Technologies, Inc.
ZF2 NS/Prefix Autoloading
require_once 'Zend/Loader/StandardAutoloader.php';$loader = new Zend\Loader\StandardAutoloader();$loader->registerNamespace( 'My', __DIR__ . '/../library/My') ->registerPrefix( 'Phly_', __DIR__ . '/../library/Phly');$loader->register();
require_once 'Zend/Loader/StandardAutoloader.php';$loader = new Zend\Loader\StandardAutoloader();$loader->registerNamespace( 'My', __DIR__ . '/../library/My') ->registerPrefix( 'Phly_', __DIR__ . '/../library/Phly');$loader->register();
© All rights reserved. Zend Technologies, Inc.
ZF2 Class-Map Autoloading
return array( 'My\Foo\Bar' => __DIR__ . '/Foo/Bar.php',);
return array( 'My\Foo\Bar' => __DIR__ . '/Foo/Bar.php',);
require_once 'Zend/Loader/ClassMapAutoloader.php';$loader = new Zend\Loader\ClassMapAutoloader();$loader->registerAutoloadMap( __DIR__ . '/../library/.classmap.php');$loader->register();
require_once 'Zend/Loader/ClassMapAutoloader.php';$loader = new Zend\Loader\ClassMapAutoloader();$loader->registerAutoloadMap( __DIR__ . '/../library/.classmap.php');$loader->register();
● .classmap.php:
© All rights reserved. Zend Technologies, Inc.
Class-Maps richiede più lavoro?
● Si, ma abbiamo già rilasciato un tool a linea di comando: bin/classmap_generator.php
● L'utilizzo è immediato:
$ cd your/library$ php /path/to/classmap_generator.php -w
$ cd your/library$ php /path/to/classmap_generator.php -w
● Class-Map verrà creato in .classmap.php
© All rights reserved. Zend Technologies, Inc.
Perchè?
● Class-Maps evidenzia un miglioramento di performance del 25% rispetto all'autoloader del ZF1 (senza acceleratore di opcode)
▶ e un miglioramento del 60-85% con un acceleratore di bytecode PHP
● L'utilizzo di prefissi e namespace con percorsi specifici evidenzia un miglioramento del 10% sulle performance (senza acceleratore di opcode)
▶ e un miglioramento del 40% con un acceleratore di bytecode PHP
© All rights reserved. Zend Technologies, Inc.
Strategie di autoloading
● Con strategie di autoloading differenti c'è la necessità di un factory
● Scegliere tra differenti strategie:
▶ Class-Map per performance migliori▶ Prefissi/Namespace per esigenze standard▶ Autoloader “classico” (in stile ZF1) per
ambienti di sviluppo
© All rights reserved. Zend Technologies, Inc.
Migrare a ZF2
● Potete utilizzare il nuovo autoloader ZF2 da subito, anche per progetti ZF1
● Iniziare a migrare ora!
● “Backported ZF2 Autoloaders”by Matthew Weier O'Phinney http://bit.ly/mq4UAh
27 © All rights reserved. Zend Technologies, Inc.
Exception
© All rights reserved. Zend Technologies, Inc.
Problema● Tutte le eccezioni derivano da una classe
comune● Nessuna possibilità di espandere la
semantica delle eccezioni tramite SPL
© All rights reserved. Zend Technologies, Inc.
L'approccio di ZF2● Eliminare Zend_Exception● Ogni componente definisce una propria
interfaccia di eccezioni● Eccezioni addizionali vengono create in
un subnamespace specifico▶ Queste eccezioni estendono le funzionalità
SPL ed implementato le interfacce specifiche dei componenti
© All rights reserved. Zend Technologies, Inc.
Vantaggi● Intercetttare specifiche eccezioni● Intercettare eccezioni di tipo SPL● Intercettare eccezioni a livello di
componenti● Intercettare basandosi su un tipo di
eccezione globale
© All rights reserved. Zend Technologies, Inc.
Esempio di ExceptionZend/EventManager|-- Exception.php`-- Exception `-- InvalidArgument- Exception.php
Zend/EventManager|-- Exception.php`-- Exception `-- InvalidArgument- Exception.php
namespace Zend\EventManager;
interface Exception {}
namespace Zend\EventManager;
interface Exception {}
namespace Zend\EventManager\Exception;
use Zend\EventManager\Exception;
class InvalidArgumentException extends \InvalidArgumentException implements Exception{}
namespace Zend\EventManager\Exception;
use Zend\EventManager\Exception;
class InvalidArgumentException extends \InvalidArgumentException implements Exception{}
© All rights reserved. Zend Technologies, Inc.
Esempio di Exception (2)
namespace Zend\EventManager\Exception;use Zend\EventManager\Exception;try { $events->trigger('foo.bar', $object);} catch (InvalidArgumentException $e) {} catch (Exception $e) {} catch (\InvalidArgumentException $e) {} catch (\Exception $e) {}
namespace Zend\EventManager\Exception;use Zend\EventManager\Exception;try { $events->trigger('foo.bar', $object);} catch (InvalidArgumentException $e) {} catch (Exception $e) {} catch (\InvalidArgumentException $e) {} catch (\Exception $e) {}
33 © All rights reserved. Zend Technologies, Inc.
Nuove funzionalità
© All rights reserved. Zend Technologies, Inc.
Nuove funzionalità● Zend\EventManager
● Zend\Di
● Nuovi servizi cloud:▶ Zend\Rackspace
▶ Zend\Service\GoGrid
▶ Zend\Cloud\Infrastructure
● Amazon S3● Rackspace● GoGrid
● E molto altro...
35 © All rights reserved. Zend Technologies, Inc.
Event manager
© All rights reserved. Zend Technologies, Inc.
Il problema● Come inserire sistemi di logging/debug in un progetto Zend
Framework?
● Come offrire la possibilità di utilizzare un sistema di caching senza estendere il codice del framework?
● Come offrire la possibilità di validare, filtrare, gestire un ACL, etc, senza estendere il codice del framework?
● Come offrire la possibilità di decidere l'ordine di un plugin, di intercettare un filtro, un evento, un trigger, etc?
● Come offrire uno strumento in grado di soddisfare queste esigenze?
© All rights reserved. Zend Technologies, Inc.
ZF2 Event Manager● Summa di diversi design patterns: PubSub,
SignalSlot, ed Intercepting Filters
● Non risolvono completamente il problema di composizione/statici
▶ Possiamo risolverlo in PHP 5.4 via Traits▶ Ci sono alcuni modi eleganti per gestire
componenti statici
© All rights reserved. Zend Technologies, Inc.
Interfaccia EventCollection
namespace Zend\EventManager;use Zend\Stdlib\CallbackHandler;interface EventCollection{public function trigger($event, $context, $argv = array());public function triggerUntil($event, $context, $argv, $callback);public function attach($event, $callback, $priority = 1);public function detach(CallbackHandler $handle);public function getEvents();public function getHandlers($event);public function clearHandlers($event);}
namespace Zend\EventManager;use Zend\Stdlib\CallbackHandler;interface EventCollection{public function trigger($event, $context, $argv = array());public function triggerUntil($event, $context, $argv, $callback);public function attach($event, $callback, $priority = 1);public function detach(CallbackHandler $handle);public function getEvents();public function getHandlers($event);public function clearHandlers($event);}
© All rights reserved. Zend Technologies, Inc.
Triggering di eventi
use Zend\EventManager\EventManager;$events = new EventManager();$events->trigger($eventName, $object, $params);
use Zend\EventManager\EventManager;$events = new EventManager();$events->trigger($eventName, $object, $params);
● Dove:▶ $eventName è il nome dell'evento, di solito il nome
del metod
▶ $object è l'oggetto triggering dell'evento
▶ $params sono i parametri di cui l'handler necessita, di solito gli argomenti del metodo
© All rights reserved. Zend Technologies, Inc.
CallbackHandler
$handler = $events->attach(’some-event’, function($e) use ($log) {
$event = $e->getName();$context = get_class($e->getTarget());$params = json_encode($e->getParams());$log->info(sprintf("%s: %s: %s", $event,
$context, $params));});
$handler = $events->attach(’some-event’, function($e) use ($log) {
$event = $e->getName();$context = get_class($e->getTarget());$params = json_encode($e->getParams());$log->info(sprintf("%s: %s: %s", $event,
$context, $params));});
© All rights reserved. Zend Technologies, Inc.
Comporre un Event Manager
use Zend\EventManager\EventCollection as Events, Zend\EventManager\EventManager;
class Foo{
protected $events;public function events(Events $events = null) {
if (null !== $events) {$this->events = $events;
} elseif (null === $this->events) {$this->events = new EventManager(__CLASS__);
}return $this->events;
}public function doSomething($param1, $param2) {
$params = compact('param1', 'param2');$this->events()->trigger(__FUNCTION__, $this, $params);
}}
use Zend\EventManager\EventCollection as Events, Zend\EventManager\EventManager;
class Foo{
protected $events;public function events(Events $events = null) {
if (null !== $events) {$this->events = $events;
} elseif (null === $this->events) {$this->events = new EventManager(__CLASS__);
}return $this->events;
}public function doSomething($param1, $param2) {
$params = compact('param1', 'param2');$this->events()->trigger(__FUNCTION__, $this, $params);
}}
© All rights reserved. Zend Technologies, Inc.
Utilizzo dei Trait!
use Zend\EventManager\EventCollection as Events, Zend\EventManager\EventManager;
trait Eventful{
public function events(Events $events = null) {if (null !== $events) {
$this->events = $events;} elseif (null === $this->events) {
$this->events = new EventManager(__CLASS__);}return $this->events;
}}class Foo{
use Eventful;protected $events;
}
use Zend\EventManager\EventCollection as Events, Zend\EventManager\EventManager;
trait Eventful{
public function events(Events $events = null) {if (null !== $events) {
$this->events = $events;} elseif (null === $this->events) {
$this->events = new EventManager(__CLASS__);}return $this->events;
}}class Foo{
use Eventful;protected $events;
}
43 © All rights reserved. Zend Technologies, Inc.
Dependency Injection
© All rights reserved. Zend Technologies, Inc.
Il problema
● Come gestire le dipendeze tra oggetti?▶ In particolare, come gestire le dipendenze
tra Controller?
© All rights reserved. Zend Technologies, Inc.
L'approccio di ZF2 ● Service Locator
▶ Schema di base: ● set($name, $service)● get($name)
▶ Formalizzazione dell'application service(mailer, logger, profiler, etc.)
▶ Buone interfacce con il typehinting
© All rights reserved. Zend Technologies, Inc.
Service Locator
use Zend\Di\ServiceLocator, Zend\EventManager\EventManager;
class MyLocator extends ServiceLocator{ protected $events; protected $map = array('events' => 'getEvents');
public function getEvents() { if (null !== $this->events) { return $this->events; } $this->events = new EventManager(); return $this->events; }}
use Zend\Di\ServiceLocator, Zend\EventManager\EventManager;
class MyLocator extends ServiceLocator{ protected $events; protected $map = array('events' => 'getEvents');
public function getEvents() { if (null !== $this->events) { return $this->events; } $this->events = new EventManager(); return $this->events; }}
© All rights reserved. Zend Technologies, Inc.
L'approccio di ZF2 ● Dependency Injection Container
▶ Injection in costruzione (construct) e setters
▶ Via codice o tramite configurazione▶ Tipicamente utilizzato per iniettare un
service locator
© All rights reserved. Zend Technologies, Inc.
Dependency Injection
$db = new Definition('My\Db\Adapter\Sqlite');$db->setParam('name', __DIR__ . '/../data/db/users.db');
$mapper = new Definition('My\Mapper\Db');$mapper->addMethodCall( 'setAdapter', array(new Reference('db')));
$service = new Definition('My\Resource\Users');$service->setParam('mapper', new Reference('mapper'));
$di = new DependencyInjector;$di->setDefinitions(array( 'db' => $db, 'mapper' => $mapper, 'users' => $service,));
$users = $di->get('users'); // My\Resource\Users
$db = new Definition('My\Db\Adapter\Sqlite');$db->setParam('name', __DIR__ . '/../data/db/users.db');
$mapper = new Definition('My\Mapper\Db');$mapper->addMethodCall( 'setAdapter', array(new Reference('db')));
$service = new Definition('My\Resource\Users');$service->setParam('mapper', new Reference('mapper'));
$di = new DependencyInjector;$di->setDefinitions(array( 'db' => $db, 'mapper' => $mapper, 'users' => $service,));
$users = $di->get('users'); // My\Resource\Users
© All rights reserved. Zend Technologies, Inc.
Controller come servizi● Risolve il problema della dipendenza dei
controller● Ogni richiesta istanzia soltanto lo stretto
necessario● Migliore testabilità dei controller
© All rights reserved. Zend Technologies, Inc.
Controller come servizi: esempio
$userController = new Definition('Site\Controller\User');$userController->setParam('service',
new Reference('users'));$di->setDefinition($userController, 'controller-user');
// Inside dispatcher:$controller = $di->get($controllerName);$result = $controller->dispatch($request, $response);
$userController = new Definition('Site\Controller\User');$userController->setParam('service',
new Reference('users'));$di->setDefinition($userController, 'controller-user');
// Inside dispatcher:$controller = $di->get($controllerName);$result = $controller->dispatch($request, $response);
51 © All rights reserved. Zend Technologies, Inc.
Nuovi servizi cloud
© All rights reserved. Zend Technologies, Inc.
Zend\Cloud● Supporto di nuovi servizi cloud:
▶ Rackspace ▶ GoGrid
● Supporto di Rackspace in Zend\Cloud\StorageService
▶ Rackspace
● Zend\Cloud\Infrastructure per la gestione delle infrastrutture di cloud computing:
▶ Amazon EC2▶ Rackspace Cloud Servers▶ GoGrid▶ Windows Azure
© All rights reserved. Zend Technologies, Inc.
Zend\Cloud\Infrastructure● Zend\Cloud\Infrastructure (alpha version):
▶ Attualmente supporta soltanto Amazon EC2▶ A breve disponibili adapter per Rackspace
Servers e GoGrid▶ Download: http://bit.ly/imQLzB
● Zend\Service\Rackspace\Files (beta version):
▶ Download: http://bit.ly/muC6AT
54 © All rights reserved. Zend Technologies, Inc.
Partecipare al progetto
© All rights reserved. Zend Technologies, Inc.
Contribuire a ZF2
● ZF2 wiki:
▶ http://bit.ly/zf2wiki● zf-contributors mailing list:
▶ [email protected]● IRC:
▶ #zftalk.dev su Freenode
© All rights reserved. Zend Technologies, Inc.
Risorse● Git guide:
▶ http://bit.ly/zf2gitguide● GitHub:
▶ http://github.com/zendframework/zf2● Official repo:
▶ git://git.zendframework.com/zf.git▶ http://git.zendframework.com/
© All rights reserved. Zend Technologies, Inc.
Domande?
© All rights reserved. Zend Technologies, Inc.
Grazie!
Maggiori informazioni:http://www.zend.comhttp://framework.zend.com/