SlideShare ist ein Scribd-Unternehmen logo
1 von 121
Downloaden Sie, um offline zu lesen
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.
Why?
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 well known 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.”
Configuration.
Everyone does it differently.
Sometimes in the same framework.
Sometimes in the same class.
Dependency injection.
A great idea!
... but you need to understand what you’re
doing.
Some patterns were implemented in Java, to
solve language problems that PHP just doesn’t
have.
“Design Patterns In Dynamic Languages”
              Peter Norvig
   http://norvig.com/design-patterns/
Try this some time...
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
• 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
Dependency Injection

• Various attempts at making DI work better:
 • DI Container
 • Using dynamic nature of PHP to your
    advantage.
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
• Functional 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 try to 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() {
         // ...
     }
}

?>
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 = array())
    lithiumutilString;
use lithiumutilCollection;
    public function __construct(array $config = array())
class Foo extends lithiumcoreObject {
    public function __construct(array $config = array())
     protected $_classes = array(
     public function'lithiumstorageCache', = array())
         'cache' => __construct(array $config
         '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

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

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;   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());
}    }
}
?>
?>
<?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() {
         // ... = $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'      => 'MongoDb',
        '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' => 'Whatever!'
    )
));
use lithiumstorageSession;

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



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)
        )
    )
));
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.
Performance.
Zoom?
• Performance vs. speed of development is a
  series of trade-offs

• Large-scale apps don’t use stock framework
  infrastructure, and that’s a good thing

• A generalized framework will never be as
  fast as hand-tuned code
Zoom!
• Choice is good
• Use native extensions (PECL) whenever
  possible.

• Don’t like a class? Change it. At runtime.
• Profiled at every step of the way with
  XHProf and XDebug cachegrinds.
Example: Resource
Routing
use appmodelsPost;
use lithiumactionResponse;
use lithiumnethttpRouter;



Router::connect('/frequent_api_call.json', array(), function($request) {
    return new Response(array(
        'type' => 'application/json',
        'body' => Post::recent()->to('json')
    ));
});
Platform
Rackspace Cloud
 •   256MB ram
 •   Ubuntu Karmic
 •   Apache 2.2.12
 •   PHP 5.3.1
 •   Xcache
 •   Siege 2.68




                     2009-11-26
Flexibility.
Lithium is a highly
flexible framework.
Most class dependencies
are dynamic.
(Our implementation of dependency injection)
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()
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);
});
use lithiumanalysisLogger;




Post                                                                                   Logger
       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.

                       (well, almost)
Databases
• 1st-class support for document-oriented
  databases

• MongoDB & CouchDB: production ready
• Relational databases in beta
• Cassandra/Redis/Riak in the works, too
<?php

$post = Post::create(array(
    'title' => '         ',
     'body' => '               '
));
$post->save();

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

?>

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

• MongoDB
• CouchDB
• MySQL
• SQLite
MongoDB + CouchDB:
$post = Post::create(array(
    'title' => '         ',
      'body' => '                           ',
      'tags' => array('PHP', 'Japan'),
      'author' => array('name' => 'Nate')
));

$post->save();
MongoDB:
$posts = Post::all(array('conditions' => array(
     'tags' => array('PHP', 'Japan'),
     'author.name' => 'Nate'
)));


// Translates to...
db.posts.find({
    tags : { $in : ['PHP', 'Japan'] },
    'author.name' : 'Nate'
})
Databases

• Adapter based, plugin aware
• Will ship with MySQL, SQLite & PostgreSQL
• SQL Server support via plugin
• Query API
The Query API

• Flexible data container
• Allows each backend data store to only worry
  about features it implements

• Keeps model API separate from backend data
  sources
The Query API

