SlideShare a Scribd company logo
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.

More Related Content

PDF
The State of Lithium
Nate Abele
 
PDF
Building Lithium Apps
Nate Abele
 
PDF
The Zen of Lithium
Nate Abele
 
PDF
Lithium: The Framework for People Who Hate Frameworks
Nate Abele
 
PDF
The Origin of Lithium
Nate Abele
 
PDF
PHP 5.3 and Lithium: the most rad php framework
G Woo
 
PDF
Dependency Injection IPC 201
Fabien Potencier
 
PDF
Dependency injection-zendcon-2010
Fabien Potencier
 
The State of Lithium
Nate Abele
 
Building Lithium Apps
Nate Abele
 
The Zen of Lithium
Nate Abele
 
Lithium: The Framework for People Who Hate Frameworks
Nate Abele
 
The Origin of Lithium
Nate Abele
 
PHP 5.3 and Lithium: the most rad php framework
G Woo
 
Dependency Injection IPC 201
Fabien Potencier
 
Dependency injection-zendcon-2010
Fabien Potencier
 

What's hot (20)

PDF
Design Patterns avec PHP 5.3, Symfony et Pimple
Hugo Hamon
 
KEY
Lithium Best
Richard McIntyre
 
PDF
Silex meets SOAP & REST
Hugo Hamon
 
PDF
The History of PHPersistence
Hugo Hamon
 
PDF
Dependency injection in PHP 5.3/5.4
Fabien Potencier
 
PDF
Database Design Patterns
Hugo Hamon
 
PDF
Dependency injection - phpday 2010
Fabien Potencier
 
PDF
Symfony2 - WebExpo 2010
Fabien Potencier
 
PDF
Decouple Your Code For Reusability (International PHP Conference / IPC 2008)
Fabien Potencier
 
PDF
Unit and Functional Testing with Symfony2
Fabien Potencier
 
PDF
Dependency Injection with PHP and PHP 5.3
Fabien Potencier
 
ODP
Rich domain model with symfony 2.5 and doctrine 2.5
Leonardo Proietti
 
ODP
Symfony2, creare bundle e valore per il cliente
Leonardo Proietti
 
PDF
Be RESTful (Symfony Camp 2008)
Fabien Potencier
 
PDF
Agile database access with CakePHP 3
José Lorenzo Rodríguez Urdaneta
 
PDF
Doctrine fixtures
Bill Chang
 
PDF
Advanced Querying with CakePHP 3
José Lorenzo Rodríguez Urdaneta
 
PDF
New in cakephp3
markstory
 
PDF
Future of HTTP in CakePHP
markstory
 
PDF
PHP Data Objects
Wez Furlong
 
Design Patterns avec PHP 5.3, Symfony et Pimple
Hugo Hamon
 
Lithium Best
Richard McIntyre
 
Silex meets SOAP & REST
Hugo Hamon
 
The History of PHPersistence
Hugo Hamon
 
Dependency injection in PHP 5.3/5.4
Fabien Potencier
 
Database Design Patterns
Hugo Hamon
 
Dependency injection - phpday 2010
Fabien Potencier
 
Symfony2 - WebExpo 2010
Fabien Potencier
 
Decouple Your Code For Reusability (International PHP Conference / IPC 2008)
Fabien Potencier
 
Unit and Functional Testing with Symfony2
Fabien Potencier
 
Dependency Injection with PHP and PHP 5.3
Fabien Potencier
 
Rich domain model with symfony 2.5 and doctrine 2.5
Leonardo Proietti
 
Symfony2, creare bundle e valore per il cliente
Leonardo Proietti
 
Be RESTful (Symfony Camp 2008)
Fabien Potencier
 
Agile database access with CakePHP 3
José Lorenzo Rodríguez Urdaneta
 
Doctrine fixtures
Bill Chang
 
Advanced Querying with CakePHP 3
José Lorenzo Rodríguez Urdaneta
 
New in cakephp3
markstory
 
Future of HTTP in CakePHP
markstory
 
PHP Data Objects
Wez Furlong
 
