SlideShare una empresa de Scribd logo
1 de 123
A Framework for People
Who Hate Frameworks.
A movement in 3 parts

• Frameworks suck
• Everything you know is wrong
• Lithium tries to suck less
The first part.
Let’s get one thing out
of the way:
Lithium sucks.
But that’s okay.
Because your
framework sucks, too.
And yes, I mean:
Why?
(Besides the obvious attempt at being provocative)
Frameworks Suck

• Code you will never use.
• Complexity overhead.
• You didn’t write it.
Also,

Martin Fowler.
His name is the
biggest, so it’s his
      fault.
We’re not saying design patterns are bad.
Quite the opposite.
Lithium implements many design patterns.
The Problem™
Some patterns only treat the symptoms,
instead of the cause.
Some examples:
Object dependencies.
“The principle of separating configuration from use.”
Sucks.
function initialize(&$controller, $settings = array()) {
    /* ...[snip]... */

    $prefixes = Router::prefixes();
    if (!empty($prefixes)) {
        foreach ($prefixes as $prefix) {
            /* ...[do something nasty to the global state]... */
        }
    }
    if (Configure::read() > 0) {
        App::import('Debugger');
        Debugger::checkSecurityKeys();
    }
}




                                  Sucks hard.
Configuration.
Everyone does it differently.
Sometimes in the same framework.
Sometimes in the same class.
Sucks
function spam($emails) {

    $this->Email->replyTo = 'nigerian.prince@example.com';
    $this->Email->from = 'Desmond Etete <nigerian.prince@example.com>';
    $this->Email->template = 'mo_monies';
    $this->Email->sendAs = 'annoying_html';

    foreach ($emails as $email) {
        $this->Email->to = $email['address'];
        $this->Email->subject = "Good to you news I have {$email['name']}";
        $this->Email->send();
    }
}
Dependency injection.
A good idea!
... or is it?
[variables changed to protect the innocent.]
                [... not really. It’s Symfony.]
Show that object who’s boss.
class User {
    function __construct($storage) {
        $this->storage = $storage;
    }
}

$storage = new SessionStorage('SESSION_ID');
$user = new User($storage);
Of course, we want this to abstract this.

Frameworks adore abstractions.
DI Container to the rescue!
class Container {
    static protected $shared = array();
    // ...

    public function getMailer() {
        if (isset(self::$shared['mailer'])) {
            return self::$shared['mailer'];
        }

        $class = $this->parameters['mailer.class'];
        $mailer = new $class();
        $mailer->setDefaultTransport($this->getMailTransport());

        return self::$shared['mailer'] = $mailer;
    }
}
But now you want an abstraction to manage
the DI container.


Duh.
So you create a “Service Container”.
class Container extends sfServiceContainer {
    static protected $shared = array();

    protected function getMailTransportService() {
        return new Zend_Mail_Transport_Smtp('smtp.gmail.com', array(
          'auth'     => 'login',
          'username' => $this['mailer.username'],
          'password' => $this['mailer.password'],
          'ssl'      => 'ssl',
          'port'     => 465,
        ));
    }
}
Of course, we now want to abstract the
crap out of the Service Container.


Double duh.
So lets use a Builder to configure the
Services.
Yeah!
require_once '/PATH/TO/sfServiceContainerAutoloader.php';
sfServiceContainerAutoloader::register();

$sc = new sfServiceContainerBuilder();

$sc->
    register('mail.transport', 'Zend_Mail_Transport_Smtp')->
    addArgument('smtp.gmail.com')->
    addArgument(array(
         'auth'     => 'login',
         'username' => '%mailer.username%',
         'password' => '%mailer.password%',
         'ssl'      => 'ssl',
         'port'     => 465,
    ))->
    setShared(false)
;

$sc->
    register('mailer', '%mailer.class%')->
    addMethodCall('setDefaultTransport', array(new sfServiceReference
('mail.transport')))
;
And for good measure, have our configurations
for Service Containers in XML files.
So....
We have Dependency Injection.
Managed by a Service Container.
Parametrized with XML data.
And the whole thing configured by a Builder.

...to fix one problem.
Anyone see what’s wrong here?
The second part.
Everything
you know
is wrong.
The sun does not
revolve around OOP
                                           ...nevertheless,
                                               it moves.




        Galileo facing the Roman Inquistion
                     - Cristiano Banti (1857)
Dependency injection.
Dependency
Injection  =
class User {

    public function create() {
        $logger = new Logger();
        $logger->write('Creating a new user...');

        $this->_doSomeInitialization();
        $this->_databaseConnection->doATransaction($this)->create();

        $logger->write('Finished creating user');
    }
}

$user = new User();
$user->create();
class User {

    public $logger;

    public function create() {
        $this->logger->write('Creating a new user...');

        $this->_doSomeInitialization();
        $this->_databaseConnection->doATransaction($this)->create();

        $this->logger->write('Finished creating user');
    }
}

$user = new User();
$user->logger = new Logger();
$user->create();
Dependency Injection
• Fixes the problem of static dependencies
• Ignores the problem of static relationships
 • Same methods called on injected classes
 • No way to introduce new relationships
• Higher overhead, more boilerplate code
class Service extends lithiumcoreObject {

    protected $_classes = array(
        'request' => 'lithiumnethttpRequest',
        'response' => 'lithiumnethttpResponse',
        'socket'   => 'lithiumnetsocketContext'
    );

    protected function _init() {
        $class = Libraries::locate('socket.util', $this->_classes['socket']);
        $this->_connection = new $class($this->_config);
        // ...
    }

    /* ...[snip]... */

    public function send($method, $path = null, $data = null, array $options = array()) {
        /* ...[snip]... */
        $response = $this->_connection->send($request, array('classes' => $this->_classes));
        // ...
    }
}
Coupling should be in
proportion to domain
relevance.
The problem of

state.
If...
Configure::write('debug', 0);


  is evil,
$this->debug = 0;



  is the
of evil.
class Service {

    protected $_timeout = 30;

    public function send($method, $data = null, array $options = array()) {

        // WTF does this do?
        $this->_prepare();

        $response = $this->_connection->send($request, array(
            'timeout' => $this->_timeout
        ));
        // ...
    }
}
OO doesn’t make you
think (about state).
Design patterns.
ActiveRecord
                        Data Access Object

 Unit of Work
                              Dependency Injection
                  Registry

   Front Controller               MVC

                   Value Object
Data Mapper                         Service Layer
L E
FA
Design patterns
• Each pattern is only useful in a limited
  context

• Layering many design patterns on top of
  each other often indicates poor design
  choices

• Mis-application arises from trying to run
  before you can walk
Tools do not mean...




...you can build a house.
The third part.
Lithium tries to suck less.
Un-broken solutions.
Aspect-Oriented Design
• Separation of concerns
• Domain classes should not know or care about cross-
   cutting concerns

• Examples:
 • Caching
 • Logging
 • Access Control, etc.
Functional Programming

• Only possible when functions are first-class
  citizens