$ages = User::all(array(
      'group'   => 'age',
      'reduce' => 'function(obj, prev) { prev.count++; }',
      'initial' => array('count' => 0)
));
The Query API
$query = new Query(array(
    'type' => 'read',
    'model' => 'appmodelsPost',
    'fields' => array('Post.title', 'Post.body'),
    'conditions' => array('Post.id' => new Query(array(
        'type' => 'read',
        'fields' => array('post_id'),
        'model' => 'appmodelsTagging',
        'conditions' => array('Tag.name' => array('foo', 'bar', 'baz')),
    )))
));
The Query API

• Run simple queries via the Model API
• Build your own complex queries with the
  Query API

• Create your own adapter, or drop in a
  custom query optimizer
Btw, li3_doctrine
Plays nice with others

• Easily load & use libraries from other
  frameworks:

  • Zend Framework, Solar, Symfony, PEAR,
    etc.

  • PSR-0 Class-loading standard
/* add the trunk */
Libraries::add("Zend", array(
    "prefix" => "Zend_",
    "includePath" => true,
    "bootstrap" => "Loader/Autoloader.php",
    "loader" => array("Zend_Loader_Autoloader", "autoload"),
    "transform" => function($class) { return str_replace("_", "/", $class) . ".php"; }
));



/* 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:

Nate Abele (@nateabele)

Joël Perras (@jperras)

                   http://lithify.me
            Sucks. But check it out anyway.

Weitere ähnliche Inhalte

Was ist angesagt?

Design Patterns avec PHP 5.3, Symfony et Pimple
Design Patterns avec PHP 5.3, Symfony et PimpleDesign Patterns avec PHP 5.3, Symfony et Pimple
Design Patterns avec PHP 5.3, Symfony et PimpleHugo Hamon
 
Silex meets SOAP & REST
Silex meets SOAP & RESTSilex meets SOAP & REST
Silex meets SOAP & RESTHugo Hamon
 
The History of PHPersistence
The History of PHPersistenceThe History of PHPersistence
The History of PHPersistenceHugo 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
 
Database Design Patterns
Database Design PatternsDatabase Design Patterns
Database Design PatternsHugo Hamon
 
Dependency injection - phpday 2010
Dependency injection - phpday 2010Dependency injection - phpday 2010
Dependency injection - phpday 2010Fabien 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
 
Unit and Functional Testing with Symfony2
Unit and Functional Testing with Symfony2Unit and Functional Testing with Symfony2
Unit and Functional Testing with Symfony2Fabien 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
 
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
 
Be RESTful (Symfony Camp 2008)
Be RESTful (Symfony Camp 2008)Be RESTful (Symfony Camp 2008)
Be RESTful (Symfony Camp 2008)Fabien Potencier
 
Doctrine fixtures
Doctrine fixturesDoctrine fixtures
Doctrine fixturesBill Chang
 
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
 

Was ist angesagt? (20)

Design Patterns avec PHP 5.3, Symfony et Pimple
Design Patterns avec PHP 5.3, Symfony et PimpleDesign Patterns avec PHP 5.3, Symfony et Pimple
Design Patterns avec PHP 5.3, Symfony et Pimple
 
Lithium Best
Lithium Best Lithium Best
Lithium Best
 
Silex meets SOAP & REST
Silex meets SOAP & RESTSilex meets SOAP & REST
Silex meets SOAP & REST
 
The History of PHPersistence
The History of PHPersistenceThe History of PHPersistence
The History of PHPersistence
 
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
 
Database Design Patterns
Database Design PatternsDatabase Design Patterns
Database Design Patterns
 
Dependency injection - phpday 2010
Dependency injection - phpday 2010Dependency injection - phpday 2010
Dependency injection - phpday 2010
 
Symfony2 - WebExpo 2010
Symfony2 - WebExpo 2010Symfony2 - WebExpo 2010
Symfony2 - WebExpo 2010
 
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)
 
Unit and Functional Testing with Symfony2
Unit and Functional Testing with Symfony2Unit and Functional Testing with Symfony2
Unit and Functional Testing with Symfony2
 
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
 
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
 
Be RESTful (Symfony Camp 2008)
Be RESTful (Symfony Camp 2008)Be RESTful (Symfony Camp 2008)
Be RESTful (Symfony Camp 2008)
 
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
 
Advanced Querying with CakePHP 3
Advanced Querying with CakePHP 3Advanced Querying with CakePHP 3
Advanced Querying with CakePHP 3
 
New in cakephp3
New in cakephp3New in cakephp3
New in cakephp3
 
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
 

Andere mochten auch

Measuring Your Code
Measuring Your CodeMeasuring Your Code
Measuring Your CodeNate Abele
 
Measuring Your Code 2.0
Measuring Your Code 2.0Measuring Your Code 2.0
Measuring Your Code 2.0Nate Abele
 
Introducing Zend Studio 10 Japanese Edition
Introducing Zend Studio 10 Japanese EditionIntroducing Zend Studio 10 Japanese Edition
Introducing Zend Studio 10 Japanese EditionSatoru Yoshida
 
Practical PHP 5.3
Practical PHP 5.3Practical PHP 5.3
Practical PHP 5.3Nate Abele
 
Building Apps with MongoDB
Building Apps with MongoDBBuilding Apps with MongoDB
Building Apps with MongoDBNate Abele
 
PHP, Lithium and MongoDB
PHP, Lithium and MongoDBPHP, Lithium and MongoDB
PHP, Lithium and MongoDBMitch Pirtle
 
Taking PHP To the next level
Taking PHP To the next levelTaking PHP To the next level
Taking PHP To the next levelDavid Coallier
 
Lithium PHP Meetup 0210
Lithium PHP Meetup 0210Lithium PHP Meetup 0210
Lithium PHP Meetup 0210schreck84
 

Andere mochten auch (8)

Measuring Your Code
Measuring Your CodeMeasuring Your Code
Measuring Your Code
 
Measuring Your Code 2.0
Measuring Your Code 2.0Measuring Your Code 2.0
Measuring Your Code 2.0
 
Introducing Zend Studio 10 Japanese Edition
Introducing Zend Studio 10 Japanese EditionIntroducing Zend Studio 10 Japanese Edition
Introducing Zend Studio 10 Japanese Edition
 
Practical PHP 5.3
Practical PHP 5.3Practical PHP 5.3
Practical PHP 5.3
 
Building Apps with MongoDB
Building Apps with MongoDBBuilding Apps with MongoDB
Building Apps with MongoDB
 
PHP, Lithium and MongoDB
PHP, Lithium and MongoDBPHP, Lithium and MongoDB
PHP, Lithium and MongoDB
 
Taking PHP To the next level
Taking PHP To the next levelTaking PHP To the next level
Taking PHP To the next level
 
Lithium PHP Meetup 0210
Lithium PHP Meetup 0210Lithium PHP Meetup 0210
Lithium PHP Meetup 0210
 

Ähnlich wie Lithium: The Framework for People Who Hate Frameworks, Tokyo Edition

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
 
Building Testable PHP Applications
Building Testable PHP ApplicationsBuilding Testable PHP Applications
Building Testable PHP Applicationschartjes
 
SPL: The Missing Link in Development
SPL: The Missing Link in DevelopmentSPL: The Missing Link in Development
SPL: The Missing Link in Developmentjsmith92
 
Php course-in-navimumbai
Php course-in-navimumbaiPhp course-in-navimumbai
Php course-in-navimumbaivibrantuser
 
Dependency injection in Drupal 8
Dependency injection in Drupal 8Dependency injection in Drupal 8
Dependency injection in Drupal 8Alexei Gorobets
 
Preparing for the next PHP version (5.6)
Preparing for the next PHP version (5.6)Preparing for the next PHP version (5.6)
Preparing for the next PHP version (5.6)Damien Seguy
 
Introduction to PHP 5.3
Introduction to PHP 5.3Introduction to PHP 5.3
Introduction to PHP 5.3guestcc91d4
 
The Naked Bundle - Symfony Live London 2014
The Naked Bundle - Symfony Live London 2014The Naked Bundle - Symfony Live London 2014
The Naked Bundle - Symfony Live London 2014Matthias Noback
 
Introducing PHP Latest Updates
Introducing PHP Latest UpdatesIntroducing PHP Latest Updates
Introducing PHP Latest UpdatesIftekhar Eather
 
FFW Gabrovo PMG - PHP OOP Part 3
FFW Gabrovo PMG - PHP OOP Part 3FFW Gabrovo PMG - PHP OOP Part 3
FFW Gabrovo PMG - PHP OOP Part 3Toni Kolev
 
Zend framework 03 - singleton factory data mapper caching logging
Zend framework 03 - singleton factory data mapper caching loggingZend framework 03 - singleton factory data mapper caching logging
Zend framework 03 - singleton factory data mapper caching loggingTricode (part of Dept)
 
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
 
関西PHP勉強会 php5.4つまみぐい
関西PHP勉強会 php5.4つまみぐい関西PHP勉強会 php5.4つまみぐい
関西PHP勉強会 php5.4つまみぐいHisateru Tanaka
 
On secure application of PHP wrappers
On secure application  of PHP wrappersOn secure application  of PHP wrappers
On secure application of PHP wrappersPositive Hack Days
 
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
 
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
 
The Naked Bundle - Symfony Barcelona
The Naked Bundle - Symfony BarcelonaThe Naked Bundle - Symfony Barcelona
The Naked Bundle - Symfony BarcelonaMatthias Noback
 
Modularity and Layered Data Model
Modularity and Layered Data ModelModularity and Layered Data Model
Modularity and Layered Data ModelAttila Jenei
 

Ähnlich wie Lithium: The Framework for People Who Hate Frameworks, Tokyo Edition (20)

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
 
Building Testable PHP Applications
Building Testable PHP ApplicationsBuilding Testable PHP Applications
Building Testable PHP Applications
 
SPL: The Missing Link in Development
SPL: The Missing Link in DevelopmentSPL: The Missing Link in Development
SPL: The Missing Link in Development
 
Php course-in-navimumbai
Php course-in-navimumbaiPhp course-in-navimumbai
Php course-in-navimumbai
 
Dependency injection in Drupal 8
Dependency injection in Drupal 8Dependency injection in Drupal 8
Dependency injection in Drupal 8
 
Preparing for the next PHP version (5.6)
Preparing for the next PHP version (5.6)Preparing for the next PHP version (5.6)
Preparing for the next PHP version (5.6)
 
Introduction to PHP 5.3
Introduction to PHP 5.3Introduction to PHP 5.3
Introduction to PHP 5.3
 
Unittests für Dummies
Unittests für DummiesUnittests für Dummies
Unittests für Dummies
 
The Naked Bundle - Symfony Live London 2014
The Naked Bundle - Symfony Live London 2014The Naked Bundle - Symfony Live London 2014
The Naked Bundle - Symfony Live London 2014
 
Introducing PHP Latest Updates
Introducing PHP Latest UpdatesIntroducing PHP Latest Updates
Introducing PHP Latest Updates
 
FFW Gabrovo PMG - PHP OOP Part 3
FFW Gabrovo PMG - PHP OOP Part 3FFW Gabrovo PMG - PHP OOP Part 3
FFW Gabrovo PMG - PHP OOP Part 3
 
Zend framework 03 - singleton factory data mapper caching logging
Zend framework 03 - singleton factory data mapper caching loggingZend framework 03 - singleton factory data mapper caching logging
Zend framework 03 - singleton factory data mapper caching logging
 
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
 
関西PHP勉強会 php5.4つまみぐい
関西PHP勉強会 php5.4つまみぐい関西PHP勉強会 php5.4つまみぐい
関西PHP勉強会 php5.4つまみぐい
 
On secure application of PHP wrappers
On secure application  of PHP wrappersOn secure application  of PHP wrappers
On secure application of PHP wrappers
 
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...
 
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
 
The Naked Bundle - Symfony Barcelona
The Naked Bundle - Symfony BarcelonaThe Naked Bundle - Symfony Barcelona
The Naked Bundle - Symfony Barcelona
 
Modularity and Layered Data Model
Modularity and Layered Data ModelModularity and Layered Data Model
Modularity and Layered Data Model
 

Kürzlich hochgeladen

From Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationFrom Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationSafe Software
 
Automating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps ScriptAutomating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps Scriptwesley chun
 
Exploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone ProcessorsExploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone Processorsdebabhi2
 
The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024Rafal Los
 
A Call to Action for Generative AI in 2024
A Call to Action for Generative AI in 2024A Call to Action for Generative AI in 2024
A Call to Action for Generative AI in 2024Results
 
A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?Igalia
 
Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...Enterprise Knowledge
 
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdfThe Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdfEnterprise Knowledge
 
Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024The Digital Insurer
 
[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdfhans926745
 
Handwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsHandwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsMaria Levchenko
 
08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking MenDelhi Call girls
 
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Drew Madelung
 
Data Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonData Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonAnna Loughnan Colquhoun
 
Breaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountBreaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountPuma Security, LLC
 
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...Neo4j
 
Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024The Digital Insurer
 
Understanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdfUnderstanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdfUK Journal
 
Histor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slideHistor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slidevu2urc
 
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024The Digital Insurer
 

Kürzlich hochgeladen (20)

From Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationFrom Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
 
Automating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps ScriptAutomating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps Script
 
Exploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone ProcessorsExploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone Processors
 
The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024
 
A Call to Action for Generative AI in 2024
A Call to Action for Generative AI in 2024A Call to Action for Generative AI in 2024
A Call to Action for Generative AI in 2024
 
A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?
 
Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...
 
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdfThe Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
 
Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024
 
[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf
 
Handwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsHandwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed texts
 
08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men
 
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
 
Data Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonData Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt Robison
 
Breaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountBreaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path Mount
 
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
 
Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024
 
Understanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdfUnderstanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdf
 
Histor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slideHistor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slide
 
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
 

Lithium: The Framework for People Who Hate Frameworks, Tokyo Edition

  • 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.
  • 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 well known design patterns.
  • 16. Some patterns only treat the symptoms, instead of the cause.
  • 18. Object dependencies. “The principle of separating configuration from use.”
  • 20. Everyone does it differently.
  • 21. Sometimes in the same framework.
  • 22. Sometimes in the same class.
  • 25. ... but you need to understand what you’re doing.
  • 26. Some patterns were implemented in Java, to solve language problems that PHP just doesn’t have.
  • 27. “Design Patterns In Dynamic Languages” Peter Norvig http://norvig.com/design-patterns/
  • 28. Try this some time...
  • 29.
  • 32. The sun does not revolve around OOP ...nevertheless, it moves. Galileo facing the Roman Inquistion - Cristiano Banti (1857)
  • 34. 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
  • 35. Dependency Injection • Various attempts at making DI work better: • DI Container • Using dynamic nature of PHP to your advantage.
  • 36. Coupling should be in proportion to domain relevance.
  • 38. If... Configure::write('debug', 0); is evil, $this->debug = 0; is the
  • 39.
  • 41. 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 )); // ... } }
  • 42. OO doesn’t make you think (about state).
  • 44. ActiveRecord Data Access Object Unit of Work Dependency Injection Registry Front Controller MVC Value Object Data Mapper Service Layer
  • 46. 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
  • 47. Tools do not mean... ...you can build a house.
  • 49. Lithium tries to suck less.
  • 51. Aspect-Oriented Design • Separation of concerns • Domain classes should not know or care about cross- cutting concerns • Examples: • Caching • Logging • Access Control, etc.
  • 52. Functional Programming • Only possible when functions are first-class citizens • Referential transparency • Functional purity
  • 53. Referential transparency is not... $this date() $_*
  • 54. Referential transparency is not... $this date() $_*
  • 55. These Are Not Design Patterns.
  • 56. Less Suck • Draws on years of experience building web frameworks • PHP 5.3+ only • Doesn’t assume you’re stupid
  • 57. Ways we try to suck less:
  • 59. <?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() { // ... } } ?>
  • 60. 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 = array()) lithiumutilString; use lithiumutilCollection; public function __construct(array $config = array()) class Foo extends lithiumcoreObject { public function __construct(array $config = array()) protected $_classes = array( public function'lithiumstorageCache', = array()) 'cache' => __construct(array $config '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())
  • 61. <?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() { // ... } } ?>
  • 62. <?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 } } ?>
  • 63. <?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)); ?>
  • 64. <?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() { // ... } } ?>
  • 65. <?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() { // ... } } ?>
  • 66. <?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() { // ... } } ?>
  • 67. <?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()); } } } ?> ?>
  • 68. <?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()); } } } ?> ?>
  • 69. <?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() { // ... = $this->_classes['cache']; $cache } $cache::write(__CLASS__, $this->_someGeneratedValue()); } } } ?> ?>
  • 71. Keeps parameter lists short & Makes class APIs more extensible
  • 73. Same idea. But...! Modifies class / object state.
  • 74. Adaptable Auth Cache Catalog Connections Logger Session
  • 75. use lithiumsecurityAuth; Auth::config(array( 'customer' => array( 'adapter' => 'Form', 'model' => 'Customer', 'fields' => array('email', 'password') ) ));
  • 76. use lithiumstorageCache; Cache::config(array( 'local' => array('adapter' => 'Apc'), 'distributed' => array( 'adapter' => 'Memcached', 'servers' => array('127.0.0.1', 11211), ), 'default' => array('adapter' => 'File') ));
  • 77. use lithiumdataConnections; Connections::config(array( 'old' => array( 'type' => 'database', 'adapter' => 'MySql', 'user' => 'bobby_tables', 'password' => '******', 'database' => 'my_app' ), 'new' => array( 'type' => 'MongoDb', 'database' => 'my_app' ) ));
  • 78. use lithiumstorageSession; Session::config(array( 'cookie' => array( 'adapter' => 'Cookie', 'expire' => '+2 days' ), 'default' => array('adapter' => 'Php') ));
  • 80. use lithiumstorageSession; Session::config(array( 'default' => array( 'adapter' => 'MyCustomAdapter', 'expires' => '+2 days', 'custom' => 'Whatever!' ) ));
  • 81. use lithiumstorageSession; Session::config(array( 'default' => array( 'adapter' => 'MyCustomAdapter', 'expires' => '+2 days', 'custom' => 'Whatever!' ) )); public function __construct(array $config = array())
  • 83. use lithiumstorageCache; Cache::config(array( 'default' => array( 'development' => array( 'adapter' => 'Apc' ), 'production' => array( 'adapter' => 'Memcached', 'servers' => array('127.0.0.1', 11211) ) ) ));
  • 84. use lithiumstorageCache; Cache::config(array( 'default' => array( 'development' => array( 'adapter' => 'Apc' ), 'production' => array( 'adapter' => 'Memcached', 'servers' => array('127.0.0.1', 11211) ) ) ));
  • 85. Works identically for all adapters.
  • 86. If you remember nothing else about configuration state...
  • 89. Zoom? • Performance vs. speed of development is a series of trade-offs • Large-scale apps don’t use stock framework infrastructure, and that’s a good thing • A generalized framework will never be as fast as hand-tuned code
  • 90. Zoom! • Choice is good • Use native extensions (PECL) whenever possible. • Don’t like a class? Change it. At runtime. • Profiled at every step of the way with XHProf and XDebug cachegrinds.
  • 92. use appmodelsPost; use lithiumactionResponse; use lithiumnethttpRouter; Router::connect('/frequent_api_call.json', array(), function($request) { return new Response(array( 'type' => 'application/json', 'body' => Post::recent()->to('json') )); });
  • 93. Platform Rackspace Cloud • 256MB ram • Ubuntu Karmic • Apache 2.2.12 • PHP 5.3.1 • Xcache • Siege 2.68 2009-11-26
  • 95. Lithium is a highly flexible framework.
  • 96. Most class dependencies are dynamic. (Our implementation of dependency injection)
  • 97. class Service extends lithiumcoreObject { protected $_classes = array( 'request' => 'lithiumnethttpRequest', 'response' => 'lithiumnethttpResponse', 'socket' => 'lithiumnetsocketContext' ); } $service = new Service(array('classes' => array( 'socket' => 'mycustomSocket' )));
  • 99. Example: Caching & Logging Caching Logging Post::find()
  • 100. Example: Caching & Logging Caching Logging Post::find()
  • 101. 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); });
  • 102. use lithiumanalysisLogger; Post Logger 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); });
  • 103. What about Observer? • Dependent on a centralized publish/ subscribe system • Extra layer of abstraction • Fewer possibilities
  • 104. What about Observer? • Filters are self-contained and attach directly to objects • Direct and intuitive
  • 105. Features: Everything is an adapter. (well, almost)
  • 106. Databases • 1st-class support for document-oriented databases • MongoDB & CouchDB: production ready • Relational databases in beta • Cassandra/Redis/Riak in the works, too
  • 107. <?php $post = Post::create(array( 'title' => ' ', 'body' => ' ' )); $post->save(); $post = Post::find($id); ?> <h2><?=$post->title; ?></h2> <p><?=$post->body; ?></p>
  • 109. This works on... • MongoDB • CouchDB • MySQL • SQLite
  • 110. MongoDB + CouchDB: $post = Post::create(array( 'title' => ' ', 'body' => ' ', 'tags' => array('PHP', 'Japan'), 'author' => array('name' => 'Nate') )); $post->save();
  • 111. MongoDB: $posts = Post::all(array('conditions' => array( 'tags' => array('PHP', 'Japan'), 'author.name' => 'Nate' ))); // Translates to... db.posts.find({ tags : { $in : ['PHP', 'Japan'] }, 'author.name' : 'Nate' })
  • 112. Databases • Adapter based, plugin aware • Will ship with MySQL, SQLite & PostgreSQL • SQL Server support via plugin • Query API
  • 113. The Query API • Flexible data container • Allows each backend data store to only worry about features it implements • Keeps model API separate from backend data sources
  • 114. The Query API $ages = User::all(array( 'group' => 'age', 'reduce' => 'function(obj, prev) { prev.count++; }', 'initial' => array('count' => 0) ));
  • 115. The Query API $query = new Query(array( 'type' => 'read', 'model' => 'appmodelsPost', 'fields' => array('Post.title', 'Post.body'), 'conditions' => array('Post.id' => new Query(array( 'type' => 'read', 'fields' => array('post_id'), 'model' => 'appmodelsTagging', 'conditions' => array('Tag.name' => array('foo', 'bar', 'baz')), ))) ));
  • 116. The Query API • Run simple queries via the Model API • Build your own complex queries with the Query API • Create your own adapter, or drop in a custom query optimizer
  • 118. Plays nice with others • Easily load & use libraries from other frameworks: • Zend Framework, Solar, Symfony, PEAR, etc. • PSR-0 Class-loading standard
  • 119. /* add the trunk */ Libraries::add("Zend", array( "prefix" => "Zend_", "includePath" => true, "bootstrap" => "Loader/Autoloader.php", "loader" => array("Zend_Loader_Autoloader", "autoload"), "transform" => function($class) { return str_replace("_", "/", $class) . ".php"; } )); /* add the incubator */ Libraries::add("Zend_Incubator", array( "prefix" => "Zend_", "includePath" => '/htdocs/libraries/Zend/incubator/library', "transform" => function($class) { return str_replace("_", "/", $class) . ".php"; } ));
  • 120. 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'); } }
  • 121. This has been a presentation by: Nate Abele (@nateabele) Joël Perras (@jperras) http://lithify.me Sucks. But check it out anyway.