Ad

Viewers also liked (7)

PDF
Measuring Your Code
Nate Abele
 
PDF
Measuring Your Code 2.0
Nate Abele
 
PDF
Practical PHP 5.3
Nate Abele
 
PDF
Building Apps with MongoDB
Nate Abele
 
KEY
PHP, Lithium and MongoDB
Mitch Pirtle
 
KEY
Taking PHP To the next level
David Coallier
 
PPT
Lithium PHP Meetup 0210
schreck84
 
Measuring Your Code
Nate Abele
 
Measuring Your Code 2.0
Nate Abele
 
Practical PHP 5.3
Nate Abele
 
Building Apps with MongoDB
Nate Abele
 
PHP, Lithium and MongoDB
Mitch Pirtle
 
Taking PHP To the next level
David Coallier
 
Lithium PHP Meetup 0210
schreck84
 
Ad

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

PDF
All I Need to Know I Learned by Writing My Own Web Framework
Ben Scofield
 
PDF
Building Testable PHP Applications
chartjes
 
PDF
SPL: The Missing Link in Development
jsmith92
 
PPT
Php course-in-navimumbai
vibrantuser
 
PDF
Dependency injection in Drupal 8
Alexei Gorobets
 
PDF
Preparing for the next PHP version (5.6)
Damien Seguy
 
PDF
Introduction to PHP 5.3
guestcc91d4
 
PDF
Unittests für Dummies
Lars Jankowfsky
 
PDF
The Naked Bundle - Symfony Live London 2014
Matthias Noback
 
PPTX
Introducing PHP Latest Updates
Iftekhar Eather
 
PPTX
FFW Gabrovo PMG - PHP OOP Part 3
Toni Kolev
 
PPT
Zend framework 03 - singleton factory data mapper caching logging
Tricode (part of Dept)
 
KEY
Can't Miss Features of PHP 5.3 and 5.4
Jeff Carouth
 
PDF
関西PHP勉強会 php5.4つまみぐい
Hisateru Tanaka
 
PPTX
On secure application of PHP wrappers
Positive Hack Days
 
PDF
Singletons in PHP - Why they are bad and how you can eliminate them from your...
go_oh
 
PDF
international PHP2011_Bastian Feder_The most unknown Parts of PHPUnit
smueller_sandsmedia
 
PDF
Php unit the-mostunknownparts
Bastian Feder
 
PDF
The Naked Bundle - Symfony Barcelona
Matthias Noback
 
PDF
Modularity and Layered Data Model
Attila Jenei
 
All I Need to Know I Learned by Writing My Own Web Framework
Ben Scofield
 
Building Testable PHP Applications
chartjes
 
SPL: The Missing Link in Development
jsmith92
 
Php course-in-navimumbai
vibrantuser
 
Dependency injection in Drupal 8
Alexei Gorobets
 
Preparing for the next PHP version (5.6)
Damien Seguy
 
Introduction to PHP 5.3
guestcc91d4
 
Unittests für Dummies
Lars Jankowfsky
 
The Naked Bundle - Symfony Live London 2014
Matthias Noback
 
Introducing PHP Latest Updates
Iftekhar Eather
 
FFW Gabrovo PMG - PHP OOP Part 3
Toni Kolev
 
Zend framework 03 - singleton factory data mapper caching logging
Tricode (part of Dept)
 
Can't Miss Features of PHP 5.3 and 5.4
Jeff Carouth
 
関西PHP勉強会 php5.4つまみぐい
Hisateru Tanaka
 
On secure application of PHP wrappers
Positive Hack Days
 
Singletons in PHP - Why they are bad and how you can eliminate them from your...
go_oh
 
international PHP2011_Bastian Feder_The most unknown Parts of PHPUnit
smueller_sandsmedia
 
Php unit the-mostunknownparts
Bastian Feder
 
The Naked Bundle - Symfony Barcelona
Matthias Noback
 
Modularity and Layered Data Model
Attila Jenei
 

Recently uploaded (20)

PDF
The Future of Artificial Intelligence (AI)
Mukul
 