• Referential transparency
• Function purity
Referential transparency is not...


 $this                date()


           $_*
Referential transparency is not...


 $this                date()


           $_*
These Are Not
Design Patterns.
Less Suck
• Draws on years of experience building web
  frameworks

• PHP 5.3+ only
• Doesn’t assume you’re stupid
Ways we suck less:
Consistency.
<?php

namespace applicationbar;

use lithiumutilString;
use lithiumutilCollection;

class Foo extends lithiumcoreObject {

     protected $_classes = array(
         'cache' => 'lithiumstorageCache',
         'logger' => 'lithiumanalysisLogger'
     );

     public function __construct(array $config = array()) {
         // ...
     }

     protected function _init() {
         // ...
     }
}

?>
<?php

namespace applicationbar;

use lithiumutilString;
use lithiumutilCollection;

class Foo extends lithiumcoreObject {

     protected $_classes = array(
         'cache' => 'lithiumstorageCache',
         'logger' => 'lithiumanalysisLogger'
     );

     public function __construct(array $config = array()) {
         // ...
                                                              1
     }

     protected function _init() {
         // ...
     }
}

?>
public function __construct(array $config = array())
<?php
    public function __construct(array $config = array())

namespace applicationbar;
    public function __construct(array $config = array())

use public function __construct(array $config =
    lithiumutilString;                         array())
use lithiumutilCollection;
    public function __construct(array $config =   array())
class Foo extends lithiumcoreObject {
    public function __construct(array $config =   array())
    protected $_classes = array(
    public function'lithiumstorageCache', =
        'cache' => __construct(array $config      array())
        'logger' => 'lithiumanalysisLogger'
    public function __construct(array $config =
    );                                            array())

     public function __construct(array $config = array()) {
         // ...
     }
     public function __construct(array $config = array())

     protected function _init() {
     public function __construct(array $config = array())
         // ...
     }
     public function __construct(array $config = array())
}
     public function __construct(array $config = array())
?>
     public function __construct(array $config = array())
<?php
     <?php
namespace applicationbar;
     class Foo extends lithiumcoreObject {
use lithiumutilString;
use lithiumutilCollection;
          protected function _init() {
class Foo extends lithiumcoreObject {
               $or = $some->highOverHead($operation);
               $or()->otherwise(HARD_TO_TEST)->code();
    protected $_classes = array(
          }
        'cache' => 'lithiumstorageCache',
     } 'logger' => 'lithiumanalysisLogger'
     );

      ?>
     public function __construct(array $config = array()) {
         // ...
     }

     protected function _init() {
         // ...
                                    2
     }
}

?>
<?php
     <?php
namespace applicationbar;
     class Foo extends lithiumcoreObject {
use lithiumutilString;
use lithiumutilCollection;
          protected function _init() {
class Foo extends lithiumcoreObject {
               $or = $some->highOverHead($operation);
               $or()->otherwise(HARD_TO_TEST)->code();
    protected $_classes = array(
          }
        'cache' => 'lithiumstorageCache',
     } 'logger' => 'lithiumanalysisLogger'
     );

      ?>
     public function __construct(array $config = array()) {
         // ...
     }

     protected function _init() {
         // ...
                                    2
     }
}
     $foo = new Foo(array('init' => false));
?>
<?php

namespace applicationbar;   3
use lithiumutilString;
use lithiumutilCollection;
                                    new applicationbarFoo();
                                    // loads app/bar/Foo.php
class Foo extends lithiumcoreObject {

     protected $_classes = array(
         'cache' => 'lithiumstorageCache',
         'logger' => 'lithiumanalysisLogger'
     );

     public function __construct(array $config = array()) {
         // ...
     }

     protected function _init() {
         // ...
     }
}

?>
<?php

namespace applicationbar;



                                    4
use lithiumutilString;
use lithiumutilCollection;

class Foo extends lithiumcoreObject {

     protected $_classes = array(
         'cache' => 'lithiumstorageCache',
         'logger' => 'lithiumanalysisLogger'
     );

     public function __construct(array $config = array()) {
         // ...
     }

     protected function _init() {
         // ...
     }
}

?>
<?php

namespace applicationbar;

use lithiumutilString;
use lithiumutilCollection;

class Foo extends lithiumcoreObject {

     protected $_classes = array(
         'cache' => 'lithiumstorageCache',
         'logger' => 'lithiumanalysisLogger'   5
     );

     public function __construct(array $config = array()) {
         // ...
     }

     protected function _init() {
         // ... = $this->_classes['cache'];
         $cache
     }   $cache::write(__CLASS__, $this->_someGeneratedValue());
}    }
}
?>
?>
<?php

namespace applicationbar;

use lithiumutilString;
use lithiumutilCollection;

class Foo extends lithiumcoreObject {

     protected $_classes = array(
         'cache' => 'lithiumstorageCache',
         'logger' => 'lithiumanalysisLogger'   5
     );

     $foo = new Foo(array('classes' => array(
     public function __construct(array $config = array()) {
          'cache' => 'applicationextensionsCache'
         // ...
     )));
     }

     protected function _init() {
         // ... = $this->_classes['cache'];
         $cache
     }   $cache::write(__CLASS__, $this->_someGeneratedValue());
}    }
}
?>
?>
$options = array()
Keeps parameter lists short
             &
Makes class APIs more extensible
$config = array()
Same idea. But...!
Modifies class / object state.
Adaptable

   Auth

  Cache

  Catalog

Connections

  Logger

  Session
use lithiumsecurityAuth;

Auth::config(array(
    'customer' => array(
        'adapter' => 'Form',
        'model'   => 'Customer',
        'fields' => array('email', 'password')
    )
));
use lithiumstorageCache;

Cache::config(array(
    'local' => array('adapter' => 'Apc'),
    'distributed' => array(
        'adapter' => 'Memcached',
        'servers' => array('127.0.0.1', 11211),
    ),
    'default' => array('adapter' => 'File')
));
use lithiumdataConnections;

Connections::config(array(
    'old' => array(
        'type'      => 'database',
        'adapter' => 'MySql',
        'user'      => 'bobby_tables',
        'password' => '******',
        'database' => 'my_app'
    ),
    'new' => array(
        'type'      => 'http',
        'adapter' => 'CouchDb',
        'database' => 'my_app'
    )
));
use lithiumstorageSession;

Session::config(array(
    'cookie' => array(
        'adapter' => 'Cookie',
        'expire' => '+2 days'
    ),
    'default' => array('adapter' => 'Php')
));
Also fun:
use lithiumstorageSession;

Session::config(array(
    'default' => array(
        'adapter' => 'MyCustomAdapter',
        'expires' => '+2 days',
        'custom' => 'Whatevah!'
    )
));



 public function __construct(array $config = array())
Multiple environments?
use lithiumstorageCache;

Cache::config(array(
    'default' => array(
        'development' => array(
            'adapter' => 'Apc'
        ),
        'production' => array(
            'adapter' => 'Memcached',
            'servers' => array('127.0.0.1', 11211)
        )
    )
));
Works identically for all adapters.
If you remember nothing
else about configuration
state...
Immutability.
Set it and forget it.
Speed.
Zoom!

