php 5.3 and lithium: the most rad php framework
DESCRIPTION
Presentation given to the Orange County PHP meetup on Feb 24 2010. The presentation covers the new features in php 5.3 and goes on to show how they are used in Lithium, the most rad php framework.TRANSCRIPT
Wednesday, February 24, 2010
PHP 5.3
Wednesday, February 24, 2010
Why?• Speed & Memory
• Namespaces
• Anonymous Functions
• Late Static Binding
• Syntax enhancements
• SPL
• Phar
• ext/intl
• ext/fileinfo
• ext/sqlite3
• mysqlnd
Wednesday, February 24, 2010
Speed & Memory
http://sebastian-bergmann.de/archives/745-Benchmark-of-PHP-Branches-3.0-through-5.3-CVS.html
Drupal 20% fasterQdig 2% fastertypo3 30% fasterwordpress 15% fasterxoops 10% fasterhttp://news.php.net/php.internals/36484
gc_enable() : New Garbage Collector
Wednesday, February 24, 2010
Namespaces
• Autoloading made easy
• \lithium\core\Libraries
• \li3_docs\controllers\BrowserController
• http://groups.google.com/group/php-standards/web/psr-0-final-proposal
http://php.net/manual/en/language.namespaces.php
Wednesday, February 24, 2010
Namespaces Example
<?php
namespace app;
use \app\models\Post;
class PostsController extends \lithium\action\Controller {
public function index() { $posts = Post::all(); return compact(‘posts’); }}
?>
Wednesday, February 24, 2010
<?php
function __autoload($className){ $className = ltrim($className, '\\'); $fileName = ''; $namespace = ''; if ($lastNsPos = strripos($className, '\\')) { $namespace = substr($className, 0, $lastNsPos); $className = substr($className, $lastNsPos + 1); $fileName = str_replace('\\', DIRECTORY_SEPARATOR, $namespace) . DIRECTORY_SEPARATOR; } $fileName .= str_replace('_', DIRECTORY_SEPARATOR, $className) . '.php';
require $fileName;}
?>
http://groups.google.com/group/php-standards/web/psr-0-final-proposalAutoloading
Wednesday, February 24, 2010
Anonymous Functions
• Lambda• assigned to a variable
• useful for recursion and multiple calls
• Closure• added as a method parameter
• use() the parent scope
http://php.net/manual/en/functions.anonymous.php
Wednesday, February 24, 2010
Lambda Example<?php
$cube = function ($value) { return ($value * $value * $value);};$result = array_map($cube, array(1, 2, 3));var_dump($result);/*array 0 => int 1 1 => int 8 2 => int 27*/
?>
Wednesday, February 24, 2010
Another Lambda
$multiply = function ($value, $times) use (&$multiply) { return ($times > 0) ? $multiply($value * $value, --$times) : $value;};var_dump($multiply(2, 3));/*int 256*/
Wednesday, February 24, 2010
Closure Example<?php$data = 'string';$result = array_filter(array(1, 2, 'string'), function ($value) use ($data) { return ($value !== $data);});var_dump($result);/*array 0 => int 1 1 => int 2*/
?>
Wednesday, February 24, 2010
Crazy Example<?php
function Y($F) { return current(array(function($f) { return $f($f); }))->__invoke(function($f) use ($F) { return $F(function($x) use ($f) { return $f($f)->__invoke($x); }); });}
$factorial = Y(function($fact) { return function($n) use ($fact) { return ($n <= 1) ? 1 : $n * $fact($n - 1); };});
var_dump($factorial(6));/*int 720*/
?>
Wednesday, February 24, 2010
Why Static?
• Promotes proper application design
• Stateless
• Easier to access
Wednesday, February 24, 2010
Late Static Binding<?phpclass A { public static function who() { return __CLASS__; } public static function test() { return static::who(); }}class B extends A { public static function who() { return __CLASS__; }}
$result = B::test();var_dump($result);/*string 'B' (length=1)*/
http://php.net/lsb
Wednesday, February 24, 2010
Standard PHP Library (SPL)
• spl_autoload_register()
• Iterators
• Exceptions
• File Handling
• Observer/Subject
• Stack, Queue, Heap, ObjectStorage
http://us.php.net/manual/en/book.spl.php
Wednesday, February 24, 2010
Syntax Enhancements
• PHP 5 < 5.3
• __set()/__get()
• __isset()/__unset()
• __call()
• PHP 5.3
• __callStatic()
• __invoke()
• ?:
http://php.net/manual/en/language.oop5.magic.php
Wednesday, February 24, 2010
Phar
• PHP archives
• includable (include 'phar:///path/to/myphar.phar/file.php')
• stream accessible
• distributable
Wednesday, February 24, 2010
ext/intl
• Collator
• Locale
• IntlDateFormatter
• NumberFormatter
Wednesday, February 24, 2010
ext/fileinfo <?php
$info = new \finfo(FILEINFO_MIME);$result = $info->file(__FILE__);var_dump($result);/*string 'text/x-php; charset=us-ascii' (length=28)*/
$result = finfo_file(finfo_open(FILEINFO_MIME), __FILE__);var_dump($result);/*string 'text/x-php; charset=us-ascii' (length=28)*/?>
Wednesday, February 24, 2010
ext/sqlite3• SQLite is a in-process library that implements a
self-contained, serverless, zero-configuration, transactional SQL database engine (http://www.sqlite.org/about.html)
• A more compact format for database files.
• Support for both UTF-8 and UTF-16 text.
• Manifest typing and BLOB support.
• New API via Sqlite3 class or sqlite3 functions
Wednesday, February 24, 2010
mysqlnd
• mysql native driver
• faster
• easier to compile
• transparent client, same old mysql/mysqli
Wednesday, February 24, 2010
Lithiumthe most rad php framework
Wednesday, February 24, 2010
In Lithium• Namespaces
• Anonymous Functions
• Late Static Binding
• Syntax Enhancements
• SPL
• Phar
• Sqlite3
Wednesday, February 24, 2010
Lithium Namespaces• action
• analysis
• console
• core
• g11n
• net
• security
• storage
• template
• test
• tests
• util
Wednesday, February 24, 2010
Namespace Example
<?php
namespace app\extensions\helper;
class Form extends \lithium\template\helper\Form {
public function config(array $config = array()) { .... }}
Wednesday, February 24, 2010
Anonymous Functions Example
<?php
Validator::add('role', function ($value, $format, $options) { return (in_array($value, array('admin', 'editor', 'user')));});
?>
Wednesday, February 24, 2010
LSB Example<?php
namespace lithium\core;
class StaticObject { ...}
?><?php
namespace lithium\data;
class Model extends \lithium\core\StaticObject { ...}
?> <?php
namespace app\models;
class Post extends \lithium\data\Model {
}
?>
Wednesday, February 24, 2010
__callStatic<?php
namespace lithium\data;
class Model extends \lithium\core\StaticObject {
public static function __callStatic($method, $params) { ... }
?> <?php
namespace app\controllers
use app\models\Post;
class PostsController extends \lithium\action\Controller {
public function index() { $posts = Post::all(); return compact('posts') }}
?>
Wednesday, February 24, 2010
__invoke<?php
namespace lithium\action;
class Controller extends lithium\core\Object {
public function __invoke($request, $dispatchParams, array $options = array()) { ... }
}?>
<?php
namespace lithium\action;
class Dispatcher extends \lithium\core\StaticObject {
protected static function _call($callable, $request, $params) { ... if (is_callable($callable = $params['callable'])) { return $callable($params['request'], $params['params']); } throw new Exception('Result not callable'); ... }}?>
Wednesday, February 24, 2010
SPL Iterators<?php
protected function _cleanUp($path = null) { $path = $path ?: LITHIUM_APP_PATH . '/resources/tmp/tests'; $path = $path[0] !== '/' ? LITHIUM_APP_PATH . '/resources/tmp/' . $path : $path; if (!is_dir($path)) { return; } $dirs = new RecursiveDirectoryIterator($path); $iterator = new RecursiveIteratorIterator($dirs, RecursiveIteratorIterator::CHILD_FIRST); foreach ($iterator as $item) { if ($item->getPathname() === "{$path}/empty") continue; ($item->isDir()) ? rmdir($item->getPathname()) : unlink($item->getPathname()); }}
?>
Wednesday, February 24, 2010
SPL Interfaces
<?php/* * @link http://us.php.net/manual/en/class.arrayaccess.php * @link http://us.php.net/manual/en/class.iterator.php * @link http://us.php.net/manual/en/class.countable.php */class Collection extends \lithium\core\Object implements \ArrayAccess, \Iterator, \Countable { ...}
?>
Wednesday, February 24, 2010
SPL autoloader<?php
namespace lithium\core;
class Libraries { ... public static function add($name, $config = array()) { ... if (!empty($config['loader'])) { spl_autoload_register($config['loader']); } ... } ...}?>
Wednesday, February 24, 2010
Phar<?php
namespace lithium\console\command;
use \Phar;
class Library extends \lithium\console\Command {
public function archive() { ....
$archive = new Phar("{$path}.phar"); $from = $this->_toPath($from); $result = (boolean) $archive->buildFromDirectory($from, $this->filter); ...
$archive->compress(Phar::GZ); return true; }}
?>
Wednesday, February 24, 2010
Sqlite3
<?php
Connections::add('default', array( 'type' => 'database', 'adapter' => 'Sqlite3', 'database' => LITHIUM_APP_PATH . '/resources/db/sqlite.db'));
?>
Wednesday, February 24, 2010
By Lithium
• Simple, Uniform API
• Unified Constructor
• Adaptable
• Filters (Aspect Oriented Programming)
• $_classes (Dependency Injection)
• Collections
Wednesday, February 24, 2010
Simple Uniform API
• logical namespaces and classes
• simple method names
• <= 3 params per method
• $config
• $options
Wednesday, February 24, 2010
Unified Constructor
• $config
• always an array
• check for $_autoConfig
• _init() and __init()
Wednesday, February 24, 2010
Adaptable• \security\Auth
• \storage\Session
• \storage\Cache
• \g11n\Catalog
• \data\Connections
• \analysis\Logger
Wednesday, February 24, 2010
Filters• Aspect Oriented Programming
secondary or supporting functions are isolated from the main program's business logic...increase modularity by allowing the separation of cross-cutting concerns... (http://en.wikipedia.org/wiki/Aspect-oriented_programming)
• modify core functionality without extending a class
• define your own callbacks
• @filter
Wednesday, February 24, 2010
Routes Filter<?php
use \lithium\action\Dispatcher;
Dispatcher::applyFilter('run', function($self, $params, $chain) { include __DIR__ . '/routes.php'; return $chain->next($self, $params, $chain);});
?>
Wednesday, February 24, 2010
Asset Filter<?php
use \lithium\action\Dispatcher;use \lithium\core\Libraries;use \lithium\net\http\Media;
Dispatcher::applyFilter('_callable', function($self, $params, $chain) { list($plugin, $asset) = explode('/', $params['request']->url, 2) + array("", ""); if ($asset && $library = Libraries::get($plugin)) { $asset = "{$library['path']}/webroot/{$asset}";
if (file_exists($asset)) { return function () use ($asset) { $info = pathinfo($asset); $type = Media::type($info['extension']); header("Content-type: {$type['content']}"); return file_get_contents($asset); }; } } return $chain->next($self, $params, $chain);});
?>
Wednesday, February 24, 2010
Xhprof Filter<?php
use \lithium\action\Dispatcher;
Dispatcher::applyFilter('run', function($self, $params, $chain) { xhprof_enable(); $data = $chain->next($self, $params, $chain); $xhprof_data = xhprof_disable();
$XHPROF_ROOT = '/usr/local/php/5.3.1/lib/xhprof'; include_once $XHPROF_ROOT . "/xhprof_lib/utils/xhprof_lib.php"; include_once $XHPROF_ROOT . "/xhprof_lib/utils/xhprof_runs.php";
$xhprof_runs = new XHProfRuns_Default(); $run_id = $xhprof_runs->save_run($xhprof_data, "xhprof_lithium");
return $data;});
?>
Wednesday, February 24, 2010
Save Filter<?php
namespace app\models;
class Paste extends \lithium\data\Model {
public static function __init(array $options = array()) { parent::__init($options); static::applyFilter('save', function($self, $params, $chain) { $document = $params['record']; if (!$document->id) { $document->created = date('Y-m-d h:i:s'); } if (!empty($params['data'])) { $document->set($params['data']); } $document->parsed = $self::parse($document->content, $document->language); $document->preview = substr($document->content, 0, 100); $document->modified = date('Y-m-d h:i:s'); $params['record'] = $document; return $chain->next($self, $params, $chain); }); }}
?>
Wednesday, February 24, 2010
$_classes
• Dependency Injectiona technique for supplying an external dependency (i.e. a reference) to a software component - that is, indicating to a part of a program which other parts it can use... (http://en.wikipedia.org/wiki/Dependency_injection)
• modify core functionality without extending a class
Wednesday, February 24, 2010
$_classes Example
<?php
namespace lithium\console;
class Library extends \lithium\console\Command { ... protected $_classes = array( 'service' => '\lithium\net\http\Service', 'response' => '\lithium\console\Response' ); ...}?>
Wednesday, February 24, 2010
$_classes Example<?phpnamespace lithium\tests\cases\console;
use \lithium\console\Request;
class LibraryTest extends \lithium\test\Unit { ... public function setUp() { ... $this->classes = array( 'service' => '\lithium\tests\mocks\console\command\MockLibraryService', 'response' => '\lithium\tests\mocks\console\MockResponse' ); ... } ... public function testArchiveNoLibrary() { ... $app = new Library(array( 'request' => new Request(), 'classes' => $this->classes )); $expected = true; $result = $app->archive(); $this->assertEqual($expected, $result); } ...}?>
Wednesday, February 24, 2010
Collections
• lithium\util\Collection
• lithium\data\Collection
• lithium\data\collection\RecordSet
• lithium\data\collection\Document
• lithium\test\Group
Wednesday, February 24, 2010
Collections Example<?php
use \lithium\util\Collection;
$coll = new Collection(array('items' => array(0, 1, 2, 3, 4)));$coll->first(); // 1 (the first non-empty value)$coll->current(); // 0$coll->next(); // 1$coll->next(); // 2$coll->next(); // 3$coll->prev(); // 2$coll->rewind(); // 0$coll->each(function($value) { return $value + 1;});$coll->to('array'); // array(1, 2, 3, 4, 5)
?>
<?php
use \lithium\test\Group;
$group = new Group(array('items' => array( 'lithium\tests\cases\core\Libraries', 'lithium\tests\cases\core\Object',))$resul = $group->tests()->run();
?>
Wednesday, February 24, 2010
More Lithium
• Integrated Test Suite for fast TDD
• Command Line Framework
• Document Based Data Sources
• Object based Record Sets with access to non static model methods
• Transparent content type rendering
Wednesday, February 24, 2010
Still More Lithium
• Automatic output escaping
• Http Services
• g11n for internationalized applications
• Authentication
• Session/Cookie Handling
• Authorization (1.0)
Wednesday, February 24, 2010
Even More Lithium
• Validator
• Logging
• Debugger
• Parser
• Inspector
• Sockets
Wednesday, February 24, 2010
Lithium Integrations
• Use 3rd party libraries
• Easy to add with Libraries class
• Especially simple when PSR-0 is followed
• Access classes in a standard way
Wednesday, February 24, 2010
Using Zendhttp://rad-dev.org/lithium/wiki/guides/using/zend
<?php
Libraries::add("Zend", array( "prefix" => "Zend_", 'path' => '/htdocs/libraries/Zend/trunk/library/Zend', "includePath" => '/htdocs/libraries/Zend/trunk/library', "bootstrap" => "Loader/Autoloader.php", "loader" => array("Zend_Loader_Autoloader", "autoload"), "transform" => function($class) { return str_replace("_", "/", $class) . ".php"; }));
?><?php
namespace app\controllers;
use \Zend_Mail_Storage_Pop3;
class EmailController extends \lithium\action\Controller {
public function index() { $mail = new Zend_Mail_Storage_Pop3(array( 'host' => 'localhost', 'user' => 'test', 'password' => 'test' )); return compact('mail'); }}
?>
Wednesday, February 24, 2010
Plugins
• namespaces allow for a true plugin system
• modify application with filters
• add extensions
• share your handy work
Wednesday, February 24, 2010
Some Plugins
• li3_docs
• li3_oauth
• li3_bot
• li3_doctrine
• li3_lab
Wednesday, February 24, 2010
Wednesday, February 24, 2010
lithium_qa
• http://rad-dev.org/lithium/wiki/standards
• Check syntax of your code
• Shows rules violations in your code
• Automate the process with SCM hooks
Wednesday, February 24, 2010
Lithium
• http://lithify.me
• http://rad-dev.org/lithium/wiki
• http://www.ohloh.net/p/lithium
• http://twitter.com/UnionOfRAD
• irc://irc.freenode.net/#li3
• http://search.twitter.com/search?q=%23li3
the most rad php framework
Wednesday, February 24, 2010