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

Nate Abele
Nate AbeleCEO & Co-Founder at Union of RAD, LLC (@radify)
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.
Lithium: The Framework for People Who Hate Frameworks, Tokyo Edition
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...
Lithium: The Framework for People Who Hate Frameworks, Tokyo Edition
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
Lithium: The Framework for People Who Hate Frameworks, Tokyo Edition
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.
1 of 121

Recommended

The State of Lithium by
The State of LithiumThe State of Lithium
The State of LithiumNate Abele
2.3K views32 slides
Building Lithium Apps by
Building Lithium AppsBuilding Lithium Apps
Building Lithium AppsNate Abele
5.7K views57 slides
The Zen of Lithium by
The Zen of LithiumThe Zen of Lithium
The Zen of LithiumNate Abele
2.6K views118 slides
Lithium: The Framework for People Who Hate Frameworks by
Lithium: The Framework for People Who Hate FrameworksLithium: The Framework for People Who Hate Frameworks
Lithium: The Framework for People Who Hate FrameworksNate Abele
12.2K views123 slides
The Origin of Lithium by
The Origin of LithiumThe Origin of Lithium
The Origin of LithiumNate Abele
8.4K views22 slides
PHP 5.3 and Lithium: the most rad php framework by
PHP 5.3 and Lithium: the most rad php frameworkPHP 5.3 and Lithium: the most rad php framework
PHP 5.3 and Lithium: the most rad php frameworkG Woo
5.9K views58 slides

More Related Content

What's hot

Design Patterns avec PHP 5.3, Symfony et Pimple by
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
6.1K views68 slides
Lithium Best by
Lithium Best Lithium Best
Lithium Best Richard McIntyre
1.8K views129 slides
Silex meets SOAP & REST by
Silex meets SOAP & RESTSilex meets SOAP & REST
Silex meets SOAP & RESTHugo Hamon
14.8K views62 slides
The History of PHPersistence by
The History of PHPersistenceThe History of PHPersistence
The History of PHPersistenceHugo Hamon
2.3K views75 slides
Dependency injection in PHP 5.3/5.4 by
Dependency injection in PHP 5.3/5.4Dependency injection in PHP 5.3/5.4
Dependency injection in PHP 5.3/5.4Fabien Potencier
37.4K views114 slides
Database Design Patterns by
Database Design PatternsDatabase Design Patterns
Database Design PatternsHugo Hamon
11.4K views87 slides

What's hot(20)

Design Patterns avec PHP 5.3, Symfony et Pimple by Hugo Hamon
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
Hugo Hamon6.1K views
Silex meets SOAP & REST by Hugo Hamon
Silex meets SOAP & RESTSilex meets SOAP & REST
Silex meets SOAP & REST
Hugo Hamon14.8K views
The History of PHPersistence by Hugo Hamon
The History of PHPersistenceThe History of PHPersistence
The History of PHPersistence
Hugo Hamon2.3K views
Dependency injection in PHP 5.3/5.4 by Fabien Potencier
Dependency injection in PHP 5.3/5.4Dependency injection in PHP 5.3/5.4
Dependency injection in PHP 5.3/5.4
Fabien Potencier37.4K views
Database Design Patterns by Hugo Hamon
Database Design PatternsDatabase Design Patterns
Database Design Patterns
Hugo Hamon11.4K views
Dependency injection - phpday 2010 by Fabien Potencier
Dependency injection - phpday 2010Dependency injection - phpday 2010
Dependency injection - phpday 2010
Fabien Potencier4.3K views
Decouple Your Code For Reusability (International PHP Conference / IPC 2008) by Fabien 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)
Fabien Potencier4.2K views
Unit and Functional Testing with Symfony2 by Fabien Potencier
Unit and Functional Testing with Symfony2Unit and Functional Testing with Symfony2
Unit and Functional Testing with Symfony2
Fabien Potencier20.4K views
Dependency Injection with PHP and PHP 5.3 by Fabien Potencier
Dependency Injection with PHP and PHP 5.3Dependency Injection with PHP and PHP 5.3
Dependency Injection with PHP and PHP 5.3
Fabien Potencier15.4K views
Rich domain model with symfony 2.5 and doctrine 2.5 by Leonardo Proietti
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
Leonardo Proietti12K views
Symfony2, creare bundle e valore per il cliente by Leonardo Proietti
Symfony2, creare bundle e valore per il clienteSymfony2, creare bundle e valore per il cliente
Symfony2, creare bundle e valore per il cliente
Leonardo Proietti1.3K views
Doctrine fixtures by Bill Chang
Doctrine fixturesDoctrine fixtures
Doctrine fixtures
Bill Chang5K views
New in cakephp3 by markstory
New in cakephp3New in cakephp3
New in cakephp3
markstory2.1K views
Future of HTTP in CakePHP by markstory
Future of HTTP in CakePHPFuture of HTTP in CakePHP
Future of HTTP in CakePHP
markstory4.3K views
PHP Data Objects by Wez Furlong
PHP Data ObjectsPHP Data Objects
PHP Data Objects
Wez Furlong10.4K views