• Use native extensions (PECL) whenever
  possible.

• Don’t like a class? Change it. At runtime.
• Profiled at every step of the way.
Flexibility.
Lithium is the most
flexible framework.
Most class dependencies
are dynamic.
class Service extends lithiumcoreObject {

    protected $_classes = array(
        'request' => 'lithiumnethttpRequest',
        'response' => 'lithiumnethttpResponse',
        'socket'   => 'lithiumnetsocketContext'
    );
}


$service = new Service(array('classes' => array(
    'socket' => 'mycustomSocket'
)));
The Filter System:
Aspect-Oriented Design
for PHP.
Example: Caching & Logging

    Caching


       Logging


              Post::find()
Example: Caching & Logging

    Caching


       Logging


              Post::find()
Example: Caching & Logging

    Caching


       Logging


              Post::find()
use lithiumanalysisLogger;

Post::applyFilter('find', function($self, $params, $chain) {
    // Generate the log message
    $conditions = $params['options']['conditions'];
    $message = 'Post query with constraint ' . var_export($conditions, true);

      Logger::write('info', $message);
      return $chain->next($self, $params, $chain);
});
Post                                                                                   Logger
       use lithiumanalysisLogger;

       Post::applyFilter('find', function($self, $params, $chain) {
           // Generate the log message
           $conditions = $params['options']['conditions'];
           $message = 'Post query with constraint ' . var_export($conditions, true);

             Logger::write('info', $message);
             return $chain->next($self, $params, $chain);
       });
What about Observer?

• Dependent on a centralized publish/
  subscribe system

• Extra layer of abstraction
• Fewer possibilities
What about Observer?


• Filters are self-contained and attach
  directly to objects

• Direct and intuitive
Features: Everything is an adapter.
G11n (Globalization)
• CLDR
• Gettext
• PHP arrays
• Code
• Pecl/intl support on the way
Databases

• 1st-class support for document-oriented
  databases

• MongoDB & CouchDB: production ready
• Relational databases coming soon
<?php

$post = Post::create(array(
    'title' => 'Forget the words and sing along',
    'body' => 'Everything you know is wrong'
));
$post->save();

$post = Post::find($id);

?>

<h2><?=$post->title; ?></h2>
<p><?=$post->body; ?></p>
This works on...

• MongoDB
• CouchDB
• MySQL
• SQLite (almost)
Databases

• Adapter based. Plugin aware.
• Will ship with MySQL, SQLite, PostgreSQL &
  SQL Server.

• Query API
Integration with other
frameworks

• Easily load & use libraries from other
  frameworks:

  • Zend Framework, Solar, Symfony
/* add the trunk */
Libraries::add("Zend", array(
    "prefix" => "Zend_",
    "includePath" => '/htdocs/libraries/Zend/trunk/library',
    "bootstrap" => "Loader/Autoloader.php",
    "loader" => array("Zend_Loader_Autoloader", "autoload"),
    "transform" => function($class) { return str_replace("_", "/", $class) . ".php"; }
));
// Note that 'path' can be dropped if trunk/library/Zend is placed
// directly into your /libraries directory.

/* add the incubator */
Libraries::add("Zend_Incubator", array(
    "prefix" => "Zend_",
    "includePath" => '/htdocs/libraries/Zend/incubator/library',
    "transform" => function($class) { return str_replace("_", "/", $class) . ".php"; }
));
namespace appcontrollers;

use Zend_Mail_Storage_Pop3;

class EmailController extends lithiumactionController {

    public function index() {
        $mail = new Zend_Mail_Storage_Pop3(array(
            'host' => 'localhost', 'user' => 'test', 'password' => 'test'
        ));
        return compact('mail');
    }

}
This has been a presentation by:

Joël Perras (@jperras)
Nate Abele (@nateabele)


            Sucks. But check it out anyway.

Más contenido relacionado

La actualidad más candente

The History of PHPersistence
The History of PHPersistenceThe History of PHPersistence
The History of PHPersistenceHugo Hamon
 
Database Design Patterns
Database Design PatternsDatabase Design Patterns
Database Design PatternsHugo Hamon
 
Dependency injection-zendcon-2010
Dependency injection-zendcon-2010Dependency injection-zendcon-2010
Dependency injection-zendcon-2010Fabien Potencier
 
Silex meets SOAP & REST
Silex meets SOAP & RESTSilex meets SOAP & REST
Silex meets SOAP & RESTHugo Hamon
 
Dependency injection in PHP 5.3/5.4
Dependency injection in PHP 5.3/5.4Dependency injection in PHP 5.3/5.4
Dependency injection in PHP 5.3/5.4Fabien Potencier
 
Dependency injection - phpday 2010
Dependency injection - phpday 2010Dependency injection - phpday 2010
Dependency injection - phpday 2010Fabien Potencier
 
Dependency Injection with PHP and PHP 5.3
Dependency Injection with PHP and PHP 5.3Dependency Injection with PHP and PHP 5.3
Dependency Injection with PHP and PHP 5.3Fabien Potencier
 
Decouple Your Code For Reusability (International PHP Conference / IPC 2008)
Decouple Your Code For Reusability (International PHP Conference / IPC 2008)Decouple Your Code For Reusability (International PHP Conference / IPC 2008)
Decouple Your Code For Reusability (International PHP Conference / IPC 2008)Fabien Potencier
 
Rich domain model with symfony 2.5 and doctrine 2.5
Rich domain model with symfony 2.5 and doctrine 2.5Rich domain model with symfony 2.5 and doctrine 2.5
Rich domain model with symfony 2.5 and doctrine 2.5Leonardo Proietti
 
Symfony2, creare bundle e valore per il cliente
Symfony2, creare bundle e valore per il clienteSymfony2, creare bundle e valore per il cliente
Symfony2, creare bundle e valore per il clienteLeonardo Proietti
 
Doctrine fixtures
Doctrine fixturesDoctrine fixtures
Doctrine fixturesBill Chang
 
Unit and Functional Testing with Symfony2
Unit and Functional Testing with Symfony2Unit and Functional Testing with Symfony2
Unit and Functional Testing with Symfony2Fabien Potencier
 
New in cakephp3
New in cakephp3New in cakephp3
New in cakephp3markstory
 
Future of HTTP in CakePHP
Future of HTTP in CakePHPFuture of HTTP in CakePHP
Future of HTTP in CakePHPmarkstory
 
PHP Data Objects
PHP Data ObjectsPHP Data Objects
PHP Data ObjectsWez Furlong
 

La actualidad más candente (20)

The History of PHPersistence
The History of PHPersistenceThe History of PHPersistence
The History of PHPersistence
 
Database Design Patterns
Database Design PatternsDatabase Design Patterns
Database Design Patterns
 
Dependency injection-zendcon-2010
Dependency injection-zendcon-2010Dependency injection-zendcon-2010
Dependency injection-zendcon-2010
 
