SlideShare a Scribd company logo
Zend Framework 2 Patterns
Matthew Weier O'Phinney
Project Lead, Zend Framework


To watch the webinar please go to:
http://www.zend.com/en/webinar/Framework/70170000000bX3J-
webinar-zf-2-patterns-20110330.flv


                                                Š All rights reserved. Zend Technologies, Inc.
Roadmap for today
●   Namespaces and Autoloading
●   Exceptions
●   Configuration
●   Plugin systems
●   Dispatching
●   Inversion of Control




                     Š All rights reserved. Zend Technologies, Inc.
Format
●   List The Problems
●   Detail the ZF2 Approach




                    Š All rights reserved. Zend Technologies, Inc.
But first, some history




     Š All rights reserved. Zend Technologies, Inc.
Zend Framework 1.X
●   1.0 Released in July 2007
●   Largely evolutionary development
    ▶   Inconsistencies in APIs, particularly surrounding
        plugins and configuration
    ▶   Best practices have been discovered over time
    ▶   Many key features for modern applications have
        been added in recent versions




                         Š All rights reserved. Zend Technologies, Inc.
Zend Framework 2.0
●   First new major release
    ▶   Allowing us to break backwards compatibility
●   Focus is on:
    ▶   Consistency
    ▶   Performance
    ▶   Documentation
    ▶   User productivity




                        Š All rights reserved. Zend Technologies, Inc.
Namespaces and Autoloading




7          Š All rights reserved. Zend Technologies, Inc.
The Problems
●   Lengthy class names
    ▶   Difficult to refactor
    ▶   Difficult to retain semantics with shorter names
●   Performance issues
    ▶   Many classes are used JIT, and shouldn't be loaded
        until needed
●   Missing require_once statements lead to errors




                          Š All rights reserved. Zend Technologies, Inc.
ZF2 Approach: Namespaces
●   Formalize the prefixes used in ZF1
    ▶   Namespace separator correlates to directory
        separator
●   Help identify dependencies (imports)
    ▶   Allows refactoring using different implementations
        easier
    ▶   Makes packaging easier




                        Š All rights reserved. Zend Technologies, Inc.
Namespaces


namespace ZendEventManager;

use ZendStdlibCallbackHandler;

class EventManager implements EventCollection
{
    /* ... */
}




                   Š All rights reserved. Zend Technologies, Inc.
Namespaces
●   Interfaces as namespaces
    ▶   Interface names are adjectives or nouns
    ▶   Concrete implementations in a sub-namespace
        named after the interface
    ▶   Contract-Oriented paradigm




                        Š All rights reserved. Zend Technologies, Inc.
Interfaces as Namespaces
Zend/Session              namespace ZendSession;
|-- Storage.php           interface Storage
`-- Storage
                          {
    |--
                              /* ... */
ArrayStorage.php
                          }
    `--
SessionStorage.php
namespace ZendSessionStorage;
use ArrayObject,
    ZendSessionStorage,
    ZendSessionException;
class ArrayStorage
    extends ArrayObject
    implements Storage
{ /* ... */ }
                   Š All rights reserved. Zend Technologies, Inc.
ZF2 Approach: Autoloading
●   No more require_once calls!
●   Multiple approaches
    ▶   ZF1-style include_path autoloader
    ▶   Per-namespace/prefix autoloading
    ▶   Class-map autoloading




                        Š All rights reserved. Zend Technologies, Inc.
ZF1-Style Autoloading



require_once
'Zend/Loader/StandardAutoloader.php';
$loader =
    new ZendLoaderStandardAutoloader(array(
    'fallback_autoloader' => true,
));
$loader->register();




                   Š All rights reserved. Zend Technologies, Inc.
ZF2 NS/Prefix Autoloading


require_once
'Zend/Loader/StandardAutoloader.php';
$loader = new ZendLoaderStandardAutoloader();
$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(
    'MyFooBar' => __DIR__ . '/Foo/Bar.php',
);



require_once
'Zend/Loader/ClassMapAutoloader.php';
$loader = new ZendLoaderClassMapAutoloader();
$loader->registerAutoloadMap(
    __DIR__ . '/../library/.classmap.php');
$loader->register();



                   Š All rights reserved. Zend Technologies, Inc.
Exceptions




17   Š All rights reserved. Zend Technologies, Inc.
The Problems
●   All exceptions derived from a common class
●   No ability to extend more semantic exception
    types offered in SPL




                    Š All rights reserved. Zend Technologies, Inc.
ZF2 Approach
●   Eliminated Zend_Exception
●   Each component defines a marker Exception
    interface
●   Additional exception types are created in an
    Exception subnamespace
    ▶   These extend SPL exceptions, and implement the
        component-level exception interface




                       Š All rights reserved. Zend Technologies, Inc.
What the solution provides
●   Catch specific exception types
●   Catch SPL exception types
●   Catch any component-level exception
●   Catch based on global exception type




                     Š All rights reserved. Zend Technologies, Inc.
Exceptions in use
Zend/EventManager                               namespace
|-- Exception.php                               ZendEventManager;
`-- Exception
    `-- InvalidArgument-                        interface Exception {}
        Exception.php



namespace ZendEventManagerException;

use ZendEventManagerException;

class InvalidArgumentException
    extends InvalidArgumentException
    implements Exception
{}


                     Š All rights reserved. Zend Technologies, Inc.
Exceptions in use

namespace ZendEventManagerException;
use ZendEventManagerException;
try {
    $events->trigger('foo.bar', $object);
} catch (InvalidArgumentException $e) {
} catch (Exception $e) {
} catch (InvalidArgumentException $e) {
} catch (Exception $e) {
}




                    Š All rights reserved. Zend Technologies, Inc.
Configuration




23   Š All rights reserved. Zend Technologies, Inc.
The Problems
●   Case-SeNSItiviTy
●   Varying APIs
    ▶   setOptions()
    ▶   setConfig()
    ▶   __construct()
    ▶   explicit setters




                           Š All rights reserved. Zend Technologies, Inc.
ZF2 Approach
●   Option names will be
    lowercase_underscore_separated_word
    s
●   Standard solution across components
    ▶   setOptions() style, proxying to setters, or
    ▶   per-component configuration objects




                        Š All rights reserved. Zend Technologies, Inc.