Viewers also liked

Measuring Your Code by
Measuring Your CodeMeasuring Your Code
Measuring Your CodeNate Abele
10 views60 slides
Measuring Your Code 2.0 by
Measuring Your Code 2.0Measuring Your Code 2.0
Measuring Your Code 2.0Nate Abele
1.4K views60 slides
Introducing Zend Studio 10 Japanese Edition by
Introducing Zend Studio 10 Japanese EditionIntroducing Zend Studio 10 Japanese Edition
Introducing Zend Studio 10 Japanese EditionSatoru Yoshida
1K views23 slides
Practical PHP 5.3 by
Practical PHP 5.3Practical PHP 5.3
Practical PHP 5.3Nate Abele
7K views48 slides
Building Apps with MongoDB by
Building Apps with MongoDBBuilding Apps with MongoDB
Building Apps with MongoDBNate Abele
9.3K views53 slides
PHP, Lithium and MongoDB by
PHP, Lithium and MongoDBPHP, Lithium and MongoDB
PHP, Lithium and MongoDBMitch Pirtle
4.7K views31 slides

Viewers also liked(8)

Measuring Your Code by Nate Abele
Measuring Your CodeMeasuring Your Code
Measuring Your Code
Nate Abele10 views
Measuring Your Code 2.0 by Nate Abele
Measuring Your Code 2.0Measuring Your Code 2.0
Measuring Your Code 2.0
Nate Abele1.4K views
Introducing Zend Studio 10 Japanese Edition by Satoru Yoshida
Introducing Zend Studio 10 Japanese EditionIntroducing Zend Studio 10 Japanese Edition
Introducing Zend Studio 10 Japanese Edition
Satoru Yoshida1K views
Practical PHP 5.3 by Nate Abele
Practical PHP 5.3Practical PHP 5.3
Practical PHP 5.3
Nate Abele7K views
Building Apps with MongoDB by Nate Abele
Building Apps with MongoDBBuilding Apps with MongoDB
Building Apps with MongoDB
Nate Abele9.3K views
PHP, Lithium and MongoDB by Mitch Pirtle
PHP, Lithium and MongoDBPHP, Lithium and MongoDB
PHP, Lithium and MongoDB
Mitch Pirtle4.7K views
Taking PHP To the next level by David Coallier
Taking PHP To the next levelTaking PHP To the next level
Taking PHP To the next level
David Coallier793 views
Lithium PHP Meetup 0210 by schreck84
Lithium PHP Meetup 0210Lithium PHP Meetup 0210
Lithium PHP Meetup 0210
schreck84343 views

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

All I Need to Know I Learned by Writing My Own Web Framework by
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
13K views71 slides
Building Testable PHP Applications by
Building Testable PHP ApplicationsBuilding Testable PHP Applications
Building Testable PHP Applicationschartjes
7.4K views90 slides
SPL: The Missing Link in Development by
SPL: The Missing Link in DevelopmentSPL: The Missing Link in Development
SPL: The Missing Link in Developmentjsmith92
733 views44 slides
Php course-in-navimumbai by
Php course-in-navimumbaiPhp course-in-navimumbai
Php course-in-navimumbaivibrantuser
84 views28 slides
Dependency injection in Drupal 8 by
Dependency injection in Drupal 8Dependency injection in Drupal 8
Dependency injection in Drupal 8Alexei Gorobets
3.8K views57 slides
Preparing for the next PHP version (5.6) by
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
1.2K views41 slides

Similar to Lithium: The Framework for People Who Hate Frameworks, Tokyo Edition(20)