Symfony2 - WebExpo 2010
Symfony2 - WebExpo 2010Symfony2 - WebExpo 2010
Symfony2 - WebExpo 2010
 
Silex meets SOAP & REST
Silex meets SOAP & RESTSilex meets SOAP & REST
Silex meets SOAP & REST
 
Dependency injection in PHP 5.3/5.4
Dependency injection in PHP 5.3/5.4Dependency injection in PHP 5.3/5.4
Dependency injection in PHP 5.3/5.4
 
Dependency injection - phpday 2010
Dependency injection - phpday 2010Dependency injection - phpday 2010
Dependency injection - phpday 2010
 
Dependency Injection with PHP and PHP 5.3
Dependency Injection with PHP and PHP 5.3Dependency Injection with PHP and PHP 5.3
Dependency Injection with PHP and PHP 5.3
 
Decouple Your Code For Reusability (International PHP Conference / IPC 2008)
Decouple Your Code For Reusability (International PHP Conference / IPC 2008)Decouple Your Code For Reusability (International PHP Conference / IPC 2008)
Decouple Your Code For Reusability (International PHP Conference / IPC 2008)
 
Rich domain model with symfony 2.5 and doctrine 2.5
Rich domain model with symfony 2.5 and doctrine 2.5Rich domain model with symfony 2.5 and doctrine 2.5
Rich domain model with symfony 2.5 and doctrine 2.5
 
Symfony2, creare bundle e valore per il cliente
Symfony2, creare bundle e valore per il clienteSymfony2, creare bundle e valore per il cliente
Symfony2, creare bundle e valore per il cliente
 
Agile database access with CakePHP 3
Agile database access with CakePHP 3Agile database access with CakePHP 3
Agile database access with CakePHP 3
 
Doctrine fixtures
Doctrine fixturesDoctrine fixtures
Doctrine fixtures
 
Unit and Functional Testing with Symfony2
Unit and Functional Testing with Symfony2Unit and Functional Testing with Symfony2
Unit and Functional Testing with Symfony2
 
New in cakephp3
New in cakephp3New in cakephp3
New in cakephp3
 
Advanced Querying with CakePHP 3
Advanced Querying with CakePHP 3Advanced Querying with CakePHP 3
Advanced Querying with CakePHP 3
 
Future of HTTP in CakePHP
Future of HTTP in CakePHPFuture of HTTP in CakePHP
Future of HTTP in CakePHP
 
PHP Data Objects
PHP Data ObjectsPHP Data Objects
PHP Data Objects
 
CakeFest 2013 keynote
CakeFest 2013 keynoteCakeFest 2013 keynote
CakeFest 2013 keynote
 
Lithium Best
Lithium Best Lithium Best
Lithium Best
 

Similar a Lithium: The Framework for People Who Hate Frameworks

Can't Miss Features of PHP 5.3 and 5.4
Can't Miss Features of PHP 5.3 and 5.4Can't Miss Features of PHP 5.3 and 5.4
Can't Miss Features of PHP 5.3 and 5.4Jeff Carouth
 
Dependency Injection
Dependency InjectionDependency Injection
Dependency InjectionRifat Nabi
 
Doctrine For Beginners
Doctrine For BeginnersDoctrine For Beginners
Doctrine For BeginnersJonathan Wage
 
All I Need to Know I Learned by Writing My Own Web Framework
All I Need to Know I Learned by Writing My Own Web FrameworkAll I Need to Know I Learned by Writing My Own Web Framework
All I Need to Know I Learned by Writing My Own Web FrameworkBen Scofield
 
Zend Framework Study@Tokyo #2
Zend Framework Study@Tokyo #2Zend Framework Study@Tokyo #2
Zend Framework Study@Tokyo #2Shinya Ohyanagi
 
PhpUnit - The most unknown Parts
PhpUnit - The most unknown PartsPhpUnit - The most unknown Parts
PhpUnit - The most unknown PartsBastian Feder
 
Symfony2 Building on Alpha / Beta technology
Symfony2 Building on Alpha / Beta technologySymfony2 Building on Alpha / Beta technology
Symfony2 Building on Alpha / Beta technologyDaniel Knell
 
Virtual Madness @ Etsy
Virtual Madness @ EtsyVirtual Madness @ Etsy
Virtual Madness @ EtsyNishan Subedi
 
Why is crud a bad idea - focus on real scenarios
Why is crud a bad idea - focus on real scenariosWhy is crud a bad idea - focus on real scenarios
Why is crud a bad idea - focus on real scenariosDivante
 
Php unit the-mostunknownparts
Php unit the-mostunknownpartsPhp unit the-mostunknownparts
Php unit the-mostunknownpartsBastian Feder
 
international PHP2011_Bastian Feder_The most unknown Parts of PHPUnit
international PHP2011_Bastian Feder_The most unknown Parts of PHPUnitinternational PHP2011_Bastian Feder_The most unknown Parts of PHPUnit
international PHP2011_Bastian Feder_The most unknown Parts of PHPUnitsmueller_sandsmedia
 
Singletons in PHP - Why they are bad and how you can eliminate them from your...
Singletons in PHP - Why they are bad and how you can eliminate them from your...Singletons in PHP - Why they are bad and how you can eliminate them from your...
Singletons in PHP - Why they are bad and how you can eliminate them from your...go_oh
 
Dependency injection in Drupal 8
Dependency injection in Drupal 8Dependency injection in Drupal 8
Dependency injection in Drupal 8Alexei Gorobets
 
How Kris Writes Symfony Apps
How Kris Writes Symfony AppsHow Kris Writes Symfony Apps
How Kris Writes Symfony AppsKris Wallsmith
 
SPL: The Missing Link in Development
SPL: The Missing Link in DevelopmentSPL: The Missing Link in Development
SPL: The Missing Link in Developmentjsmith92
 
Advanced symfony Techniques
Advanced symfony TechniquesAdvanced symfony Techniques
Advanced symfony TechniquesKris Wallsmith
 
Unit testing with zend framework tek11
Unit testing with zend framework tek11Unit testing with zend framework tek11
Unit testing with zend framework tek11Michelangelo van Dam
 

Similar a Lithium: The Framework for People Who Hate Frameworks (20)

Can't Miss Features of PHP 5.3 and 5.4
Can't Miss Features of PHP 5.3 and 5.4Can't Miss Features of PHP 5.3 and 5.4
Can't Miss Features of PHP 5.3 and 5.4
 
Unittests für Dummies
Unittests für DummiesUnittests für Dummies
Unittests für Dummies
 
Dependency Injection
Dependency InjectionDependency Injection
Dependency Injection
 
Doctrine For Beginners
Doctrine For BeginnersDoctrine For Beginners
Doctrine For Beginners
 
All I Need to Know I Learned by Writing My Own Web Framework
All I Need to Know I Learned by Writing My Own Web FrameworkAll I Need to Know I Learned by Writing My Own Web Framework
All I Need to Know I Learned by Writing My Own Web Framework
 
