Decoupled Library Packages for PHP 5.4
-
Upload
pmjones88 -
Category
Technology
-
view
6.036 -
download
1
description
Transcript of Decoupled Library Packages for PHP 5.4
![Page 1: Decoupled Library Packages for PHP 5.4](https://reader034.fdocuments.net/reader034/viewer/2022051817/54923184ac795916288b46f0/html5/thumbnails/1.jpg)
Decoupled Libraries for PHP 5.4:The Aura Project
PHP Conference Brazil 2012
auraphp.github.com
paul-m-jones.com@pmjones
Saturday, December 1, 12
![Page 2: Decoupled Library Packages for PHP 5.4](https://reader034.fdocuments.net/reader034/viewer/2022051817/54923184ac795916288b46f0/html5/thumbnails/2.jpg)
Read These
Saturday, December 1, 12
![Page 3: Decoupled Library Packages for PHP 5.4](https://reader034.fdocuments.net/reader034/viewer/2022051817/54923184ac795916288b46f0/html5/thumbnails/3.jpg)
About Me• PHP since 1999
• Developer, Senior Developer,Team Lead, Architect, VP Engineering
• Aura project, benchmarking series, Solar framework, Savant template system
• Zend_DB, Zend_View
• ZCE Education Advisory Board,PHP-FIG Voting Member (PSR-0/1/2)
Saturday, December 1, 12
![Page 4: Decoupled Library Packages for PHP 5.4](https://reader034.fdocuments.net/reader034/viewer/2022051817/54923184ac795916288b46f0/html5/thumbnails/4.jpg)
Overview
• Background of libraries vs. frameworks
• Principles of decoupled libraries
• Examples: individual Aura libraries
Saturday, December 1, 12
![Page 5: Decoupled Library Packages for PHP 5.4](https://reader034.fdocuments.net/reader034/viewer/2022051817/54923184ac795916288b46f0/html5/thumbnails/5.jpg)
Background:Libraries vs Frameworks
Saturday, December 1, 12
![Page 6: Decoupled Library Packages for PHP 5.4](https://reader034.fdocuments.net/reader034/viewer/2022051817/54923184ac795916288b46f0/html5/thumbnails/6.jpg)
Frameworks: Bad!
• PHP 3, PHP 4, and early PHP 5: “framework” a bad word (“CMS” was ok)
• Libraries and collections: Horde, PEAR, phpLib, phpClasses
• Not unified in operation: different constructor signatures, different method verbiage, different usage idioms, tough to combine
• Started Solar (solarphp.com) in 2005 as a library collection(PHP 5, E_STRICT)
Saturday, December 1, 12
![Page 7: Decoupled Library Packages for PHP 5.4](https://reader034.fdocuments.net/reader034/viewer/2022051817/54923184ac795916288b46f0/html5/thumbnails/7.jpg)
Frameworks: Good!
• Rails: “framework” suddenly acceptable
• Cake, CodeIgniter, Symfony, Zend
• Tapped into developer needs
• All delivered as a monolithic whole
• Re-branded Solar libraries as a framework
Saturday, December 1, 12
![Page 8: Decoupled Library Packages for PHP 5.4](https://reader034.fdocuments.net/reader034/viewer/2022051817/54923184ac795916288b46f0/html5/thumbnails/8.jpg)
Frameworks: Good?
• Want to use just part of a framework? Difficult.
• Download entire framework and try to use one part ...
• ... except it has dependencies.
• Have to set up parts you don’t care about.
Saturday, December 1, 12
![Page 9: Decoupled Library Packages for PHP 5.4](https://reader034.fdocuments.net/reader034/viewer/2022051817/54923184ac795916288b46f0/html5/thumbnails/9.jpg)
Frameworks: Re-Evaluating
• PHP 5.3 “full stack”: Lithium, Symfony 2, Zend Framework 2, others
• Micro-frameworks: Glue, Limonade, Silex, Slim
• Context, router/dispatcher, HTTP request/response, session manager
• Ed Finkler, “The Micro-PHP Manifesto” (microphp.org)
• Componentized: Symfony 2 (kind of), Zend Framework 2 (kind of)
Saturday, December 1, 12
![Page 10: Decoupled Library Packages for PHP 5.4](https://reader034.fdocuments.net/reader034/viewer/2022051817/54923184ac795916288b46f0/html5/thumbnails/10.jpg)
install: zend-config zend-http
depends: zend-escaper zend-filter zend-i18n zend-loader zend-servicemanager zend-stdlib zend-uri zend-validator
suggest: pecl-weakref zendframework/zend-di zendframework/zend-crypt zendframework/zend-db zendframework/zend-math
Saturday, December 1, 12
![Page 11: Decoupled Library Packages for PHP 5.4](https://reader034.fdocuments.net/reader034/viewer/2022051817/54923184ac795916288b46f0/html5/thumbnails/11.jpg)
The Aura Projectfor PHP 5.4+
Saturday, December 1, 12
![Page 12: Decoupled Library Packages for PHP 5.4](https://reader034.fdocuments.net/reader034/viewer/2022051817/54923184ac795916288b46f0/html5/thumbnails/12.jpg)
Rewrite Solar
• Solar Framework: 5+ years old at the time (Oct 2010)
• Monolithic; tough to use just parts of it
• Extract components and rewrite using PHP 5.4
• Independent, de-coupled library packages
Saturday, December 1, 12
![Page 13: Decoupled Library Packages for PHP 5.4](https://reader034.fdocuments.net/reader034/viewer/2022051817/54923184ac795916288b46f0/html5/thumbnails/13.jpg)
Driving Principles
• Libraries first, framework later
• No dependencies on any other package (self-contained)
• Tests and assets encapsulated within package
• No use of globals within packages (e.g., $_SERVER)
• Carry data across package boundaries using data transfer objects
• Use a separated interface for each shared tool (signal, log, cache, etc)
Saturday, December 1, 12
![Page 14: Decoupled Library Packages for PHP 5.4](https://reader034.fdocuments.net/reader034/viewer/2022051817/54923184ac795916288b46f0/html5/thumbnails/14.jpg)
Use Dependency Injection
• Solar used service locator and universal constructor
• In Aura, that would mean a package dependency
• So, all packages are set up for dependency injection
• You can use any DI container you like (Aura.Di is nice ;-)
• Factories and builders instead of new keyword
Saturday, December 1, 12
![Page 15: Decoupled Library Packages for PHP 5.4](https://reader034.fdocuments.net/reader034/viewer/2022051817/54923184ac795916288b46f0/html5/thumbnails/15.jpg)
Service Locator Examplesclass Foo{ protected $db; public function __construct() { $this->db = Locator::get('db'); }}
Saturday, December 1, 12
![Page 16: Decoupled Library Packages for PHP 5.4](https://reader034.fdocuments.net/reader034/viewer/2022051817/54923184ac795916288b46f0/html5/thumbnails/16.jpg)
class Foo{ protected $db; public function __construct(Locator $locator) { $this->db = $locator->get('db'); }}
Saturday, December 1, 12
![Page 17: Decoupled Library Packages for PHP 5.4](https://reader034.fdocuments.net/reader034/viewer/2022051817/54923184ac795916288b46f0/html5/thumbnails/17.jpg)
Dependency Injection Examplesclass Foo{ protected $db; public function __construct(Database $db) { $this->db = $db; }}
Saturday, December 1, 12
![Page 18: Decoupled Library Packages for PHP 5.4](https://reader034.fdocuments.net/reader034/viewer/2022051817/54923184ac795916288b46f0/html5/thumbnails/18.jpg)
class Foo{ protected $db; public function setDb(Database $db) { $this->db = $db; }}
Saturday, December 1, 12
![Page 19: Decoupled Library Packages for PHP 5.4](https://reader034.fdocuments.net/reader034/viewer/2022051817/54923184ac795916288b46f0/html5/thumbnails/19.jpg)
class Foo{ protected $db_factory;
public function __construct(DatabaseFactory $db_factory) { $this->db_factory = $db_factory; }
public function doSomething() { $db = $this->db_factory->newInstance(); }}
Saturday, December 1, 12
![Page 20: Decoupled Library Packages for PHP 5.4](https://reader034.fdocuments.net/reader034/viewer/2022051817/54923184ac795916288b46f0/html5/thumbnails/20.jpg)
Dependency Injection > Service Locator
• Locator hides dependencies
• Locator is itself a dependency (all libraries need it)
• Harder to write tests
• DI reveals dependencies
• Is not itself a dependency
• Easier to write tests, mocks, etc.
Saturday, December 1, 12
![Page 21: Decoupled Library Packages for PHP 5.4](https://reader034.fdocuments.net/reader034/viewer/2022051817/54923184ac795916288b46f0/html5/thumbnails/21.jpg)
Aura.Router
Saturday, December 1, 12
![Page 22: Decoupled Library Packages for PHP 5.4](https://reader034.fdocuments.net/reader034/viewer/2022051817/54923184ac795916288b46f0/html5/thumbnails/22.jpg)
Description
Aura Router is a PHP package that implements web routing. Given a URL path
and a copy of $_SERVER, it will extract controller, action, and parameter values
for a specific application route.
Saturday, December 1, 12
![Page 23: Decoupled Library Packages for PHP 5.4](https://reader034.fdocuments.net/reader034/viewer/2022051817/54923184ac795916288b46f0/html5/thumbnails/23.jpg)
Package Organization
Saturday, December 1, 12
![Page 24: Decoupled Library Packages for PHP 5.4](https://reader034.fdocuments.net/reader034/viewer/2022051817/54923184ac795916288b46f0/html5/thumbnails/24.jpg)
Instantiation
// (standalone, no autoloader)$map = require '/path/to/Aura.Router/scripts/instance.php';
// (with autoloader)use Aura\Router\Map;use Aura\Router\DefinitionFactory;use Aura\Router\RouteFactory;
$map = new Map(new DefinitionFactory, new RouteFactory);
Saturday, December 1, 12
![Page 25: Decoupled Library Packages for PHP 5.4](https://reader034.fdocuments.net/reader034/viewer/2022051817/54923184ac795916288b46f0/html5/thumbnails/25.jpg)
Creating Routes// add a simple named route without params$map->add('home', '/');
// add a simple unnamed route with params$map->add(null, '/{:controller}/{:action}/{:id:(\d+)}');
// add a complex named route$map->add('read', '/blog/read/{:id}{:format}', [ 'params' => [ 'id' => '(\d+)', 'format' => '(\..+)?', ], 'values' => [ 'controller' => 'blog', 'action' => 'read', 'format' => '.html', ],));
Saturday, December 1, 12
![Page 26: Decoupled Library Packages for PHP 5.4](https://reader034.fdocuments.net/reader034/viewer/2022051817/54923184ac795916288b46f0/html5/thumbnails/26.jpg)
Matching Routes// get the incoming request URI path$path = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
// get the route based on the path and server$route = $map->match($path, $_SERVER);
The `match()` method does not parse the URI or use `$_SERVER` internally. This is because different
systems may have different ways of representing that information; e.g., through a URI object or a
context object. As long as you can pass the string path and a server array, you can use Aura Router
in your application foundation or framework.Saturday, December 1, 12
![Page 27: Decoupled Library Packages for PHP 5.4](https://reader034.fdocuments.net/reader034/viewer/2022051817/54923184ac795916288b46f0/html5/thumbnails/27.jpg)
Route Values$route = $map->match('/blog/read/42.json', $_SERVER);var_export($route->values);
// shows these values:[ 'controller' => 'blog', 'action' => 'read', 'id' => '42', 'format' => '.json',]
Saturday, December 1, 12
![Page 28: Decoupled Library Packages for PHP 5.4](https://reader034.fdocuments.net/reader034/viewer/2022051817/54923184ac795916288b46f0/html5/thumbnails/28.jpg)
Dispatching Routes$params = $route->values;
$class = ucfirst($params['controller']) . 'Page';unset($params['controller']);
$method = $params['action'] . 'Action';unset($params['action']);
$object = new $class();echo $object->$method($params);
Saturday, December 1, 12
![Page 29: Decoupled Library Packages for PHP 5.4](https://reader034.fdocuments.net/reader034/viewer/2022051817/54923184ac795916288b46f0/html5/thumbnails/29.jpg)
Micro-Framework Route$map->add('read', '/blog/read/{:id}{:format}', [ 'params' => [ 'id' => '(\d+)', 'format' => '(\..+)?', ], 'values' => [ 'controller' => function ($args) { $id = (int) $args['id']; return "Reading blog ID {$id}"; }, 'format' => '.html', ],));
Saturday, December 1, 12
![Page 30: Decoupled Library Packages for PHP 5.4](https://reader034.fdocuments.net/reader034/viewer/2022051817/54923184ac795916288b46f0/html5/thumbnails/30.jpg)
Micro-Framework Dispatcher
$params = $route->values;$controller = $params['controller'];unset($params['controller']);echo $controller($params);
Saturday, December 1, 12
![Page 31: Decoupled Library Packages for PHP 5.4](https://reader034.fdocuments.net/reader034/viewer/2022051817/54923184ac795916288b46f0/html5/thumbnails/31.jpg)
Aura.Web
Saturday, December 1, 12
![Page 32: Decoupled Library Packages for PHP 5.4](https://reader034.fdocuments.net/reader034/viewer/2022051817/54923184ac795916288b46f0/html5/thumbnails/32.jpg)
DescriptionThe Aura Web package provides tools to build web page controllers, including an
`AbstractPage` for action methods, a `Context` class for discovering the request
environment, and a `Response` transfer object that describes the eventual HTTP
response. (Note that the `Response` transfer object is not itself an HTTP response.)
Saturday, December 1, 12
![Page 33: Decoupled Library Packages for PHP 5.4](https://reader034.fdocuments.net/reader034/viewer/2022051817/54923184ac795916288b46f0/html5/thumbnails/33.jpg)
Setup// include all package files,// or add to your autoloaderinclude '/path/to/Aura.Web/src.php';
// create a page controllernamespace Vendor\Package\Web;
use Aura\Web\AbstractPage;
class Page extends AbstractPage{ // controller body}
Saturday, December 1, 12
![Page 34: Decoupled Library Packages for PHP 5.4](https://reader034.fdocuments.net/reader034/viewer/2022051817/54923184ac795916288b46f0/html5/thumbnails/34.jpg)
Instantiation and Callinguse Vendor\Package\Web\Page;use Aura\Web\Context;use Aura\Web\Accept;use Aura\Web\Response;use Aura\Web\Signal;use Aura\Web\Renderer\None as Renderer;
$params = [ 'action' => 'hello', 'format' => '.html', 'noun' => 'world',];
$page = new Page( new Context($GLOBALS), new Accept($_SERVER), new Response, new Signal, new Renderer, $params);
$response_transfer = $page->exec();
Saturday, December 1, 12
![Page 35: Decoupled Library Packages for PHP 5.4](https://reader034.fdocuments.net/reader034/viewer/2022051817/54923184ac795916288b46f0/html5/thumbnails/35.jpg)
use Vendor\Package\Web\Page;use Aura\Web\Context;use Aura\Web\Accept;use Aura\Web\Response;use Aura\Web\Signal;use Aura\Web\Renderer\None as Renderer;
Saturday, December 1, 12
![Page 36: Decoupled Library Packages for PHP 5.4](https://reader034.fdocuments.net/reader034/viewer/2022051817/54923184ac795916288b46f0/html5/thumbnails/36.jpg)
$params = [ 'action' => 'hello', 'format' => '.html', 'noun' => 'world',];
Saturday, December 1, 12
![Page 37: Decoupled Library Packages for PHP 5.4](https://reader034.fdocuments.net/reader034/viewer/2022051817/54923184ac795916288b46f0/html5/thumbnails/37.jpg)
$page = new Page( new Context($GLOBALS), new Accept($_SERVER), new Response, new Signal, new Renderer, $params);
$response_transfer = $page->exec();
Saturday, December 1, 12
![Page 38: Decoupled Library Packages for PHP 5.4](https://reader034.fdocuments.net/reader034/viewer/2022051817/54923184ac795916288b46f0/html5/thumbnails/38.jpg)
Naive Factoryclass NaivePageFactory{ protected $map = [ 'page-name' => 'Vendor\Package\Web\Page', ]; public function newInstance($name, array $params) { $class = $this->map[$name]; return new $class( new Context($GLOBALS), new Accept($_SERVER), new Response, new Signal, new Renderer, $params ); }}
Saturday, December 1, 12
![Page 39: Decoupled Library Packages for PHP 5.4](https://reader034.fdocuments.net/reader034/viewer/2022051817/54923184ac795916288b46f0/html5/thumbnails/39.jpg)
Instantiation With Naive Factoryuse NaivePageFactory;
$params = [ 'action' => 'hello', 'format' => '.html', 'noun' => 'world',];
$factory = new NaivePageFactory;$page = $factory->newInstance('page-name', $params);$response_transfer = $page->exec();
Saturday, December 1, 12
![Page 40: Decoupled Library Packages for PHP 5.4](https://reader034.fdocuments.net/reader034/viewer/2022051817/54923184ac795916288b46f0/html5/thumbnails/40.jpg)
Important Parts• $this->params for incoming parameters
• $this->context for get, post, files, etc.
• $this->accept for content-type, language, encoding, etc
• $this->response for headers, cookies, content (data transfer object)
• $this->signal for signals/events/notifiers (separated interface)
• $this->renderer for rendering strategy (default “none”)
• $this->data for data to be rendered
• (pre|post)_(exec|action|render) hooks, and new catch_exception hook
Saturday, December 1, 12
![Page 41: Decoupled Library Packages for PHP 5.4](https://reader034.fdocuments.net/reader034/viewer/2022051817/54923184ac795916288b46f0/html5/thumbnails/41.jpg)
Action Methodnamespace Vendor\Package\Web;
use Aura\Web\AbstractPage;
class Page extends AbstractPage{ protected function actionHello($noun = null) { $noun = htmlspecialchars($noun, ENT_QUOTES, 'UTF-8'); $content = "Hello, {$noun}!"; $this->response->setContent($content); }}
Saturday, December 1, 12
![Page 42: Decoupled Library Packages for PHP 5.4](https://reader034.fdocuments.net/reader034/viewer/2022051817/54923184ac795916288b46f0/html5/thumbnails/42.jpg)
Data Capture
protected function actionHello($noun = null){ $this->data->noun = $noun;}
Saturday, December 1, 12
![Page 43: Decoupled Library Packages for PHP 5.4](https://reader034.fdocuments.net/reader034/viewer/2022051817/54923184ac795916288b46f0/html5/thumbnails/43.jpg)
Rendering Strategyclass NaiveRenderer extends AbstractRenderer{ public function exec() { // get data from controller $data = (array) $this->controller->getData();
// pick a template file based on controller action $action = $this->controller->getAction(); $__file__ = "/path/to/templates/{$action}.php"; // closure to execute template file $template = function () use (array $data, $__file__) { ob_start(); extract($data); require $__file__; return ob_get_clean(); }; // invoke closure $content = $template(); // set content on response, and done! $response = $this->controller->getResponse(); $response->setContent($content); }}
Saturday, December 1, 12
![Page 44: Decoupled Library Packages for PHP 5.4](https://reader034.fdocuments.net/reader034/viewer/2022051817/54923184ac795916288b46f0/html5/thumbnails/44.jpg)
// get data from controller $data = (array) $this->controller->getData();
// pick a template file based on controller action $action = $this->controller->getAction(); $__file__ = "/path/to/templates/{$action}.php";
Saturday, December 1, 12
![Page 45: Decoupled Library Packages for PHP 5.4](https://reader034.fdocuments.net/reader034/viewer/2022051817/54923184ac795916288b46f0/html5/thumbnails/45.jpg)
// closure to execute template file $template = function () use (array $data, $__file__) { ob_start(); extract($data); require $__file__; return ob_get_clean(); }; // invoke closure $content = $template();
Saturday, December 1, 12
![Page 46: Decoupled Library Packages for PHP 5.4](https://reader034.fdocuments.net/reader034/viewer/2022051817/54923184ac795916288b46f0/html5/thumbnails/46.jpg)
// set content on response, and done! $response = $this->controller->getResponse(); $response->setContent($content);
Saturday, December 1, 12
![Page 47: Decoupled Library Packages for PHP 5.4](https://reader034.fdocuments.net/reader034/viewer/2022051817/54923184ac795916288b46f0/html5/thumbnails/47.jpg)
// template file 'hello.php'$noun = htmlspecialchars($noun, ENT_QUOTES, 'UTF-8');echo "Hello {$noun}!";
Saturday, December 1, 12
![Page 48: Decoupled Library Packages for PHP 5.4](https://reader034.fdocuments.net/reader034/viewer/2022051817/54923184ac795916288b46f0/html5/thumbnails/48.jpg)
Naive Factory and Naive Rendererclass NaivePageFactory{ protected $map = [ 'page-name' => 'Vendor\Package\Web\Page', ]; public function newInstance($name, array $params) { $class = $this->map[$name]; return new $class( new Context($GLOBALS), new Accept($_SERVER), new Response, new Signal, new NaiveRenderer, // <-- strategy $params ); }}
Saturday, December 1, 12
![Page 49: Decoupled Library Packages for PHP 5.4](https://reader034.fdocuments.net/reader034/viewer/2022051817/54923184ac795916288b46f0/html5/thumbnails/49.jpg)
Response Delivery
• ResponseTransfer object is *not* an HTTP response
• It is a Data Transfer Object
• Must convert it to a real HTTP response
• Allows any HTTP library, or none
Saturday, December 1, 12
![Page 50: Decoupled Library Packages for PHP 5.4](https://reader034.fdocuments.net/reader034/viewer/2022051817/54923184ac795916288b46f0/html5/thumbnails/50.jpg)
Delivery Code$headers = $response_transfer->getHeaders();foreach ($headers as $label => $value) { header($label, $value);}
$cookies = $response_transfer->getCookies();foreach ($cookies as $cookie) { setcookie( $cookie['value'], $cookie['expire'], $cookie['path'], $cookie['domain'], $cookie['secure'], $cookie['httponly'] );}
echo $response_transfer->getContent();Saturday, December 1, 12
![Page 51: Decoupled Library Packages for PHP 5.4](https://reader034.fdocuments.net/reader034/viewer/2022051817/54923184ac795916288b46f0/html5/thumbnails/51.jpg)
Full-Stack Framework
Saturday, December 1, 12
![Page 52: Decoupled Library Packages for PHP 5.4](https://reader034.fdocuments.net/reader034/viewer/2022051817/54923184ac795916288b46f0/html5/thumbnails/52.jpg)
Packages (Stable and Beta)•Aura.Autoload
•Aura.Cli
•Aura.Di
• Aura.Filter
•Aura.Http
• Aura.Intl
•Aura.Marshal
•Aura.Router
• Aura.Session
•Aura.Signal
•Aura.Sql
•Aura.Uri
•Aura.View
•Aura.WebSaturday, December 1, 12
![Page 53: Decoupled Library Packages for PHP 5.4](https://reader034.fdocuments.net/reader034/viewer/2022051817/54923184ac795916288b46f0/html5/thumbnails/53.jpg)
Aura.Framework and System
• “Aura.Framework” package to connect all the others into a cohesive whole
• “Aura.Demo” package to provide “hello world”
• “System” package to provide a project skeleton
• Still beta
Saturday, December 1, 12
![Page 54: Decoupled Library Packages for PHP 5.4](https://reader034.fdocuments.net/reader034/viewer/2022051817/54923184ac795916288b46f0/html5/thumbnails/54.jpg)
Saturday, December 1, 12
![Page 55: Decoupled Library Packages for PHP 5.4](https://reader034.fdocuments.net/reader034/viewer/2022051817/54923184ac795916288b46f0/html5/thumbnails/55.jpg)
Conclusion
Saturday, December 1, 12
![Page 56: Decoupled Library Packages for PHP 5.4](https://reader034.fdocuments.net/reader034/viewer/2022051817/54923184ac795916288b46f0/html5/thumbnails/56.jpg)
• Background of libraries vs. frameworks
• Principles of decoupled libraries
• Individual Aura packages
Saturday, December 1, 12
![Page 57: Decoupled Library Packages for PHP 5.4](https://reader034.fdocuments.net/reader034/viewer/2022051817/54923184ac795916288b46f0/html5/thumbnails/57.jpg)
Obrigado!
auraphp.github.com
paul-m-jones.com@pmjones
Saturday, December 1, 12