All I Need to Know I Learned by Writing My Own Web Framework by Ben Scofield
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
Ben Scofield13K views
Building Testable PHP Applications by chartjes
Building Testable PHP ApplicationsBuilding Testable PHP Applications
Building Testable PHP Applications
chartjes7.4K views
SPL: The Missing Link in Development by jsmith92
SPL: The Missing Link in DevelopmentSPL: The Missing Link in Development
SPL: The Missing Link in Development
jsmith92733 views
Php course-in-navimumbai by vibrantuser
Php course-in-navimumbaiPhp course-in-navimumbai
Php course-in-navimumbai
vibrantuser84 views
Dependency injection in Drupal 8 by Alexei Gorobets
Dependency injection in Drupal 8Dependency injection in Drupal 8
Dependency injection in Drupal 8
Alexei Gorobets3.8K views
Preparing for the next PHP version (5.6) by Damien Seguy
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 Seguy1.2K views
Introduction to PHP 5.3 by guestcc91d4
Introduction to PHP 5.3Introduction to PHP 5.3
Introduction to PHP 5.3
guestcc91d43.5K views
The Naked Bundle - Symfony Live London 2014 by Matthias Noback
The Naked Bundle - Symfony Live London 2014The Naked Bundle - Symfony Live London 2014
The Naked Bundle - Symfony Live London 2014
Matthias Noback4K views
Introducing PHP Latest Updates by Iftekhar Eather
Introducing PHP Latest UpdatesIntroducing PHP Latest Updates
Introducing PHP Latest Updates
Iftekhar Eather1.3K views
FFW Gabrovo PMG - PHP OOP Part 3 by Toni Kolev
FFW Gabrovo PMG - PHP OOP Part 3FFW Gabrovo PMG - PHP OOP Part 3
FFW Gabrovo PMG - PHP OOP Part 3
Toni Kolev265 views
Zend framework 03 - singleton factory data mapper caching logging by Tricode (part of Dept)
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 by Jeff Carouth
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
Jeff Carouth3.1K views
関西PHP勉強会 php5.4つまみぐい by Hisateru Tanaka
関西PHP勉強会 php5.4つまみぐい関西PHP勉強会 php5.4つまみぐい
関西PHP勉強会 php5.4つまみぐい
Hisateru Tanaka2.6K views
Singletons in PHP - Why they are bad and how you can eliminate them from your... by go_oh
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_oh43.5K views
international PHP2011_Bastian Feder_The most unknown Parts of PHPUnit by smueller_sandsmedia
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
Php unit the-mostunknownparts by Bastian Feder
Php unit the-mostunknownpartsPhp unit the-mostunknownparts
Php unit the-mostunknownparts
Bastian Feder1.6K views
The Naked Bundle - Symfony Barcelona by Matthias Noback
The Naked Bundle - Symfony BarcelonaThe Naked Bundle - Symfony Barcelona
The Naked Bundle - Symfony Barcelona
Matthias Noback3.3K views
Modularity and Layered Data Model by Attila Jenei
Modularity and Layered Data ModelModularity and Layered Data Model
Modularity and Layered Data Model
Attila Jenei1K views

Recently uploaded

Beyond the Hype: What Generative AI Means for the Future of Work - Damien Cum... by
Beyond the Hype: What Generative AI Means for the Future of Work - Damien Cum...Beyond the Hype: What Generative AI Means for the Future of Work - Damien Cum...
Beyond the Hype: What Generative AI Means for the Future of Work - Damien Cum...NUS-ISS
34 views35 slides
Tunable Laser (1).pptx by
Tunable Laser (1).pptxTunable Laser (1).pptx
Tunable Laser (1).pptxHajira Mahmood
23 views37 slides
The Research Portal of Catalonia: Growing more (information) & more (services) by
The Research Portal of Catalonia: Growing more (information) & more (services)The Research Portal of Catalonia: Growing more (information) & more (services)
The Research Portal of Catalonia: Growing more (information) & more (services)CSUC - Consorci de Serveis Universitaris de Catalunya
73 views25 slides
Top 10 Strategic Technologies in 2024: AI and Automation by
Top 10 Strategic Technologies in 2024: AI and AutomationTop 10 Strategic Technologies in 2024: AI and Automation
Top 10 Strategic Technologies in 2024: AI and AutomationAutomationEdge Technologies
14 views14 slides
Voice Logger - Telephony Integration Solution at Aegis by
Voice Logger - Telephony Integration Solution at AegisVoice Logger - Telephony Integration Solution at Aegis
Voice Logger - Telephony Integration Solution at AegisNirmal Sharma
17 views1 slide
Throughput by
ThroughputThroughput
ThroughputMoisés Armani Ramírez
36 views11 slides