Zend Framework Study@Tokyo #2
Zend Framework Study@Tokyo #2Zend Framework Study@Tokyo #2
Zend Framework Study@Tokyo #2
 
PhpUnit - The most unknown Parts
PhpUnit - The most unknown PartsPhpUnit - The most unknown Parts
PhpUnit - The most unknown Parts
 
Symfony2 Building on Alpha / Beta technology
Symfony2 Building on Alpha / Beta technologySymfony2 Building on Alpha / Beta technology
Symfony2 Building on Alpha / Beta technology
 
Separation of concerns - DPC12
Separation of concerns - DPC12Separation of concerns - DPC12
Separation of concerns - DPC12
 
Virtual Madness @ Etsy
Virtual Madness @ EtsyVirtual Madness @ Etsy
Virtual Madness @ Etsy
 
Why is crud a bad idea - focus on real scenarios
Why is crud a bad idea - focus on real scenariosWhy is crud a bad idea - focus on real scenarios
Why is crud a bad idea - focus on real scenarios
 
Php unit the-mostunknownparts
Php unit the-mostunknownpartsPhp unit the-mostunknownparts
Php unit the-mostunknownparts
 
international PHP2011_Bastian Feder_The most unknown Parts of PHPUnit
international PHP2011_Bastian Feder_The most unknown Parts of PHPUnitinternational PHP2011_Bastian Feder_The most unknown Parts of PHPUnit
international PHP2011_Bastian Feder_The most unknown Parts of PHPUnit
 
Singletons in PHP - Why they are bad and how you can eliminate them from your...
Singletons in PHP - Why they are bad and how you can eliminate them from your...Singletons in PHP - Why they are bad and how you can eliminate them from your...
Singletons in PHP - Why they are bad and how you can eliminate them from your...
 
Dependency injection in Drupal 8
Dependency injection in Drupal 8Dependency injection in Drupal 8
Dependency injection in Drupal 8
 
Unit testing zend framework apps
Unit testing zend framework appsUnit testing zend framework apps
Unit testing zend framework apps
 
How Kris Writes Symfony Apps
How Kris Writes Symfony AppsHow Kris Writes Symfony Apps
How Kris Writes Symfony Apps
 
SPL: The Missing Link in Development
SPL: The Missing Link in DevelopmentSPL: The Missing Link in Development
SPL: The Missing Link in Development
 
Advanced symfony Techniques
Advanced symfony TechniquesAdvanced symfony Techniques
Advanced symfony Techniques
 
Unit testing with zend framework tek11
Unit testing with zend framework tek11Unit testing with zend framework tek11
Unit testing with zend framework tek11
 

Más de Nate Abele

Measuring Your Code 2.0
Measuring Your Code 2.0Measuring Your Code 2.0
Measuring Your Code 2.0Nate Abele
 
Measuring Your Code
Measuring Your CodeMeasuring Your Code
Measuring Your CodeNate Abele
 
Building Apps with MongoDB
Building Apps with MongoDBBuilding Apps with MongoDB
Building Apps with MongoDBNate Abele
 
Practical PHP 5.3
Practical PHP 5.3Practical PHP 5.3
Practical PHP 5.3Nate Abele
 
Measuring Your Code
Measuring Your CodeMeasuring Your Code
Measuring Your CodeNate Abele
 

Más de Nate Abele (6)

Measuring Your Code 2.0
Measuring Your Code 2.0Measuring Your Code 2.0
Measuring Your Code 2.0
 
Measuring Your Code
Measuring Your CodeMeasuring Your Code
Measuring Your Code
 
Building Apps with MongoDB
Building Apps with MongoDBBuilding Apps with MongoDB
Building Apps with MongoDB
 
Practical PHP 5.3
Practical PHP 5.3Practical PHP 5.3
Practical PHP 5.3
 
Measuring Your Code
Measuring Your CodeMeasuring Your Code
Measuring Your Code
 
Doin' It Rong
Doin' It RongDoin' It Rong
Doin' It Rong
 

Último

Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024Scott Keck-Warren
 
TeamStation AI System Report LATAM IT Salaries 2024
TeamStation AI System Report LATAM IT Salaries 2024TeamStation AI System Report LATAM IT Salaries 2024
TeamStation AI System Report LATAM IT Salaries 2024Lonnie McRorey
 
DSPy a system for AI to Write Prompts and Do Fine Tuning
DSPy a system for AI to Write Prompts and Do Fine TuningDSPy a system for AI to Write Prompts and Do Fine Tuning
DSPy a system for AI to Write Prompts and Do Fine TuningLars Bell
 
Dev Dives: Streamline document processing with UiPath Studio Web
Dev Dives: Streamline document processing with UiPath Studio WebDev Dives: Streamline document processing with UiPath Studio Web
Dev Dives: Streamline document processing with UiPath Studio WebUiPathCommunity
 
Designing IA for AI - Information Architecture Conference 2024
Designing IA for AI - Information Architecture Conference 2024Designing IA for AI - Information Architecture Conference 2024
Designing IA for AI - Information Architecture Conference 2024Enterprise Knowledge
 
How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.Curtis Poe
 
TrustArc Webinar - How to Build Consumer Trust Through Data Privacy
TrustArc Webinar - How to Build Consumer Trust Through Data PrivacyTrustArc Webinar - How to Build Consumer Trust Through Data Privacy
TrustArc Webinar - How to Build Consumer Trust Through Data PrivacyTrustArc
 
Story boards and shot lists for my a level piece
Story boards and shot lists for my a level pieceStory boards and shot lists for my a level piece
Story boards and shot lists for my a level piececharlottematthew16
 
SAP Build Work Zone - Overview L2-L3.pptx
SAP Build Work Zone - Overview L2-L3.pptxSAP Build Work Zone - Overview L2-L3.pptx
SAP Build Work Zone - Overview L2-L3.pptxNavinnSomaal
 
How to write a Business Continuity Plan
How to write a Business Continuity PlanHow to write a Business Continuity Plan
How to write a Business Continuity PlanDatabarracks
 
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptx
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptxMerck Moving Beyond Passwords: FIDO Paris Seminar.pptx
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptxLoriGlavin3
 
SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024Lorenzo Miniero
 
Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Commit University
 
Leverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage Cost
Leverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage CostLeverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage Cost
Leverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage CostZilliz
 
Developer Data Modeling Mistakes: From Postgres to NoSQL
Developer Data Modeling Mistakes: From Postgres to NoSQLDeveloper Data Modeling Mistakes: From Postgres to NoSQL
Developer Data Modeling Mistakes: From Postgres to NoSQLScyllaDB
 
Powerpoint exploring the locations used in television show Time Clash
Powerpoint exploring the locations used in television show Time ClashPowerpoint exploring the locations used in television show Time Clash
Powerpoint exploring the locations used in television show Time Clashcharlottematthew16
 