setOptions() style
class Foo
{
    public function setOptions($options)
    {
        if (!is_array($options)
            && !($options instanceof
Traversable)
        ) {
            throw new
InvalidArgumentException();
        }

       foreach ($options as $key => $value) {
           $method = normalize($key);
           if (method_exists($this, $method)) {
               $this->$method($value);
           }
       }           Š All rights reserved. Zend Technologies, Inc.
Options object style
class FooOptions extends Options
{
    public $bar;
    public $baz;

    public function __construct($options = null)
    {
        if (!is_array($options)
            && !($options instanceof Traversable)
        ) {
            throw new InvalidArgumentException();
        }

        foreach ($options as $key => $value) {
            $prop = normalize($key);
            $this->$prop = $value;
        }
    }
}                    Š All rights reserved. Zend Technologies, Inc.
Options object style


class Foo
{
    public function __construct(Options $options =
null)
    {
        if (null !== $options) {
            foreach ($options as $key => $value) {
                $this->$key = $value;
            }
        }
    }
}



                     Š All rights reserved. Zend Technologies, Inc.
Plugin Architectures




29       Š All rights reserved. Zend Technologies, Inc.
Terminology
●   For our purposes, a “plugin” is any class that is
    determined at runtime.
    ▶   Action and view helpers
    ▶   Adapters
    ▶   Filters and validators




                         Š All rights reserved. Zend Technologies, Inc.
The Problems
●   Varying approaches to dynamically discovering
    plugin classes
    ▶   Prefix-path stacks (most common)
    ▶   Paths relative to the calling class
    ▶   Setters to indicate classes
●   Most common approach is terrible
    ▶   Bad performance
    ▶   Hard to debug
    ▶   No caching of discovered plugins

                          Š All rights reserved. Zend Technologies, Inc.
ZF2 Approach: Plugin Broker
●   Separate Plugin Location interface
    ▶   Allows varying implementation of plugin lookup
●   Separate Plugin Broker interface
    ▶   Composes a Plugin Locator




                        Š All rights reserved. Zend Technologies, Inc.
ZF2 Approach: Plugin Broker
●   Standard implementation across components
    ▶   Subclassing standard implementation allows type-
        hinting, caching discovered plugins, etc.
    ▶   while allowing you to substitute your own
        implementations
●   Class-map location by default
●   2-5x performance gains!
●   Easier to debug


                        Š All rights reserved. Zend Technologies, Inc.
Plugin class location
namespace ZendLoader;

interface ShortNameLocater
{
    public function isLoaded($name);
    public function getClassName($name);
    public function load($name);
}
namespace ZendView;
use ZendLoaderPluginClassLoader;
class HelperLoader extends PluginClassLoader
{
    protected $plugins = array(
        'action' => 'ZendViewHelperAction',
        'baseurl' => 'ZendViewHelperBaseUrl',
        /* ... */
    );
}
                     Š All rights reserved. Zend Technologies, Inc.
Plugin broker

namespace ZendLoader;

interface Broker
{
    public function load($plugin, array $options =
null);
    public function getPlugins();
    public function isLoaded($name);
    public function register($name, $plugin);
    public function unregister($name);
    public function setClassLoader(
        ShortNameLocater $loader);
    public function getClassLoader();
}



                     Š All rights reserved. Zend Technologies, Inc.
Plugin broker
class HelperBroker extends PluginBroker {
    protected $defaultClassLoader =
'ZendViewHelperLoader';
    protected $view;
    public function setView(Renderer $view) {}
    public function getView() {}
    public function load($plugin, array $options = null) {
        $helper = parent::load($plugin, $options);
        if (null !== ($view = $this->getView())) {
            $helper->setView($view);
        }
        return $helper;
    }
    protected function validatePlugin($plugin)
    {
        if (!$plugin instanceof Helper) {
            throw new InvalidHelperException();
        }
        return true;
    }
}                       Š All rights reserved. Zend Technologies, Inc.
ZF2 Approach: Events
●   Trigger events at interesting points in your
    application
    ▶   Use as basic subject/observer pattern
    ▶   Or as intercepting filters
    ▶   Or a full-fledged Aspect-Oriented Programming
        system




                          Š All rights reserved. Zend Technologies, Inc.
ZF2 Approach: Events
●   Compose an EventManager to a class
●   Attach handlers to events
    ▶   Handlers receive an Event
         ●   event name
         ●   target (calling) object
         ●   parameters passed
    ▶   Handlers can also be attached statically




                              Š All rights reserved. Zend Technologies, Inc.
Triggering an event


public function doSomething(
    $with, $params = array()
) {
    $this->events()->trigger(
        __FUNCTION__, compact('with', 'params')
    );
    /* ... */
}




                   Š All rights reserved. Zend Technologies, Inc.
Listening to an event

use ZendEventManagerEventManager as Events;

$events = new Events();
$events->attach('doSomething', function($e) use
($log) {
    $event = $e->getName();
    $target = get_class($e->getTarget());
    $params = json_encode($e->getParams());
    $message = sprintf('%s (%s): %s', $event,
$target, $params);
    $log->info($message);
});




                     Š All rights reserved. Zend Technologies, Inc.
Attaching statically to an event


use ZendEventManagerStaticEventManager as
AllEvents;

$events = AllEvents::getInstance();

// Specify the class composing an EventManager
// as first arg
$events->attach('Foo', 'doSomething', function($e)
{});




                     Š All rights reserved. Zend Technologies, Inc.
Dispatchers




42   Š All rights reserved. Zend Technologies, Inc.
The Problems
●   Not terribly performant
●   Hard to customize
●   Hard to inject controllers with dependencies
●   Forces pre-initialization of resources if you
    want them configured by Zend_Application




                     Š All rights reserved. Zend Technologies, Inc.
ZF2 Approach
●   Discrete Request, Response, and Dispatchable
    interfaces
    ▶   Request encompasses request environment
    ▶   Response aggregates response returned
    ▶   Dispatchable objects formalize a Strategy
        pattern




                       Š All rights reserved. Zend Technologies, Inc.
ZF2 Approach
●   Anything Dispatchable can be attached to the
    MVC
    ▶   Server components (XML-RPC, JSON-RPC, etc.)
●   Allows building your own MVC approach
    ▶   Do you want action methods to receive explicit
        arguments?
    ▶   Do you want to select a different action method
        based on request headers?



                        Š All rights reserved. Zend Technologies, Inc.
MVC Interfaces
interface Message
{
    public function setMetadata($spec, $value =
null);
    public function getMetadata($key = null);
    public function setContent($content);
    public function getContent();
}
interface Request           interface Response
    extends Message             extends Message
{                           {
    public function             public function
        __toString();               __toString();
    public function             public function

fromString($string);                              fromString($string);
}                                                     public function
                                                  send();
                                                  }
                       Š All rights reserved. Zend Technologies, Inc.
MVC Interfaces


interface Dispatchable
{
    public function dispatch(
        Request $request,
        Response $response = null);
}




                   Š All rights reserved. Zend Technologies, Inc.
Inversion of Control




48      Š All rights reserved. Zend Technologies, Inc.
The Problems
●   How do objects get dependencies?
    ▶   In particular, how do Controllers get dependencies?




                         Š All rights reserved. Zend Technologies, Inc.
ZF2 Approach
●   Service Locator
    ▶   Basic pattern:
         ●   set($name, $service)
         ●   get($name)
    ▶   Formalization of application services
        (mailer, logger, profiler, etc.)
    ▶   Good interface for typehinting




                          Š All rights reserved. Zend Technologies, Inc.
Service Locator
use ZendDiServiceLocator,
    ZendEventManagerEventManager;

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.
ZF2 Approach
●   Dependency Injection Container
    ▶   Scaffolding for constructor and setter injection
    ▶   Use programmatically, or from configuration
    ▶   Typically used to seed a service locator




                         Š All rights reserved. Zend Technologies, Inc.
Dependency Injection
$db = new Definition('MyDbAdapterSqlite');
$db->setParam('name', __DIR__ .
'/../data/db/users.db');

$mapper = new Definition('MyMapperDb');
$mapper->addMethodCall(
    'setAdapter', array(new Reference('db')));

$service = new Definition('MyResourceUsers');
$service->setParam('mapper', new
Reference('mapper'));

$di = new DependencyInjector;
$di->setDefinitions(array(
    'db'     => $db,
    'mapper' => $mapper,
    'users' => $service,
));
                     Š All rights reserved. Zend Technologies, Inc.
Controllers as services
●   Solves issue of controller dependencies
●   Each request only instantiates what's needed
    for that request
●   Better testability of controllers




                      Š All rights reserved. Zend Technologies, Inc.
Controllers as services


$userController = new
Definition('SiteControllerUser');
$userController->setParam(
    'service', new Reference('users'));
$di->setDefinition($userController, 'controller-
user');

// Inside dispatcher:
$controller = $di->get($controllerName);
$result = $controller->dispatch($request, $response);




                     Š All rights reserved. Zend Technologies, Inc.
More to come!




56    Š All rights reserved. Zend Technologies, Inc.
Zend Framework 2.0
●   Schedule:
    ▶   MVC milestone by end of May
    ▶   Preview Release following MVC milestone
    ▶   Beta release during summer
    ▶   Stable by end-of-year




                        Š All rights reserved. Zend Technologies, Inc.
Resources




58   Š All rights reserved. Zend Technologies, Inc.
●   ZF2 Wiki: http://bit.ly/zf2wiki
●   ZF2 Git information: http://bit.ly/zf2gitguide
●   ZF2 MVC sandbox:
    git://git.mwop.net/zf2sandbox.git
●   ZF2 DI prototype: http://bit.ly/gBBnDS




                     Š All rights reserved. Zend Technologies, Inc.
Thank you!
     ●   http://framework.zend.com/
     ●   http://twitter.com/weierophinney




60                        Š All rights reserved. Zend Technologies, Inc.
Webinar
    To watch the webinar please go to:
    http://www.zend.com/en/webinar/Framework/
    70170000000bX3J-webinar-zf-2-patterns-
    20110330.flv
    Or
    http://bit.ly/qXeCWI

    (short registration required)




Insert->Header & Footer             Š All rights reserved. Zend Technologies, Inc.   61

More Related Content

PDF
ZF2 Presentation @PHP Tour 2011 in Lille
Zend by Rogue Wave Software
 
PDF
Zend Framework 2 quick start
Enrico Zimuel
 
PDF
Quick start on Zend Framework 2
Enrico Zimuel
 
PDF
A quick start on Zend Framework 2
Enrico Zimuel
 
PDF
Manage cloud infrastructures using Zend Framework 2 (and ZF1)
Enrico Zimuel
 
PDF
Zend Framework 2 - Basic Components
Mateusz Tymek
 
PDF
Manage cloud infrastructures in PHP using Zend Framework 2 (and 1)
Enrico Zimuel
 
PDF
Testing untestable code - ConFoo13
Stephan HochdĂśrfer
 
ZF2 Presentation @PHP Tour 2011 in Lille
Zend by Rogue Wave Software
 
Zend Framework 2 quick start
Enrico Zimuel
 
Quick start on Zend Framework 2
Enrico Zimuel
 
A quick start on Zend Framework 2
Enrico Zimuel
 
Manage cloud infrastructures using Zend Framework 2 (and ZF1)
Enrico Zimuel
 
Zend Framework 2 - Basic Components
Mateusz Tymek
 
Manage cloud infrastructures in PHP using Zend Framework 2 (and 1)
Enrico Zimuel
 
Testing untestable code - ConFoo13
Stephan HochdĂśrfer
 

What's hot (19)

PDF
Testing untestable code - IPC12
Stephan HochdĂśrfer
 
PDF
Testing untestable code - PHPBNL11
Stephan HochdĂśrfer
 
PDF
Building DSLs with Xtext - Eclipse Modeling Day 2009
Heiko Behrens
 
PPTX
Interactive Java Support to your tool -- The JShell API and Architecture
JavaDayUA
 
PPTX
JShell: An Interactive Shell for the Java Platform
JavaDayUA
 
PDF
Diving into HHVM Extensions (PHPNW Conference 2015)
James Titcumb
 
PDF
How to build customizable multitenant web applications - PHPBNL11
Stephan HochdĂśrfer
 
PPT
Secure Programming
alpha0
 
PPT
Symfony2 Service Container: Inject me, my friend
Kirill Chebunin
 
PPTX
JavaOne 2014 - CON2013 - Code Generation in the Java Compiler: Annotation Pro...
Jorge Hidalgo
 
PDF
Apigility reloaded
Ralf Eggert
 
PDF
Irving iOS Jumpstart Meetup - Objective-C Session 1b
irving-ios-jumpstart
 
PDF
CFEngine 3
Brian Repko
 
PPTX
The Art of Metaprogramming in Java
Abdelmonaim Remani
 
PDF
Review unknown code with static analysis - bredaphp
Damien Seguy
 
PDF
Quick Intro To JRuby
Frederic Jean
 
KEY
Groovy DSLs, from Beginner to Expert - Guillaume Laforge and Paul King - Spri...
Guillaume Laforge
 
PDF
Invokedynamic / JSR-292
ytoshima
 
PDF
Rich Model And Layered Architecture in SF2 Application
Kirill Chebunin
 
Testing untestable code - IPC12
Stephan HochdĂśrfer
 
Testing untestable code - PHPBNL11
Stephan HochdĂśrfer
 
Building DSLs with Xtext - Eclipse Modeling Day 2009
Heiko Behrens
 
Interactive Java Support to your tool -- The JShell API and Architecture
JavaDayUA
 
JShell: An Interactive Shell for the Java Platform
JavaDayUA
 
Diving into HHVM Extensions (PHPNW Conference 2015)
James Titcumb
 
How to build customizable multitenant web applications - PHPBNL11
Stephan HochdĂśrfer
 
Secure Programming
alpha0
 
Symfony2 Service Container: Inject me, my friend
Kirill Chebunin
 
JavaOne 2014 - CON2013 - Code Generation in the Java Compiler: Annotation Pro...
Jorge Hidalgo
 
Apigility reloaded
Ralf Eggert
 
Irving iOS Jumpstart Meetup - Objective-C Session 1b
irving-ios-jumpstart
 
CFEngine 3
Brian Repko
 
The Art of Metaprogramming in Java
Abdelmonaim Remani
 
Review unknown code with static analysis - bredaphp
Damien Seguy
 
Quick Intro To JRuby
Frederic Jean
 
Groovy DSLs, from Beginner to Expert - Guillaume Laforge and Paul King - Spri...
Guillaume Laforge
 
Invokedynamic / JSR-292
ytoshima
 
Rich Model And Layered Architecture in SF2 Application
Kirill Chebunin
 
Ad

Viewers also liked (17)

PPT
Nuevas TecnologĂ­as
Oscar Corrales
 
ODT
Recurso 4
Sabinamaria
 
PDF
SBResume1
Sandler Bryson
 
DOCX
Informaciòn legal y jurÏdica
jbyasoc
 
PPTX
Sexuality - Final Poster
Amanda Shea
 
PDF
Group 4 Contemp Project
Yunji Kim
 
PPTX
El mono bondadoso
UPCI
 
PDF
Calif 2°e 10 07 15 i
bonitalosiramzepol
 
PPT
IMPERIAL PALACE WATERPARK RESORT & SPA IN MACTAN
Daisy Mendez
 
DOCX
fatwa tentang orang awam syi'ah
R&R Darulkautsar
 
PDF
Secrets Of Successful Property Managers
SLT Properties, LLC
 
PDF
front page resume
Alan Redcay
 
PDF
Certificate of Organizer
sumroze Rafeeq
 
PPTX
PHP and database functionality
Sayed Ahmed
 
DOCX
Reality Theory Case Study
Cristina De Robles
 
PPTX
PREPAREDNESS OF BICOL COLLEGE IN THE ACCREDITATION OF BSHM PROGRAM BY THE PAC...
Maria Luisa Gonzales
 
PPTX
Intelligent Security, Compliance and Privacy in Office 365
Miguel Isidoro
 
Nuevas TecnologĂ­as
Oscar Corrales
 
Recurso 4
Sabinamaria
 
SBResume1
Sandler Bryson
 
Informaciòn legal y jurÏdica
jbyasoc
 
Sexuality - Final Poster
Amanda Shea
 
Group 4 Contemp Project
Yunji Kim
 
El mono bondadoso
UPCI
 
Calif 2°e 10 07 15 i
bonitalosiramzepol
 
IMPERIAL PALACE WATERPARK RESORT & SPA IN MACTAN
Daisy Mendez
 
fatwa tentang orang awam syi'ah
R&R Darulkautsar
 
Secrets Of Successful Property Managers
SLT Properties, LLC
 
front page resume
Alan Redcay
 
Certificate of Organizer
sumroze Rafeeq
 
PHP and database functionality
Sayed Ahmed
 
Reality Theory Case Study
Cristina De Robles
 
PREPAREDNESS OF BICOL COLLEGE IN THE ACCREDITATION OF BSHM PROGRAM BY THE PAC...
Maria Luisa Gonzales
 
Intelligent Security, Compliance and Privacy in Office 365
Miguel Isidoro
 
Ad

Similar to Zend Framework 2 Patterns (20)

PDF
ZFConf 2012: Zend Framework 2, a quick start (Enrico Zimuel)
ZFConf Conference
 
PDF
Zend Framework 2 Components
Shawn Stratton
 
PDF
PHP traits, treat or threat?
Nick Belhomme
 
DOCX
Zend framework 2.0
shrutisgupta
 
ODP
Zend\EventManager, Zend\Serializer and Zend\Cache
Marc
 
PDF
Zend Framework 2, What's new, Confoo 2011
Bachkoutou Toutou
 
PPTX
Zf2 phpquebec
mkherlakian
 
KEY
Extending ZF & Extending With ZF
Ralph Schindler
 
KEY
Zend framework: Getting to grips (ZF1)
Ryan Mauger
 
PDF
Using PHP 5.3 Namespaces for Fame and Fortune
Zend by Rogue Wave Software
 
PDF
ZF2 Modular Architecture - Taking advantage of it
Steve Maraspin
 
KEY
Webinar: Zend framework Getting to grips (ZF1)
Ryan Mauger
 
PPTX
Zend server 6 using zf2, 2013 webinar
Yonni Mendes
 
KEY
Zend_Tool: Practical use and Extending
ZendCon
 
PDF
Deprecated: Foundations of Zend Framework 2
Adam Culp
 
PDF
Disregard Inputs, Acquire Zend_Form
Daniel Cousineau
 
PPTX
Get Started with Zend Framework 2
Mindfire Solutions
 
PPTX
Zend Framework Workshop
10n Software, LLC
 
KEY
Zend Code in ZF 2.0
Ralph Schindler
 
KEY
Extending Zend_Tool
Ralph Schindler
 
ZFConf 2012: Zend Framework 2, a quick start (Enrico Zimuel)
ZFConf Conference
 
Zend Framework 2 Components
Shawn Stratton
 
PHP traits, treat or threat?
Nick Belhomme
 
Zend framework 2.0
shrutisgupta
 
Zend\EventManager, Zend\Serializer and Zend\Cache
Marc
 
Zend Framework 2, What's new, Confoo 2011
Bachkoutou Toutou
 
Zf2 phpquebec
mkherlakian
 
Extending ZF & Extending With ZF
Ralph Schindler
 
Zend framework: Getting to grips (ZF1)
Ryan Mauger
 
Using PHP 5.3 Namespaces for Fame and Fortune
Zend by Rogue Wave Software
 
ZF2 Modular Architecture - Taking advantage of it
Steve Maraspin
 
Webinar: Zend framework Getting to grips (ZF1)
Ryan Mauger
 
Zend server 6 using zf2, 2013 webinar
Yonni Mendes
 
Zend_Tool: Practical use and Extending
ZendCon
 
Deprecated: Foundations of Zend Framework 2
Adam Culp
 
Disregard Inputs, Acquire Zend_Form
Daniel Cousineau
 
Get Started with Zend Framework 2
Mindfire Solutions
 
Zend Framework Workshop
10n Software, LLC
 
Zend Code in ZF 2.0
Ralph Schindler
 
Extending Zend_Tool
Ralph Schindler
 

More from Zend by Rogue Wave Software (20)

PDF
Develop microservices in php
Zend by Rogue Wave Software
 
PPTX
Speed and security for your PHP application
Zend by Rogue Wave Software
 
PPTX
Building and managing applications fast for IBM i
Zend by Rogue Wave Software
 
PDF
Building web APIs in PHP with Zend Expressive
Zend by Rogue Wave Software
 
PPTX
To PHP 7 and beyond
Zend by Rogue Wave Software
 
PDF
Speed up web APIs with Expressive and Swoole (PHP Day 2018)
Zend by Rogue Wave Software
 
PDF
The Sodium crypto library of PHP 7.2 (PHP Day 2018)
Zend by Rogue Wave Software
 
PDF
Develop web APIs in PHP using middleware with Expressive (Code Europe)
Zend by Rogue Wave Software
 
PDF
Middleware web APIs in PHP 7.x
Zend by Rogue Wave Software
 
PPTX
Ongoing management of your PHP 7 application
Zend by Rogue Wave Software
 
PDF
Developing web APIs using middleware in PHP 7
Zend by Rogue Wave Software
 
PDF
The Docker development template for PHP
Zend by Rogue Wave Software
 
PDF
The most exciting features of PHP 7.1
Zend by Rogue Wave Software
 
PPTX
Unit testing for project managers
Zend by Rogue Wave Software
 
PDF
The new features of PHP 7
Zend by Rogue Wave Software
 
PPTX
Deploying PHP apps on the cloud
Zend by Rogue Wave Software
 
PPTX
Data is dead. Long live data!
Zend by Rogue Wave Software
 
PPTX
Optimizing performance
Zend by Rogue Wave Software
 
PPTX
Resolving problems & high availability
Zend by Rogue Wave Software
 
PPTX
Developing apps faster
Zend by Rogue Wave Software
 
Develop microservices in php
Zend by Rogue Wave Software
 
Speed and security for your PHP application
Zend by Rogue Wave Software
 
Building and managing applications fast for IBM i
Zend by Rogue Wave Software
 
Building web APIs in PHP with Zend Expressive
Zend by Rogue Wave Software
 
To PHP 7 and beyond
Zend by Rogue Wave Software
 
Speed up web APIs with Expressive and Swoole (PHP Day 2018)
Zend by Rogue Wave Software
 
The Sodium crypto library of PHP 7.2 (PHP Day 2018)
Zend by Rogue Wave Software
 
Develop web APIs in PHP using middleware with Expressive (Code Europe)
Zend by Rogue Wave Software
 
Middleware web APIs in PHP 7.x
Zend by Rogue Wave Software
 
Ongoing management of your PHP 7 application
Zend by Rogue Wave Software
 
Developing web APIs using middleware in PHP 7
Zend by Rogue Wave Software
 
The Docker development template for PHP
Zend by Rogue Wave Software
 
The most exciting features of PHP 7.1
Zend by Rogue Wave Software
 
Unit testing for project managers
Zend by Rogue Wave Software
 
The new features of PHP 7
Zend by Rogue Wave Software
 
Deploying PHP apps on the cloud
Zend by Rogue Wave Software
 
Data is dead. Long live data!
Zend by Rogue Wave Software
 
Optimizing performance
Zend by Rogue Wave Software
 
Resolving problems & high availability
Zend by Rogue Wave Software
 
Developing apps faster
Zend by Rogue Wave Software
 

Recently uploaded (20)

PDF
How Open Source Changed My Career by abdelrahman ismail
a0m0rajab1
 
PDF
Event Presentation Google Cloud Next Extended 2025
minhtrietgect
 
PDF
REPORT: Heating appliances market in Poland 2024
SPIUG
 
PDF
Data_Analytics_vs_Data_Science_vs_BI_by_CA_Suvidha_Chaplot.pdf
CA Suvidha Chaplot
 
PDF
The Future of Mobile Is Context-Aware—Are You Ready?
iProgrammer Solutions Private Limited
 
PDF
Trying to figure out MCP by actually building an app from scratch with open s...
Julien SIMON
 
PDF
MASTERDECK GRAPHSUMMIT SYDNEY (Public).pdf
Neo4j
 
PDF
Cloud-Migration-Best-Practices-A-Practical-Guide-to-AWS-Azure-and-Google-Clou...
Artjoker Software Development Company
 
PPTX
Applied-Statistics-Mastering-Data-Driven-Decisions.pptx
parmaryashparmaryash
 
PDF
Google I/O Extended 2025 Baku - all ppts
HusseinMalikMammadli
 
PPTX
AI and Robotics for Human Well-being.pptx
JAYMIN SUTHAR
 
PDF
Economic Impact of Data Centres to the Malaysian Economy
flintglobalapac
 
PDF
Software Development Methodologies in 2025
KodekX
 
PPTX
AI in Daily Life: How Artificial Intelligence Helps Us Every Day
vanshrpatil7
 
PDF
Structs to JSON: How Go Powers REST APIs
Emily Achieng
 
PDF
OFFOFFBOX™ – A New Era for African Film | Startup Presentation
ambaicciwalkerbrian
 
PDF
CIFDAQ's Market Wrap : Bears Back in Control?
CIFDAQ
 
PDF
Brief History of Internet - Early Days of Internet
sutharharshit158
 
PDF
SparkLabs Primer on Artificial Intelligence 2025
SparkLabs Group
 
PDF
BLW VOCATIONAL TRAINING SUMMER INTERNSHIP REPORT
codernjn73
 
How Open Source Changed My Career by abdelrahman ismail
a0m0rajab1
 
Event Presentation Google Cloud Next Extended 2025
minhtrietgect
 
REPORT: Heating appliances market in Poland 2024
SPIUG
 
Data_Analytics_vs_Data_Science_vs_BI_by_CA_Suvidha_Chaplot.pdf
CA Suvidha Chaplot
 
The Future of Mobile Is Context-Aware—Are You Ready?
iProgrammer Solutions Private Limited
 
Trying to figure out MCP by actually building an app from scratch with open s...
Julien SIMON
 
MASTERDECK GRAPHSUMMIT SYDNEY (Public).pdf
Neo4j
 
Cloud-Migration-Best-Practices-A-Practical-Guide-to-AWS-Azure-and-Google-Clou...
Artjoker Software Development Company
 
Applied-Statistics-Mastering-Data-Driven-Decisions.pptx
parmaryashparmaryash
 
Google I/O Extended 2025 Baku - all ppts
HusseinMalikMammadli
 
AI and Robotics for Human Well-being.pptx
JAYMIN SUTHAR
 
Economic Impact of Data Centres to the Malaysian Economy
flintglobalapac
 
Software Development Methodologies in 2025
KodekX
 
AI in Daily Life: How Artificial Intelligence Helps Us Every Day
vanshrpatil7
 
Structs to JSON: How Go Powers REST APIs
Emily Achieng
 
OFFOFFBOX™ – A New Era for African Film | Startup Presentation
ambaicciwalkerbrian
 
CIFDAQ's Market Wrap : Bears Back in Control?
CIFDAQ
 
Brief History of Internet - Early Days of Internet
sutharharshit158
 
SparkLabs Primer on Artificial Intelligence 2025
SparkLabs Group
 
BLW VOCATIONAL TRAINING SUMMER INTERNSHIP REPORT
codernjn73
 

Zend Framework 2 Patterns

  • 1. Zend Framework 2 Patterns Matthew Weier O'Phinney Project Lead, Zend Framework To watch the webinar please go to: http://www.zend.com/en/webinar/Framework/70170000000bX3J- webinar-zf-2-patterns-20110330.flv Š All rights reserved. Zend Technologies, Inc.
  • 2. Roadmap for today ● Namespaces and Autoloading ● Exceptions ● Configuration ● Plugin systems ● Dispatching ● Inversion of Control Š All rights reserved. Zend Technologies, Inc.
  • 3. Format ● List The Problems ● Detail the ZF2 Approach Š All rights reserved. Zend Technologies, Inc.
  • 4. But first, some history Š All rights reserved. Zend Technologies, Inc.
  • 5. Zend Framework 1.X ● 1.0 Released in July 2007 ● Largely evolutionary development ▶ Inconsistencies in APIs, particularly surrounding plugins and configuration ▶ Best practices have been discovered over time ▶ Many key features for modern applications have been added in recent versions Š All rights reserved. Zend Technologies, Inc.
  • 6. Zend Framework 2.0 ● First new major release ▶ Allowing us to break backwards compatibility ● Focus is on: ▶ Consistency ▶ Performance ▶ Documentation ▶ User productivity Š All rights reserved. Zend Technologies, Inc.
  • 7. Namespaces and Autoloading 7 Š All rights reserved. Zend Technologies, Inc.
  • 8. The Problems ● Lengthy class names ▶ Difficult to refactor ▶ Difficult to retain semantics with shorter names ● Performance issues ▶ Many classes are used JIT, and shouldn't be loaded until needed ● Missing require_once statements lead to errors Š All rights reserved. Zend Technologies, Inc.
  • 9. ZF2 Approach: Namespaces ● Formalize the prefixes used in ZF1 ▶ Namespace separator correlates to directory separator ● Help identify dependencies (imports) ▶ Allows refactoring using different implementations easier ▶ Makes packaging easier Š All rights reserved. Zend Technologies, Inc.
  • 10. Namespaces namespace ZendEventManager; use ZendStdlibCallbackHandler; class EventManager implements EventCollection { /* ... */ } Š All rights reserved. Zend Technologies, Inc.
  • 11. Namespaces ● Interfaces as namespaces ▶ Interface names are adjectives or nouns ▶ Concrete implementations in a sub-namespace named after the interface ▶ Contract-Oriented paradigm Š All rights reserved. Zend Technologies, Inc.
  • 12. Interfaces as Namespaces Zend/Session namespace ZendSession; |-- Storage.php interface Storage `-- Storage { |-- /* ... */ ArrayStorage.php } `-- SessionStorage.php namespace ZendSessionStorage; use ArrayObject, ZendSessionStorage, ZendSessionException; class ArrayStorage extends ArrayObject implements Storage { /* ... */ } Š All rights reserved. Zend Technologies, Inc.
  • 13. ZF2 Approach: Autoloading ● No more require_once calls! ● Multiple approaches ▶ ZF1-style include_path autoloader ▶ Per-namespace/prefix autoloading ▶ Class-map autoloading Š All rights reserved. Zend Technologies, Inc.
  • 14. ZF1-Style Autoloading require_once 'Zend/Loader/StandardAutoloader.php'; $loader = new ZendLoaderStandardAutoloader(array( 'fallback_autoloader' => true, )); $loader->register(); Š All rights reserved. Zend Technologies, Inc.
  • 15. ZF2 NS/Prefix Autoloading require_once 'Zend/Loader/StandardAutoloader.php'; $loader = new ZendLoaderStandardAutoloader(); $loader->registerNamespace( 'My', __DIR__ . '/../library/My') ->registerPrefix( 'Phly_', __DIR__ . '/../library/Phly'); $loader->register(); Š All rights reserved. Zend Technologies, Inc.
  • 16. ZF2 Class-Map Autoloading return array( 'MyFooBar' => __DIR__ . '/Foo/Bar.php', ); require_once 'Zend/Loader/ClassMapAutoloader.php'; $loader = new ZendLoaderClassMapAutoloader(); $loader->registerAutoloadMap( __DIR__ . '/../library/.classmap.php'); $loader->register(); Š All rights reserved. Zend Technologies, Inc.
  • 17. Exceptions 17 Š All rights reserved. Zend Technologies, Inc.
  • 18. The Problems ● All exceptions derived from a common class ● No ability to extend more semantic exception types offered in SPL Š All rights reserved. Zend Technologies, Inc.
  • 19. ZF2 Approach ● Eliminated Zend_Exception ● Each component defines a marker Exception interface ● Additional exception types are created in an Exception subnamespace ▶ These extend SPL exceptions, and implement the component-level exception interface Š All rights reserved. Zend Technologies, Inc.
  • 20. What the solution provides ● Catch specific exception types ● Catch SPL exception types ● Catch any component-level exception ● Catch based on global exception type Š All rights reserved. Zend Technologies, Inc.
  • 21. Exceptions in use Zend/EventManager namespace |-- Exception.php ZendEventManager; `-- Exception `-- InvalidArgument- interface Exception {} Exception.php namespace ZendEventManagerException; use ZendEventManagerException; class InvalidArgumentException extends InvalidArgumentException implements Exception {} Š All rights reserved. Zend Technologies, Inc.
  • 22. Exceptions in use namespace ZendEventManagerException; use ZendEventManagerException; try { $events->trigger('foo.bar', $object); } catch (InvalidArgumentException $e) { } catch (Exception $e) { } catch (InvalidArgumentException $e) { } catch (Exception $e) { } Š All rights reserved. Zend Technologies, Inc.
  • 23. Configuration 23 Š All rights reserved. Zend Technologies, Inc.
  • 24. The Problems ● Case-SeNSItiviTy ● Varying APIs ▶ setOptions() ▶ setConfig() ▶ __construct() ▶ explicit setters Š All rights reserved. Zend Technologies, Inc.
  • 25. ZF2 Approach ● Option names will be lowercase_underscore_separated_word s ● Standard solution across components ▶ setOptions() style, proxying to setters, or ▶ per-component configuration objects Š All rights reserved. Zend Technologies, Inc.
  • 26. setOptions() style class Foo { public function setOptions($options) { if (!is_array($options) && !($options instanceof Traversable) ) { throw new InvalidArgumentException(); } foreach ($options as $key => $value) { $method = normalize($key); if (method_exists($this, $method)) { $this->$method($value); } } Š All rights reserved. Zend Technologies, Inc.
  • 27. Options object style class FooOptions extends Options { public $bar; public $baz; public function __construct($options = null) { if (!is_array($options) && !($options instanceof Traversable) ) { throw new InvalidArgumentException(); } foreach ($options as $key => $value) { $prop = normalize($key); $this->$prop = $value; } } } Š All rights reserved. Zend Technologies, Inc.
  • 28. Options object style class Foo { public function __construct(Options $options = null) { if (null !== $options) { foreach ($options as $key => $value) { $this->$key = $value; } } } } Š All rights reserved. Zend Technologies, Inc.
  • 29. Plugin Architectures 29 Š All rights reserved. Zend Technologies, Inc.
  • 30. Terminology ● For our purposes, a “plugin” is any class that is determined at runtime. ▶ Action and view helpers ▶ Adapters ▶ Filters and validators Š All rights reserved. Zend Technologies, Inc.
  • 31. The Problems ● Varying approaches to dynamically discovering plugin classes ▶ Prefix-path stacks (most common) ▶ Paths relative to the calling class ▶ Setters to indicate classes ● Most common approach is terrible ▶ Bad performance ▶ Hard to debug ▶ No caching of discovered plugins Š All rights reserved. Zend Technologies, Inc.
  • 32. ZF2 Approach: Plugin Broker ● Separate Plugin Location interface ▶ Allows varying implementation of plugin lookup ● Separate Plugin Broker interface ▶ Composes a Plugin Locator Š All rights reserved. Zend Technologies, Inc.
  • 33. ZF2 Approach: Plugin Broker ● Standard implementation across components ▶ Subclassing standard implementation allows type- hinting, caching discovered plugins, etc. ▶ while allowing you to substitute your own implementations ● Class-map location by default ● 2-5x performance gains! ● Easier to debug Š All rights reserved. Zend Technologies, Inc.
  • 34. Plugin class location namespace ZendLoader; interface ShortNameLocater { public function isLoaded($name); public function getClassName($name); public function load($name); } namespace ZendView; use ZendLoaderPluginClassLoader; class HelperLoader extends PluginClassLoader { protected $plugins = array( 'action' => 'ZendViewHelperAction', 'baseurl' => 'ZendViewHelperBaseUrl', /* ... */ ); } Š All rights reserved. Zend Technologies, Inc.
  • 35. Plugin broker namespace ZendLoader; interface Broker { public function load($plugin, array $options = null); public function getPlugins(); public function isLoaded($name); public function register($name, $plugin); public function unregister($name); public function setClassLoader( ShortNameLocater $loader); public function getClassLoader(); } Š All rights reserved. Zend Technologies, Inc.
  • 36. Plugin broker class HelperBroker extends PluginBroker { protected $defaultClassLoader = 'ZendViewHelperLoader'; protected $view; public function setView(Renderer $view) {} public function getView() {} public function load($plugin, array $options = null) { $helper = parent::load($plugin, $options); if (null !== ($view = $this->getView())) { $helper->setView($view); } return $helper; } protected function validatePlugin($plugin) { if (!$plugin instanceof Helper) { throw new InvalidHelperException(); } return true; } } Š All rights reserved. Zend Technologies, Inc.
  • 37. ZF2 Approach: Events ● Trigger events at interesting points in your application ▶ Use as basic subject/observer pattern ▶ Or as intercepting filters ▶ Or a full-fledged Aspect-Oriented Programming system Š All rights reserved. Zend Technologies, Inc.
  • 38. ZF2 Approach: Events ● Compose an EventManager to a class ● Attach handlers to events ▶ Handlers receive an Event ● event name ● target (calling) object ● parameters passed ▶ Handlers can also be attached statically Š All rights reserved. Zend Technologies, Inc.
  • 39. Triggering an event public function doSomething( $with, $params = array() ) { $this->events()->trigger( __FUNCTION__, compact('with', 'params') ); /* ... */ } Š All rights reserved. Zend Technologies, Inc.
  • 40. Listening to an event use ZendEventManagerEventManager as Events; $events = new Events(); $events->attach('doSomething', function($e) use ($log) { $event = $e->getName(); $target = get_class($e->getTarget()); $params = json_encode($e->getParams()); $message = sprintf('%s (%s): %s', $event, $target, $params); $log->info($message); }); Š All rights reserved. Zend Technologies, Inc.
  • 41. Attaching statically to an event use ZendEventManagerStaticEventManager as AllEvents; $events = AllEvents::getInstance(); // Specify the class composing an EventManager // as first arg $events->attach('Foo', 'doSomething', function($e) {}); Š All rights reserved. Zend Technologies, Inc.
  • 42. Dispatchers 42 Š All rights reserved. Zend Technologies, Inc.
  • 43. The Problems ● Not terribly performant ● Hard to customize ● Hard to inject controllers with dependencies ● Forces pre-initialization of resources if you want them configured by Zend_Application Š All rights reserved. Zend Technologies, Inc.
  • 44. ZF2 Approach ● Discrete Request, Response, and Dispatchable interfaces ▶ Request encompasses request environment ▶ Response aggregates response returned ▶ Dispatchable objects formalize a Strategy pattern Š All rights reserved. Zend Technologies, Inc.
  • 45. ZF2 Approach ● Anything Dispatchable can be attached to the MVC ▶ Server components (XML-RPC, JSON-RPC, etc.) ● Allows building your own MVC approach ▶ Do you want action methods to receive explicit arguments? ▶ Do you want to select a different action method based on request headers? Š All rights reserved. Zend Technologies, Inc.
  • 46. MVC Interfaces interface Message { public function setMetadata($spec, $value = null); public function getMetadata($key = null); public function setContent($content); public function getContent(); } interface Request interface Response extends Message extends Message { { public function public function __toString(); __toString(); public function public function fromString($string); fromString($string); } public function send(); } Š All rights reserved. Zend Technologies, Inc.
  • 47. MVC Interfaces interface Dispatchable { public function dispatch( Request $request, Response $response = null); } Š All rights reserved. Zend Technologies, Inc.
  • 48. Inversion of Control 48 Š All rights reserved. Zend Technologies, Inc.
  • 49. The Problems ● How do objects get dependencies? ▶ In particular, how do Controllers get dependencies? Š All rights reserved. Zend Technologies, Inc.
  • 50. ZF2 Approach ● Service Locator ▶ Basic pattern: ● set($name, $service) ● get($name) ▶ Formalization of application services (mailer, logger, profiler, etc.) ▶ Good interface for typehinting Š All rights reserved. Zend Technologies, Inc.
  • 51. Service Locator use ZendDiServiceLocator, ZendEventManagerEventManager; 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.
  • 52. ZF2 Approach ● Dependency Injection Container ▶ Scaffolding for constructor and setter injection ▶ Use programmatically, or from configuration ▶ Typically used to seed a service locator Š All rights reserved. Zend Technologies, Inc.
  • 53. Dependency Injection $db = new Definition('MyDbAdapterSqlite'); $db->setParam('name', __DIR__ . '/../data/db/users.db'); $mapper = new Definition('MyMapperDb'); $mapper->addMethodCall( 'setAdapter', array(new Reference('db'))); $service = new Definition('MyResourceUsers'); $service->setParam('mapper', new Reference('mapper')); $di = new DependencyInjector; $di->setDefinitions(array( 'db' => $db, 'mapper' => $mapper, 'users' => $service, )); Š All rights reserved. Zend Technologies, Inc.
  • 54. Controllers as services ● Solves issue of controller dependencies ● Each request only instantiates what's needed for that request ● Better testability of controllers Š All rights reserved. Zend Technologies, Inc.
  • 55. Controllers as services $userController = new Definition('SiteControllerUser'); $userController->setParam( 'service', new Reference('users')); $di->setDefinition($userController, 'controller- user'); // Inside dispatcher: $controller = $di->get($controllerName); $result = $controller->dispatch($request, $response); Š All rights reserved. Zend Technologies, Inc.
  • 56. More to come! 56 Š All rights reserved. Zend Technologies, Inc.
  • 57. Zend Framework 2.0 ● Schedule: ▶ MVC milestone by end of May ▶ Preview Release following MVC milestone ▶ Beta release during summer ▶ Stable by end-of-year Š All rights reserved. Zend Technologies, Inc.
  • 58. Resources 58 Š All rights reserved. Zend Technologies, Inc.
  • 59. ● ZF2 Wiki: http://bit.ly/zf2wiki ● ZF2 Git information: http://bit.ly/zf2gitguide ● ZF2 MVC sandbox: git://git.mwop.net/zf2sandbox.git ● ZF2 DI prototype: http://bit.ly/gBBnDS Š All rights reserved. Zend Technologies, Inc.
  • 60. Thank you! ● http://framework.zend.com/ ● http://twitter.com/weierophinney 60 Š All rights reserved. Zend Technologies, Inc.
  • 61. Webinar To watch the webinar please go to: http://www.zend.com/en/webinar/Framework/ 70170000000bX3J-webinar-zf-2-patterns- 20110330.flv Or http://bit.ly/qXeCWI (short registration required) Insert->Header & Footer Š All rights reserved. Zend Technologies, Inc. 61