Recently uploaded(20)

Beyond the Hype: What Generative AI Means for the Future of Work - Damien Cum... by NUS-ISS
Beyond the Hype: What Generative AI Means for the Future of Work - Damien Cum...Beyond the Hype: What Generative AI Means for the Future of Work - Damien Cum...
Beyond the Hype: What Generative AI Means for the Future of Work - Damien Cum...
NUS-ISS34 views
Voice Logger - Telephony Integration Solution at Aegis by Nirmal Sharma
Voice Logger - Telephony Integration Solution at AegisVoice Logger - Telephony Integration Solution at Aegis
Voice Logger - Telephony Integration Solution at Aegis
Nirmal Sharma17 views
Attacking IoT Devices from a Web Perspective - Linux Day by Simone Onofri
Attacking IoT Devices from a Web Perspective - Linux Day Attacking IoT Devices from a Web Perspective - Linux Day
Attacking IoT Devices from a Web Perspective - Linux Day
Simone Onofri15 views
Web Dev - 1 PPT.pdf by gdsczhcet
Web Dev - 1 PPT.pdfWeb Dev - 1 PPT.pdf
Web Dev - 1 PPT.pdf
gdsczhcet55 views
Upskilling the Evolving Workforce with Digital Fluency for Tomorrow's Challen... by NUS-ISS
Upskilling the Evolving Workforce with Digital Fluency for Tomorrow's Challen...Upskilling the Evolving Workforce with Digital Fluency for Tomorrow's Challen...
Upskilling the Evolving Workforce with Digital Fluency for Tomorrow's Challen...
NUS-ISS28 views
Combining Orchestration and Choreography for a Clean Architecture by ThomasHeinrichs1
Combining Orchestration and Choreography for a Clean ArchitectureCombining Orchestration and Choreography for a Clean Architecture
Combining Orchestration and Choreography for a Clean Architecture
ThomasHeinrichs169 views
TouchLog: Finger Micro Gesture Recognition Using Photo-Reflective Sensors by sugiuralab
TouchLog: Finger Micro Gesture Recognition  Using Photo-Reflective SensorsTouchLog: Finger Micro Gesture Recognition  Using Photo-Reflective Sensors
TouchLog: Finger Micro Gesture Recognition Using Photo-Reflective Sensors
sugiuralab15 views
AI: mind, matter, meaning, metaphors, being, becoming, life values by Twain Liu 刘秋艳
AI: mind, matter, meaning, metaphors, being, becoming, life valuesAI: mind, matter, meaning, metaphors, being, becoming, life values
AI: mind, matter, meaning, metaphors, being, becoming, life values
RADIUS-Omnichannel Interaction System by RADIUS
RADIUS-Omnichannel Interaction SystemRADIUS-Omnichannel Interaction System
RADIUS-Omnichannel Interaction System
RADIUS15 views
Five Things You SHOULD Know About Postman by Postman
Five Things You SHOULD Know About PostmanFive Things You SHOULD Know About Postman
Five Things You SHOULD Know About Postman
Postman27 views
Perth MeetUp November 2023 by Michael Price
Perth MeetUp November 2023 Perth MeetUp November 2023
Perth MeetUp November 2023
Michael Price15 views
handbook for web 3 adoption.pdf by Liveplex
handbook for web 3 adoption.pdfhandbook for web 3 adoption.pdf
handbook for web 3 adoption.pdf
Liveplex19 views
Digital Product-Centric Enterprise and Enterprise Architecture - Tan Eng Tsze by NUS-ISS
Digital Product-Centric Enterprise and Enterprise Architecture - Tan Eng TszeDigital Product-Centric Enterprise and Enterprise Architecture - Tan Eng Tsze
Digital Product-Centric Enterprise and Enterprise Architecture - Tan Eng Tsze
NUS-ISS19 views

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:
  • 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...
  • 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
  • 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.