PDF
Software Development Methodologies in 2025
KodekX
 
PDF
Tea4chat - another LLM Project by Kerem Atam
a0m0rajab1
 
PDF
Orbitly Pitch Deck|A Mission-Driven Platform for Side Project Collaboration (...
zz41354899
 
PDF
CIFDAQ's Market Wrap : Bears Back in Control?
CIFDAQ
 
PDF
OFFOFFBOX™ – A New Era for African Film | Startup Presentation
ambaicciwalkerbrian
 
PPTX
The-Ethical-Hackers-Imperative-Safeguarding-the-Digital-Frontier.pptx
sujalchauhan1305
 
PDF
Data_Analytics_vs_Data_Science_vs_BI_by_CA_Suvidha_Chaplot.pdf
CA Suvidha Chaplot
 
PDF
MASTERDECK GRAPHSUMMIT SYDNEY (Public).pdf
Neo4j
 
PDF
Responsible AI and AI Ethics - By Sylvester Ebhonu
Sylvester Ebhonu
 
PDF
Using Anchore and DefectDojo to Stand Up Your DevSecOps Function
Anchore
 
PPTX
cloud computing vai.pptx for the project
vaibhavdobariyal79
 
PDF
Trying to figure out MCP by actually building an app from scratch with open s...
Julien SIMON
 
PPTX
IT Runs Better with ThousandEyes AI-driven Assurance
ThousandEyes
 
PDF
How ETL Control Logic Keeps Your Pipelines Safe and Reliable.pdf
Stryv Solutions Pvt. Ltd.
 
PPTX
Agile Chennai 18-19 July 2025 Ideathon | AI Powered Microfinance Literacy Gui...
AgileNetwork
 
PDF
Presentation about Hardware and Software in Computer
snehamodhawadiya
 
PPTX
AI and Robotics for Human Well-being.pptx
JAYMIN SUTHAR
 
PDF
Research-Fundamentals-and-Topic-Development.pdf
ayesha butalia
 
PDF
Get More from Fiori Automation - What’s New, What Works, and What’s Next.pdf
Precisely
 
The Future of Artificial Intelligence (AI)
Mukul
 
Software Development Methodologies in 2025
KodekX
 
Tea4chat - another LLM Project by Kerem Atam
a0m0rajab1
 
Orbitly Pitch Deck|A Mission-Driven Platform for Side Project Collaboration (...
zz41354899
 
CIFDAQ's Market Wrap : Bears Back in Control?
CIFDAQ
 
OFFOFFBOX™ – A New Era for African Film | Startup Presentation
ambaicciwalkerbrian
 
The-Ethical-Hackers-Imperative-Safeguarding-the-Digital-Frontier.pptx
sujalchauhan1305
 
Data_Analytics_vs_Data_Science_vs_BI_by_CA_Suvidha_Chaplot.pdf
CA Suvidha Chaplot
 
MASTERDECK GRAPHSUMMIT SYDNEY (Public).pdf
Neo4j
 
Responsible AI and AI Ethics - By Sylvester Ebhonu
Sylvester Ebhonu
 
Using Anchore and DefectDojo to Stand Up Your DevSecOps Function
Anchore
 
cloud computing vai.pptx for the project
vaibhavdobariyal79
 
Trying to figure out MCP by actually building an app from scratch with open s...
Julien SIMON
 
IT Runs Better with ThousandEyes AI-driven Assurance
ThousandEyes
 
How ETL Control Logic Keeps Your Pipelines Safe and Reliable.pdf
Stryv Solutions Pvt. Ltd.
 
Agile Chennai 18-19 July 2025 Ideathon | AI Powered Microfinance Literacy Gui...
AgileNetwork
 
Presentation about Hardware and Software in Computer
snehamodhawadiya
 
AI and Robotics for Human Well-being.pptx
JAYMIN SUTHAR
 
Research-Fundamentals-and-Topic-Development.pdf
ayesha butalia
 
Get More from Fiori Automation - What’s New, What Works, and What’s Next.pdf
Precisely
 

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.