Scanning the Internet for External Cloud Exposures via SSL Certs
Scanning the Internet for External Cloud Exposures via SSL CertsScanning the Internet for External Cloud Exposures via SSL Certs
Scanning the Internet for External Cloud Exposures via SSL CertsRizwan Syed
 
H2O.ai CEO/Founder: Sri Ambati Keynote at Wells Fargo Day
H2O.ai CEO/Founder: Sri Ambati Keynote at Wells Fargo DayH2O.ai CEO/Founder: Sri Ambati Keynote at Wells Fargo Day
H2O.ai CEO/Founder: Sri Ambati Keynote at Wells Fargo DaySri Ambati
 
Gen AI in Business - Global Trends Report 2024.pdf
Gen AI in Business - Global Trends Report 2024.pdfGen AI in Business - Global Trends Report 2024.pdf
Gen AI in Business - Global Trends Report 2024.pdfAddepto
 

Último (20)

Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024
 
TeamStation AI System Report LATAM IT Salaries 2024
TeamStation AI System Report LATAM IT Salaries 2024TeamStation AI System Report LATAM IT Salaries 2024
TeamStation AI System Report LATAM IT Salaries 2024
 
DSPy a system for AI to Write Prompts and Do Fine Tuning
DSPy a system for AI to Write Prompts and Do Fine TuningDSPy a system for AI to Write Prompts and Do Fine Tuning
DSPy a system for AI to Write Prompts and Do Fine Tuning
 
Dev Dives: Streamline document processing with UiPath Studio Web
Dev Dives: Streamline document processing with UiPath Studio WebDev Dives: Streamline document processing with UiPath Studio Web
Dev Dives: Streamline document processing with UiPath Studio Web
 
Designing IA for AI - Information Architecture Conference 2024
Designing IA for AI - Information Architecture Conference 2024Designing IA for AI - Information Architecture Conference 2024
Designing IA for AI - Information Architecture Conference 2024
 
How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.
 
TrustArc Webinar - How to Build Consumer Trust Through Data Privacy
TrustArc Webinar - How to Build Consumer Trust Through Data PrivacyTrustArc Webinar - How to Build Consumer Trust Through Data Privacy
TrustArc Webinar - How to Build Consumer Trust Through Data Privacy
 
Story boards and shot lists for my a level piece
Story boards and shot lists for my a level pieceStory boards and shot lists for my a level piece
Story boards and shot lists for my a level piece
 
SAP Build Work Zone - Overview L2-L3.pptx
SAP Build Work Zone - Overview L2-L3.pptxSAP Build Work Zone - Overview L2-L3.pptx
SAP Build Work Zone - Overview L2-L3.pptx
 
How to write a Business Continuity Plan
How to write a Business Continuity PlanHow to write a Business Continuity Plan
How to write a Business Continuity Plan
 
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptx
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptxMerck Moving Beyond Passwords: FIDO Paris Seminar.pptx
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptx
 
DMCC Future of Trade Web3 - Special Edition
DMCC Future of Trade Web3 - Special EditionDMCC Future of Trade Web3 - Special Edition
DMCC Future of Trade Web3 - Special Edition
 
SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024
 
Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!
 
Leverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage Cost
Leverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage CostLeverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage Cost
Leverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage Cost
 
Developer Data Modeling Mistakes: From Postgres to NoSQL
Developer Data Modeling Mistakes: From Postgres to NoSQLDeveloper Data Modeling Mistakes: From Postgres to NoSQL
Developer Data Modeling Mistakes: From Postgres to NoSQL
 
Powerpoint exploring the locations used in television show Time Clash
Powerpoint exploring the locations used in television show Time ClashPowerpoint exploring the locations used in television show Time Clash
Powerpoint exploring the locations used in television show Time Clash
 
Scanning the Internet for External Cloud Exposures via SSL Certs
Scanning the Internet for External Cloud Exposures via SSL CertsScanning the Internet for External Cloud Exposures via SSL Certs
Scanning the Internet for External Cloud Exposures via SSL Certs
 
H2O.ai CEO/Founder: Sri Ambati Keynote at Wells Fargo Day
H2O.ai CEO/Founder: Sri Ambati Keynote at Wells Fargo DayH2O.ai CEO/Founder: Sri Ambati Keynote at Wells Fargo Day
H2O.ai CEO/Founder: Sri Ambati Keynote at Wells Fargo Day
 
Gen AI in Business - Global Trends Report 2024.pdf
Gen AI in Business - Global Trends Report 2024.pdfGen AI in Business - Global Trends Report 2024.pdf
Gen AI in Business - Global Trends Report 2024.pdf
 

Lithium: The Framework for People Who Hate Frameworks

  • 1. A Framework for People Who Hate Frameworks.
  • 2. A movement in 3 parts • Frameworks suck • Everything you know is wrong • Lithium tries to suck less
  • 4. Let’s get one thing out of the way:
  • 8. And yes, I mean:
  • 9. Why? (Besides the obvious attempt at being provocative)
  • 10. Frameworks Suck • Code you will never use. • Complexity overhead. • You didn’t write it.
  • 12. His name is the biggest, so it’s his fault.
  • 13. We’re not saying design patterns are bad. Quite the opposite.
  • 14. Lithium implements many design patterns.
  • 16. Some patterns only treat the symptoms, instead of the cause.
  • 18. Object dependencies. “The principle of separating configuration from use.”
  • 19. Sucks. function initialize(&$controller, $settings = array()) { /* ...[snip]... */ $prefixes = Router::prefixes(); if (!empty($prefixes)) { foreach ($prefixes as $prefix) { /* ...[do something nasty to the global state]... */ } } if (Configure::read() > 0) { App::import('Debugger'); Debugger::checkSecurityKeys(); } } Sucks hard.
  • 21. Everyone does it differently.
  • 22. Sometimes in the same framework.
  • 23. Sometimes in the same class.
  • 24. Sucks function spam($emails) { $this->Email->replyTo = 'nigerian.prince@example.com'; $this->Email->from = 'Desmond Etete <nigerian.prince@example.com>'; $this->Email->template = 'mo_monies'; $this->Email->sendAs = 'annoying_html'; foreach ($emails as $email) { $this->Email->to = $email['address']; $this->Email->subject = "Good to you news I have {$email['name']}"; $this->Email->send(); } }
  • 27. ... or is it?
  • 28. [variables changed to protect the innocent.] [... not really. It’s Symfony.]
  • 29. Show that object who’s boss. class User { function __construct($storage) { $this->storage = $storage; } } $storage = new SessionStorage('SESSION_ID'); $user = new User($storage);
  • 30. Of course, we want this to abstract this. Frameworks adore abstractions.
  • 31. DI Container to the rescue!
  • 32. class Container { static protected $shared = array(); // ... public function getMailer() { if (isset(self::$shared['mailer'])) { return self::$shared['mailer']; } $class = $this->parameters['mailer.class']; $mailer = new $class(); $mailer->setDefaultTransport($this->getMailTransport()); return self::$shared['mailer'] = $mailer; } }
  • 33. But now you want an abstraction to manage the DI container. Duh.
  • 34. So you create a “Service Container”.
  • 35. class Container extends sfServiceContainer { static protected $shared = array(); protected function getMailTransportService() { return new Zend_Mail_Transport_Smtp('smtp.gmail.com', array( 'auth' => 'login', 'username' => $this['mailer.username'], 'password' => $this['mailer.password'], 'ssl' => 'ssl', 'port' => 465, )); } }
  • 36. Of course, we now want to abstract the crap out of the Service Container. Double duh.
  • 37. So lets use a Builder to configure the Services.
  • 38. Yeah! require_once '/PATH/TO/sfServiceContainerAutoloader.php'; sfServiceContainerAutoloader::register(); $sc = new sfServiceContainerBuilder(); $sc-> register('mail.transport', 'Zend_Mail_Transport_Smtp')-> addArgument('smtp.gmail.com')-> addArgument(array( 'auth' => 'login', 'username' => '%mailer.username%', 'password' => '%mailer.password%', 'ssl' => 'ssl', 'port' => 465, ))-> setShared(false) ; $sc-> register('mailer', '%mailer.class%')-> addMethodCall('setDefaultTransport', array(new sfServiceReference ('mail.transport'))) ;
  • 39. And for good measure, have our configurations for Service Containers in XML files.
  • 40. So.... We have Dependency Injection. Managed by a Service Container. Parametrized with XML data. And the whole thing configured by a Builder. ...to fix one problem.
  • 41. Anyone see what’s wrong here?
  • 44. The sun does not revolve around OOP ...nevertheless, it moves. Galileo facing the Roman Inquistion - Cristiano Banti (1857)
  • 47. class User { public function create() { $logger = new Logger(); $logger->write('Creating a new user...'); $this->_doSomeInitialization(); $this->_databaseConnection->doATransaction($this)->create(); $logger->write('Finished creating user'); } } $user = new User(); $user->create();
  • 48. class User { public $logger; public function create() { $this->logger->write('Creating a new user...'); $this->_doSomeInitialization(); $this->_databaseConnection->doATransaction($this)->create(); $this->logger->write('Finished creating user'); } } $user = new User(); $user->logger = new Logger(); $user->create();
  • 49. Dependency Injection • Fixes the problem of static dependencies • Ignores the problem of static relationships • Same methods called on injected classes • No way to introduce new relationships • Higher overhead, more boilerplate code
  • 50. class Service extends lithiumcoreObject { protected $_classes = array( 'request' => 'lithiumnethttpRequest', 'response' => 'lithiumnethttpResponse', 'socket' => 'lithiumnetsocketContext' ); protected function _init() { $class = Libraries::locate('socket.util', $this->_classes['socket']); $this->_connection = new $class($this->_config); // ... } /* ...[snip]... */ public function send($method, $path = null, $data = null, array $options = array()) { /* ...[snip]... */ $response = $this->_connection->send($request, array('classes' => $this->_classes)); // ... } }
  • 51. Coupling should be in proportion to domain relevance.
  • 53. If... Configure::write('debug', 0); is evil, $this->debug = 0; is the
  • 54.
  • 56. class Service { protected $_timeout = 30; public function send($method, $data = null, array $options = array()) { // WTF does this do? $this->_prepare(); $response = $this->_connection->send($request, array( 'timeout' => $this->_timeout )); // ... } }
  • 57. OO doesn’t make you think (about state).
  • 59. ActiveRecord Data Access Object Unit of Work Dependency Injection Registry Front Controller MVC Value Object Data Mapper Service Layer
  • 61. Design patterns • Each pattern is only useful in a limited context • Layering many design patterns on top of each other often indicates poor design choices • Mis-application arises from trying to run before you can walk
  • 62. Tools do not mean... ...you can build a house.
  • 64. Lithium tries to suck less.
  • 66. Aspect-Oriented Design • Separation of concerns • Domain classes should not know or care about cross- cutting concerns • Examples: • Caching • Logging • Access Control, etc.
  • 67. Functional Programming • Only possible when functions are first-class citizens • Referential transparency • Function purity
  • 68. Referential transparency is not... $this date() $_*
  • 69. Referential transparency is not... $this date() $_*
  • 70. These Are Not Design Patterns.
  • 71. Less Suck • Draws on years of experience building web frameworks • PHP 5.3+ only • Doesn’t assume you’re stupid
  • 72. Ways we suck less:
  • 74. <?php namespace applicationbar; use lithiumutilString; use lithiumutilCollection; class Foo extends lithiumcoreObject { protected $_classes = array( 'cache' => 'lithiumstorageCache', 'logger' => 'lithiumanalysisLogger' ); public function __construct(array $config = array()) { // ... } protected function _init() { // ... } } ?>
  • 75. <?php namespace applicationbar; use lithiumutilString; use lithiumutilCollection; class Foo extends lithiumcoreObject { protected $_classes = array( 'cache' => 'lithiumstorageCache', 'logger' => 'lithiumanalysisLogger' ); public function __construct(array $config = array()) { // ... 1 } protected function _init() { // ... } } ?>
  • 76. public function __construct(array $config = array()) <?php public function __construct(array $config = array()) namespace applicationbar; public function __construct(array $config = array()) use public function __construct(array $config = lithiumutilString; array()) use lithiumutilCollection; public function __construct(array $config = array()) class Foo extends lithiumcoreObject { public function __construct(array $config = array()) protected $_classes = array( public function'lithiumstorageCache', = 'cache' => __construct(array $config array()) 'logger' => 'lithiumanalysisLogger' public function __construct(array $config = ); array()) public function __construct(array $config = array()) { // ... } public function __construct(array $config = array()) protected function _init() { public function __construct(array $config = array()) // ... } public function __construct(array $config = array()) } public function __construct(array $config = array()) ?> public function __construct(array $config = array())
  • 77. <?php <?php namespace applicationbar; class Foo extends lithiumcoreObject { use lithiumutilString; use lithiumutilCollection; protected function _init() { class Foo extends lithiumcoreObject { $or = $some->highOverHead($operation); $or()->otherwise(HARD_TO_TEST)->code(); protected $_classes = array( } 'cache' => 'lithiumstorageCache', } 'logger' => 'lithiumanalysisLogger' ); ?> public function __construct(array $config = array()) { // ... } protected function _init() { // ... 2 } } ?>
  • 78. <?php <?php namespace applicationbar; class Foo extends lithiumcoreObject { use lithiumutilString; use lithiumutilCollection; protected function _init() { class Foo extends lithiumcoreObject { $or = $some->highOverHead($operation); $or()->otherwise(HARD_TO_TEST)->code(); protected $_classes = array( } 'cache' => 'lithiumstorageCache', } 'logger' => 'lithiumanalysisLogger' ); ?> public function __construct(array $config = array()) { // ... } protected function _init() { // ... 2 } } $foo = new Foo(array('init' => false)); ?>
  • 79. <?php namespace applicationbar; 3 use lithiumutilString; use lithiumutilCollection; new applicationbarFoo(); // loads app/bar/Foo.php class Foo extends lithiumcoreObject { protected $_classes = array( 'cache' => 'lithiumstorageCache', 'logger' => 'lithiumanalysisLogger' ); public function __construct(array $config = array()) { // ... } protected function _init() { // ... } } ?>
  • 80. <?php namespace applicationbar; 4 use lithiumutilString; use lithiumutilCollection; class Foo extends lithiumcoreObject { protected $_classes = array( 'cache' => 'lithiumstorageCache', 'logger' => 'lithiumanalysisLogger' ); public function __construct(array $config = array()) { // ... } protected function _init() { // ... } } ?>
  • 81. <?php namespace applicationbar; use lithiumutilString; use lithiumutilCollection; class Foo extends lithiumcoreObject { protected $_classes = array( 'cache' => 'lithiumstorageCache', 'logger' => 'lithiumanalysisLogger' 5 ); public function __construct(array $config = array()) { // ... } protected function _init() { // ... = $this->_classes['cache']; $cache } $cache::write(__CLASS__, $this->_someGeneratedValue()); } } } ?> ?>
  • 82. <?php namespace applicationbar; use lithiumutilString; use lithiumutilCollection; class Foo extends lithiumcoreObject { protected $_classes = array( 'cache' => 'lithiumstorageCache', 'logger' => 'lithiumanalysisLogger' 5 ); $foo = new Foo(array('classes' => array( public function __construct(array $config = array()) { 'cache' => 'applicationextensionsCache' // ... ))); } protected function _init() { // ... = $this->_classes['cache']; $cache } $cache::write(__CLASS__, $this->_someGeneratedValue()); } } } ?> ?>
  • 84. Keeps parameter lists short & Makes class APIs more extensible
  • 86. Same idea. But...! Modifies class / object state.
  • 87. Adaptable Auth Cache Catalog Connections Logger Session
  • 88. use lithiumsecurityAuth; Auth::config(array( 'customer' => array( 'adapter' => 'Form', 'model' => 'Customer', 'fields' => array('email', 'password') ) ));
  • 89. use lithiumstorageCache; Cache::config(array( 'local' => array('adapter' => 'Apc'), 'distributed' => array( 'adapter' => 'Memcached', 'servers' => array('127.0.0.1', 11211), ), 'default' => array('adapter' => 'File') ));
  • 90. use lithiumdataConnections; Connections::config(array( 'old' => array( 'type' => 'database', 'adapter' => 'MySql', 'user' => 'bobby_tables', 'password' => '******', 'database' => 'my_app' ), 'new' => array( 'type' => 'http', 'adapter' => 'CouchDb', 'database' => 'my_app' ) ));
  • 91. use lithiumstorageSession; Session::config(array( 'cookie' => array( 'adapter' => 'Cookie', 'expire' => '+2 days' ), 'default' => array('adapter' => 'Php') ));
  • 93. use lithiumstorageSession; Session::config(array( 'default' => array( 'adapter' => 'MyCustomAdapter', 'expires' => '+2 days', 'custom' => 'Whatevah!' ) )); public function __construct(array $config = array())
  • 95. use lithiumstorageCache; Cache::config(array( 'default' => array( 'development' => array( 'adapter' => 'Apc' ), 'production' => array( 'adapter' => 'Memcached', 'servers' => array('127.0.0.1', 11211) ) ) ));
  • 96. Works identically for all adapters.
  • 97. If you remember nothing else about configuration state...
  • 100. Zoom! • Use native extensions (PECL) whenever possible. • Don’t like a class? Change it. At runtime. • Profiled at every step of the way.
  • 102. Lithium is the most flexible framework.
  • 104. class Service extends lithiumcoreObject { protected $_classes = array( 'request' => 'lithiumnethttpRequest', 'response' => 'lithiumnethttpResponse', 'socket' => 'lithiumnetsocketContext' ); } $service = new Service(array('classes' => array( 'socket' => 'mycustomSocket' )));
  • 106. Example: Caching & Logging Caching Logging Post::find()
  • 107. Example: Caching & Logging Caching Logging Post::find()
  • 108. Example: Caching & Logging Caching Logging Post::find()
  • 109. use lithiumanalysisLogger; Post::applyFilter('find', function($self, $params, $chain) { // Generate the log message $conditions = $params['options']['conditions']; $message = 'Post query with constraint ' . var_export($conditions, true); Logger::write('info', $message); return $chain->next($self, $params, $chain); });
  • 110. Post Logger use lithiumanalysisLogger; Post::applyFilter('find', function($self, $params, $chain) { // Generate the log message $conditions = $params['options']['conditions']; $message = 'Post query with constraint ' . var_export($conditions, true); Logger::write('info', $message); return $chain->next($self, $params, $chain); });
  • 111. What about Observer? • Dependent on a centralized publish/ subscribe system • Extra layer of abstraction • Fewer possibilities
  • 112. What about Observer? • Filters are self-contained and attach directly to objects • Direct and intuitive
  • 113. Features: Everything is an adapter.
  • 114. G11n (Globalization) • CLDR • Gettext • PHP arrays • Code • Pecl/intl support on the way
  • 115. Databases • 1st-class support for document-oriented databases • MongoDB & CouchDB: production ready • Relational databases coming soon
  • 116. <?php $post = Post::create(array( 'title' => 'Forget the words and sing along', 'body' => 'Everything you know is wrong' )); $post->save(); $post = Post::find($id); ?> <h2><?=$post->title; ?></h2> <p><?=$post->body; ?></p>
  • 117. This works on... • MongoDB • CouchDB • MySQL • SQLite (almost)
  • 118. Databases • Adapter based. Plugin aware. • Will ship with MySQL, SQLite, PostgreSQL & SQL Server. • Query API
  • 119. Integration with other frameworks • Easily load & use libraries from other frameworks: • Zend Framework, Solar, Symfony
  • 120. /* add the trunk */ Libraries::add("Zend", array( "prefix" => "Zend_", "includePath" => '/htdocs/libraries/Zend/trunk/library', "bootstrap" => "Loader/Autoloader.php", "loader" => array("Zend_Loader_Autoloader", "autoload"), "transform" => function($class) { return str_replace("_", "/", $class) . ".php"; } )); // Note that 'path' can be dropped if trunk/library/Zend is placed // directly into your /libraries directory. /* add the incubator */ Libraries::add("Zend_Incubator", array( "prefix" => "Zend_", "includePath" => '/htdocs/libraries/Zend/incubator/library', "transform" => function($class) { return str_replace("_", "/", $class) . ".php"; } ));
  • 121. namespace appcontrollers; use Zend_Mail_Storage_Pop3; class EmailController extends lithiumactionController { public function index() { $mail = new Zend_Mail_Storage_Pop3(array( 'host' => 'localhost', 'user' => 'test', 'password' => 'test' )); return compact('mail'); } }
  • 122.
  • 123. This has been a presentation by: Joël Perras (@jperras) Nate Abele (@nateabele) Sucks. But check it out anyway.