SlideShare ist ein Scribd-Unternehmen logo
1 von 32
Downloaden Sie, um offline zu lesen
Durian Building Singapore / Dave Cross / CC BY-NC-SA 2.0

DURIAN
A PHP 5.5 microframework based on generator-style middleware	

http://durianphp.com
BEFORE WE BEGIN…
What the heck are generators ?
GENERATORS
•

Introduced in PHP 5.5 (although HHVM had them earlier)	


•

Generators are basically iterators with a simpler syntax	


•

The mere presence of the yield keyword turns a closure into a
generator constructor	


•

Generators are forward-only (cannot be rewound)	


•

You can send() values into generators	


•

You can throw() exceptions into generators
THE YIELD KEYWORD
class MyIterator implements Iterator	
{	
private $values;	

!

public function __construct(array $values) {	
$this->values = $values;	
}	
public function current() {	
return current($this->values);	
}	
public function key() {	
return key($this->values);	
}	
public function next() {	
return next($this->values);	
}	
public function rewind() {}	
public function valid() {	
return null !== key($this->values);	
}	

}	
 	
$iterator = new MyIterator([1,2,3,4,5]);	
 	
while ($iterator->valid()) {	
echo $iterator->current();	
$iterator->next();	
}

$callback = function (array $values) {	
foreach ($values as $value) {	
yield $value;	
}	
};	
 	
$generator = $callback([1,2,3,4,5]);	
 	
while ($generator->valid()) {	
echo $generator->current();	
$generator->next();	
}
PHP MICROFRAMEWORKS
How do they handle middleware and routing ?
EVENT LISTENERS
$app->before(function (Request $request) use ($app) {	
$app['response_time'] = microtime(true);	
});	
 	
$app->get('/blog', function () use ($app) {	
return $app['blog_service']->getPosts()->toJson();	
});	
 	
$app->after(function (Request $request, Response $response) use ($app) {	
$time = microtime(true) - $app['response_time'];	
$response->headers->set('X-Response-Time', $time);	
});
THE DOWNSIDE
•

A decorator has to be split into two separate
functions to wrap the main application	


•

Data has to be passed between functions	


•

Can be confusing to maintain
HIERARCHICAL ROUTING
$app->path('blog', function ($request) use ($app) {	
$time = microtime(true);	
$blog = BlogService::create()->initialise();	
 	
$app->path('posts', function () use ($app, $blog) {	
$posts = $blog->getAllPosts();	
 	
$app->get(function () use ($app, $posts) {	
return $app->template('posts/index', $posts->toJson());	
});	
});	
 	
$time = microtime(true) - $time;	
$this->response()->header('X-Response-Time', $time);	
});
THE DOWNSIDE
•

Subsequent route and method declarations are now
embedded inside a closure	


•

Closure needs to be executed to proceed	


•

Potentially incurring expensive initialisation or
computations only to be discarded	


•

Middleware code is still split across two locations
“CALLBACK HELL”
$app->path('a', function () use ($app) {	
$app->param('b', function ($b) use ($app) {	
$app->path('c', function () use ($b, $app) {	
$app->param('d', function ($d) use ($app) {	
$app->get(function () use ($d, $app) {	
$app->json(function () use ($app) {	
// ...	
});	
});	
});	
});	
});	
});
How about other languages ?
KOA (NODEJS)
var koa = require('koa');	
var app = koa();	

!
app.use(function *(next){	
var start = new Date;	
yield next;	
var ms = new Date - start;	
console.log('%s %s - %s', this.method, this.url, ms);	
});	

!
app.use(function *(){	
this.body = 'Hello World';	
});	

!
app.listen(3000);
MARTINI (GOLANG)
package main	
import "github.com/codegangsta/martini"	

!
func main() {	
m := martini.Classic()	

!
m.Use(func(c martini.Context, log *log.Logger) {	
log.Println("before a request")	
c.Next()	
log.Println("after a request")	
})	

!
m.Get("/", func() string {	
return "Hello world!"	
})	

!
m.Run()	
}
INTRODUCING DURIAN
•

Take advantage of PHP 5.4, 5.5 features	


•

Unify interface across controllers and middleware	


•

Avoid excessive nesting / callback hell	


•

Use existing library components	


•

None of this has anything to do with durians
COMPONENTS
•

Application container: Pimple by @fabpot	


•

Request/Response: Symfony2 HttpFoundation	


•

Routing: FastRoute by @nikic	


•

Symfony2 HttpKernelInterface (for stackphp
compatibility)
A DURIAN APPLICATION
$app = new DurianApplication();	
!

$app->route('/hello/{name}', function () {	
return 'Hello '.$this->param('name');	
});	
!

$app->run();


•

Nothing special there, basically the same syntax
as every microframework ever
HANDLERS
•

Simple wrapper around closures and generators	


•

Handlers consist of the primary callback and an optional guard
callback

$responseHandler = $app->handler(function () {	
$time = microtime(true);	
yield;	
$time = microtime(true) - $time;	
$this->response()->headers->set('X-Response-Time', $time);	
}, function () use ($app) {	
return $app['debug'];	
});
THE HANDLER STACK
•

Application::handle() iterates through a generator that
produces Handlers to be invoked	


•

Generators produced from handlers are placed into
another stack to be revisited in reverse order	


•

A Handler may produce a generator that produces more
Handlers, which are fed back to the main generator	


•

The route dispatcher is one such handler
function

generator

Route dispatcher
A

D

B

A

C

B

C

D
MODIFYING THE STACK
$app['middleware.response_time'] = $app->handler(function () {	
$time = microtime(true);	
yield;	
$time = microtime(true) - $time;	
$this->response()->headers->set('X-Response-Time', $time);	
}, function () use ($app) {	
return $this->master() && $app['debug'];	
});	

!
$app->handlers([	
'middleware.response_time',	
new DurianMiddlewareRouterMiddleware()	
]);	

!
$app->after(new DurianMiddlewareResponseMiddleware());	

!
$app->before(new DurianMiddlewareWhoopsMiddleware());
ROUTE HANDLER
•

Apply the handler concept to route matching	



$app->handler(function () {	
$this->response('Hello World!');	
}, function () {	
$matcher = new RequestMatcher('^/$');	
return $matcher->matches($this->request());	
});	

•

Compare to	



$app->route('/', function () {	
$this->response('Hello World!');	
});
ROUTE CHAINING
$app['awesome_library'] = $app->share(function ($app) {	
return new MyAwesomeLibrary();	
});	

!
$app->route('/hello', function () use ($app) {	
$app['awesome_library']->performExpensiveOperation();	
yield 'Hello ';	
$app['awesome_library']->performCleanUp();	
})->route('/{name}', function () {	
return $this->last().$this->param('name');	
})->get(function () {	
return ['method' => 'GET', 'message' => $this->last()];	
})->post(function () {	
return ['method' => 'POST', 'message' => $this->last()];	
});
ROUTE DISPATCHING
•

This route definition:	



$albums = $app->route('/albums', A)->get(B)->post(C);	
$albums->route('/{aid:[0-9]+}', D, E)->get(F)->put(G, H)->delete(I);	

•

Gets turned into:	



GET
POST
GET
PUT
DELETE

/albums
/albums
/albums/{aid}
/albums/{aid}
/albums/{aid}

=>
=>
=>
=>
=>

[A,B]"
[A,C]"
[A,D,E,F]"
[A,D,E,G,H]"
[A,D,E,I]
•

Route chaining isn’t mandatory !	


•

You can still use the regular syntax

// Routes will support GET by default	
$app->route('/users');	

!
// Methods can be declared without handlers	
$app->route('/users/{name}')->post();	

!
// Declare multiple methods separated by pipe characters	
$app->route('/users/{name}/friends')->method('GET|POST');
CONTEXT
•

Every handler is bound to the Context object using Closure::bind	


•

A new context is created for every request or sub request
Get the Request object

$request = $this->request();

Get the Response

$response = $this->response();

Set the Response

$this->response("I'm a teapot", 418);

Get the last handler output

$last = $this->last();

Get a route parameter

$id = $this->param('id');

Throw an error

$this->error('Forbidden', 403);
EXCEPTION HANDLING
•

Exceptions are caught and bubbled back up through all registered
generators	


•

Intercept them by wrapping the yield statement with a try/catch block

$exceptionHandlerMiddleware = $app->handler(function () {	
try {	
yield;	
} catch (Exception $exception) {	
$this->response($exception->getMessage(), 500);	
}	
});
AWESOME EXAMPLE
Let’s add two integers together !
$app->route('/add', function () use ($app) {



$app['number_collection'] = $app->share(function ($app) {	
return new NumberCollection();	
});	
$app['number_parser'] = $app->share(function ($app) {	
return new SimpleNumberStringParser();	
});"
yield;	
$addition = new AdditionOperator('SimplePHPEasyPlusNumberSimpleNumber');	
$operation = new ArithmeticOperation($addition);	
$engine = new Engine($operation);	
$calcul = new Calcul($engine, $app['number_collection']);	
$runner = new CalculRunner();	
$runner->run($calcul);	
$result = $calcul->getResult();	
$numericResult = $result->getValue();	
$this->response('The answer is: ' . $numericResult);

})->route('/{first:[0-9]+}', function () use ($app) {

$firstParsedNumber = $app['number_parser']->parse($this->param('first'));	
$firstNumber = new SimpleNumber($firstParsedNumber);	
$firstNumberProxy = new CollectionItemNumberProxy($firstNumber);	
$app['number_collection']->add($firstNumberProxy);

})->route('/{second:[0-9]+}', function () use ($app) {

$secondParsedNumber = $app['number_parser']->parse($this->param('second'));	
$secondNumber = new SimpleNumber($secondParsedNumber);	
$secondNumberProxy = new CollectionItemNumberProxy($secondNumber);	
$app['number_collection']->add($secondNumberProxy);

})->get();
COMING SOON
•

Proper tests and coverage (!!!)	


•

Handlers for format negotiation, session, locale, etc	


•

Dependency injection through reflection (via trait)	


•

Framework/engine-agnostic view composition and
template rendering (separate project)
THANK YOU
bigblah@gmail.com	

https://github.com/gigablah	

http://durianphp.com

Weitere ähnliche Inhalte

Was ist angesagt?

Building Lithium Apps
Building Lithium AppsBuilding Lithium Apps
Building Lithium AppsNate Abele
 
Doctrine MongoDB ODM (PDXPHP)
Doctrine MongoDB ODM (PDXPHP)Doctrine MongoDB ODM (PDXPHP)
Doctrine MongoDB ODM (PDXPHP)Kris Wallsmith
 
Lithium: The Framework for People Who Hate Frameworks
Lithium: The Framework for People Who Hate FrameworksLithium: The Framework for People Who Hate Frameworks
Lithium: The Framework for People Who Hate FrameworksNate Abele
 
Looping the Loop with SPL Iterators
Looping the Loop with SPL IteratorsLooping the Loop with SPL Iterators
Looping the Loop with SPL IteratorsMark Baker
 
Silex meets SOAP & REST
Silex meets SOAP & RESTSilex meets SOAP & REST
Silex meets SOAP & RESTHugo Hamon
 
Electrify your code with PHP Generators
Electrify your code with PHP GeneratorsElectrify your code with PHP Generators
Electrify your code with PHP GeneratorsMark Baker
 
Rich domain model with symfony 2.5 and doctrine 2.5
Rich domain model with symfony 2.5 and doctrine 2.5Rich domain model with symfony 2.5 and doctrine 2.5
Rich domain model with symfony 2.5 and doctrine 2.5Leonardo Proietti
 
Introducing Assetic (NYPHP)
Introducing Assetic (NYPHP)Introducing Assetic (NYPHP)
Introducing Assetic (NYPHP)Kris Wallsmith
 
Symfony2, creare bundle e valore per il cliente
Symfony2, creare bundle e valore per il clienteSymfony2, creare bundle e valore per il cliente
Symfony2, creare bundle e valore per il clienteLeonardo Proietti
 
Lithium: The Framework for People Who Hate Frameworks, Tokyo Edition
Lithium: The Framework for People Who Hate Frameworks, Tokyo EditionLithium: The Framework for People Who Hate Frameworks, Tokyo Edition
Lithium: The Framework for People Who Hate Frameworks, Tokyo EditionNate Abele
 
News of the Symfony2 World
News of the Symfony2 WorldNews of the Symfony2 World
News of the Symfony2 WorldFabien Potencier
 
Design Patterns avec PHP 5.3, Symfony et Pimple
Design Patterns avec PHP 5.3, Symfony et PimpleDesign Patterns avec PHP 5.3, Symfony et Pimple
Design Patterns avec PHP 5.3, Symfony et PimpleHugo Hamon
 
The State of Lithium
The State of LithiumThe State of Lithium
The State of LithiumNate Abele
 
Forget about loops
Forget about loopsForget about loops
Forget about loopsDušan Kasan
 
PHP 5.3 Overview
PHP 5.3 OverviewPHP 5.3 Overview
PHP 5.3 Overviewjsmith92
 
Future of HTTP in CakePHP
Future of HTTP in CakePHPFuture of HTTP in CakePHP
Future of HTTP in CakePHPmarkstory
 

Was ist angesagt? (20)

Building Lithium Apps
Building Lithium AppsBuilding Lithium Apps
Building Lithium Apps
 
Doctrine MongoDB ODM (PDXPHP)
Doctrine MongoDB ODM (PDXPHP)Doctrine MongoDB ODM (PDXPHP)
Doctrine MongoDB ODM (PDXPHP)
 
Lithium: The Framework for People Who Hate Frameworks
Lithium: The Framework for People Who Hate FrameworksLithium: The Framework for People Who Hate Frameworks
Lithium: The Framework for People Who Hate Frameworks
 
Looping the Loop with SPL Iterators
Looping the Loop with SPL IteratorsLooping the Loop with SPL Iterators
Looping the Loop with SPL Iterators
 
Silex meets SOAP & REST
Silex meets SOAP & RESTSilex meets SOAP & REST
Silex meets SOAP & REST
 
Electrify your code with PHP Generators
Electrify your code with PHP GeneratorsElectrify your code with PHP Generators
Electrify your code with PHP Generators
 
Rich domain model with symfony 2.5 and doctrine 2.5
Rich domain model with symfony 2.5 and doctrine 2.5Rich domain model with symfony 2.5 and doctrine 2.5
Rich domain model with symfony 2.5 and doctrine 2.5
 
Introducing Assetic (NYPHP)
Introducing Assetic (NYPHP)Introducing Assetic (NYPHP)
Introducing Assetic (NYPHP)
 
Symfony2, creare bundle e valore per il cliente
Symfony2, creare bundle e valore per il clienteSymfony2, creare bundle e valore per il cliente
Symfony2, creare bundle e valore per il cliente
 
Lithium: The Framework for People Who Hate Frameworks, Tokyo Edition
Lithium: The Framework for People Who Hate Frameworks, Tokyo EditionLithium: The Framework for People Who Hate Frameworks, Tokyo Edition
Lithium: The Framework for People Who Hate Frameworks, Tokyo Edition
 
News of the Symfony2 World
News of the Symfony2 WorldNews of the Symfony2 World
News of the Symfony2 World
 
Advanced Querying with CakePHP 3
Advanced Querying with CakePHP 3Advanced Querying with CakePHP 3
Advanced Querying with CakePHP 3
 
Zero to SOLID
Zero to SOLIDZero to SOLID
Zero to SOLID
 
Design Patterns avec PHP 5.3, Symfony et Pimple
Design Patterns avec PHP 5.3, Symfony et PimpleDesign Patterns avec PHP 5.3, Symfony et Pimple
Design Patterns avec PHP 5.3, Symfony et Pimple
 
The State of Lithium
The State of LithiumThe State of Lithium
The State of Lithium
 
Forget about loops
Forget about loopsForget about loops
Forget about loops
 
PHP 5.3 Overview
PHP 5.3 OverviewPHP 5.3 Overview
PHP 5.3 Overview
 
Symfony 2.0 on PHP 5.3
Symfony 2.0 on PHP 5.3Symfony 2.0 on PHP 5.3
Symfony 2.0 on PHP 5.3
 
Future of HTTP in CakePHP
Future of HTTP in CakePHPFuture of HTTP in CakePHP
Future of HTTP in CakePHP
 
Symfony2 - WebExpo 2010
Symfony2 - WebExpo 2010Symfony2 - WebExpo 2010
Symfony2 - WebExpo 2010
 

Ähnlich wie Durian: a PHP 5.5 microframework with generator-style middleware

PHPCon 2016: PHP7 by Witek Adamus / XSolve
PHPCon 2016: PHP7 by Witek Adamus / XSolvePHPCon 2016: PHP7 by Witek Adamus / XSolve
PHPCon 2016: PHP7 by Witek Adamus / XSolveXSolve
 
関西PHP勉強会 php5.4つまみぐい
関西PHP勉強会 php5.4つまみぐい関西PHP勉強会 php5.4つまみぐい
関西PHP勉強会 php5.4つまみぐいHisateru Tanaka
 
Nashvile Symfony Routes Presentation
Nashvile Symfony Routes PresentationNashvile Symfony Routes Presentation
Nashvile Symfony Routes PresentationBrent Shaffer
 
The promise of asynchronous php
The promise of asynchronous phpThe promise of asynchronous php
The promise of asynchronous phpWim Godden
 
PHP and Rich Internet Applications
PHP and Rich Internet ApplicationsPHP and Rich Internet Applications
PHP and Rich Internet Applicationselliando dias
 
The promise of asynchronous php
The promise of asynchronous phpThe promise of asynchronous php
The promise of asynchronous phpWim Godden
 
Jsphp 110312161301-phpapp02
Jsphp 110312161301-phpapp02Jsphp 110312161301-phpapp02
Jsphp 110312161301-phpapp02Seri Moth
 
Elements of Functional Programming in PHP
Elements of Functional Programming in PHPElements of Functional Programming in PHP
Elements of Functional Programming in PHPJarek Jakubowski
 
Aura Project for PHP
Aura Project for PHPAura Project for PHP
Aura Project for PHPHari K T
 
Micropage in microtime using microframework
Micropage in microtime using microframeworkMicropage in microtime using microframework
Micropage in microtime using microframeworkRadek Benkel
 
Thinking Functionally with JavaScript
Thinking Functionally with JavaScriptThinking Functionally with JavaScript
Thinking Functionally with JavaScriptLuis Atencio
 
PHP and Rich Internet Applications
PHP and Rich Internet ApplicationsPHP and Rich Internet Applications
PHP and Rich Internet Applicationselliando dias
 
Can't Miss Features of PHP 5.3 and 5.4
Can't Miss Features of PHP 5.3 and 5.4Can't Miss Features of PHP 5.3 and 5.4
Can't Miss Features of PHP 5.3 and 5.4Jeff Carouth
 
Why async and functional programming in PHP7 suck and how to get overr it?
Why async and functional programming in PHP7 suck and how to get overr it?Why async and functional programming in PHP7 suck and how to get overr it?
Why async and functional programming in PHP7 suck and how to get overr it?Lucas Witold Adamus
 
Good Evils In Perl (Yapc Asia)
Good Evils In Perl (Yapc Asia)Good Evils In Perl (Yapc Asia)
Good Evils In Perl (Yapc Asia)Kang-min Liu
 

Ähnlich wie Durian: a PHP 5.5 microframework with generator-style middleware (20)

PHPCon 2016: PHP7 by Witek Adamus / XSolve
PHPCon 2016: PHP7 by Witek Adamus / XSolvePHPCon 2016: PHP7 by Witek Adamus / XSolve
PHPCon 2016: PHP7 by Witek Adamus / XSolve
 
関西PHP勉強会 php5.4つまみぐい
関西PHP勉強会 php5.4つまみぐい関西PHP勉強会 php5.4つまみぐい
関西PHP勉強会 php5.4つまみぐい
 
Nashvile Symfony Routes Presentation
Nashvile Symfony Routes PresentationNashvile Symfony Routes Presentation
Nashvile Symfony Routes Presentation
 
Functional programming with php7
Functional programming with php7Functional programming with php7
Functional programming with php7
 
The promise of asynchronous php
The promise of asynchronous phpThe promise of asynchronous php
The promise of asynchronous php
 
PHP and Rich Internet Applications
PHP and Rich Internet ApplicationsPHP and Rich Internet Applications
PHP and Rich Internet Applications
 
The promise of asynchronous php
The promise of asynchronous phpThe promise of asynchronous php
The promise of asynchronous php
 
Jsphp 110312161301-phpapp02
Jsphp 110312161301-phpapp02Jsphp 110312161301-phpapp02
Jsphp 110312161301-phpapp02
 
PHP pod mikroskopom
PHP pod mikroskopomPHP pod mikroskopom
PHP pod mikroskopom
 
Elements of Functional Programming in PHP
Elements of Functional Programming in PHPElements of Functional Programming in PHP
Elements of Functional Programming in PHP
 
Aura Project for PHP
Aura Project for PHPAura Project for PHP
Aura Project for PHP
 
Micropage in microtime using microframework
Micropage in microtime using microframeworkMicropage in microtime using microframework
Micropage in microtime using microframework
 
Laravel 101
Laravel 101Laravel 101
Laravel 101
 
Thinking Functionally with JavaScript
Thinking Functionally with JavaScriptThinking Functionally with JavaScript
Thinking Functionally with JavaScript
 
PHP and Rich Internet Applications
PHP and Rich Internet ApplicationsPHP and Rich Internet Applications
PHP and Rich Internet Applications
 
Can't Miss Features of PHP 5.3 and 5.4
Can't Miss Features of PHP 5.3 and 5.4Can't Miss Features of PHP 5.3 and 5.4
Can't Miss Features of PHP 5.3 and 5.4
 
Unittests für Dummies
Unittests für DummiesUnittests für Dummies
Unittests für Dummies
 
Why async and functional programming in PHP7 suck and how to get overr it?
Why async and functional programming in PHP7 suck and how to get overr it?Why async and functional programming in PHP7 suck and how to get overr it?
Why async and functional programming in PHP7 suck and how to get overr it?
 
Solid principles
Solid principlesSolid principles
Solid principles
 
Good Evils In Perl (Yapc Asia)
Good Evils In Perl (Yapc Asia)Good Evils In Perl (Yapc Asia)
Good Evils In Perl (Yapc Asia)
 

Kürzlich hochgeladen

Designing IA for AI - Information Architecture Conference 2024
Designing IA for AI - Information Architecture Conference 2024Designing IA for AI - Information Architecture Conference 2024
Designing IA for AI - Information Architecture Conference 2024Enterprise Knowledge
 
Install Stable Diffusion in windows machine
Install Stable Diffusion in windows machineInstall Stable Diffusion in windows machine
Install Stable Diffusion in windows machinePadma Pradeep
 
Are Multi-Cloud and Serverless Good or Bad?
Are Multi-Cloud and Serverless Good or Bad?Are Multi-Cloud and Serverless Good or Bad?
Are Multi-Cloud and Serverless Good or Bad?Mattias Andersson
 
Beyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
Beyond Boundaries: Leveraging No-Code Solutions for Industry InnovationBeyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
Beyond Boundaries: Leveraging No-Code Solutions for Industry InnovationSafe Software
 
SAP Build Work Zone - Overview L2-L3.pptx
SAP Build Work Zone - Overview L2-L3.pptxSAP Build Work Zone - Overview L2-L3.pptx
SAP Build Work Zone - Overview L2-L3.pptxNavinnSomaal
 
The Future of Software Development - Devin AI Innovative Approach.pdf
The Future of Software Development - Devin AI Innovative Approach.pdfThe Future of Software Development - Devin AI Innovative Approach.pdf
The Future of Software Development - Devin AI Innovative Approach.pdfSeasiaInfotech2
 
Search Engine Optimization SEO PDF for 2024.pdf
Search Engine Optimization SEO PDF for 2024.pdfSearch Engine Optimization SEO PDF for 2024.pdf
Search Engine Optimization SEO PDF for 2024.pdfRankYa
 
Vertex AI Gemini Prompt Engineering Tips
Vertex AI Gemini Prompt Engineering TipsVertex AI Gemini Prompt Engineering Tips
Vertex AI Gemini Prompt Engineering TipsMiki Katsuragi
 
CloudStudio User manual (basic edition):
CloudStudio User manual (basic edition):CloudStudio User manual (basic edition):
CloudStudio User manual (basic edition):comworks
 
Developer Data Modeling Mistakes: From Postgres to NoSQL
Developer Data Modeling Mistakes: From Postgres to NoSQLDeveloper Data Modeling Mistakes: From Postgres to NoSQL
Developer Data Modeling Mistakes: From Postgres to NoSQLScyllaDB
 
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)Mark Simos
 
Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Commit University
 
Bun (KitWorks Team Study 노별마루 발표 2024.4.22)
Bun (KitWorks Team Study 노별마루 발표 2024.4.22)Bun (KitWorks Team Study 노별마루 발표 2024.4.22)
Bun (KitWorks Team Study 노별마루 발표 2024.4.22)Wonjun Hwang
 
Artificial intelligence in cctv survelliance.pptx
Artificial intelligence in cctv survelliance.pptxArtificial intelligence in cctv survelliance.pptx
Artificial intelligence in cctv survelliance.pptxhariprasad279825
 
Vector Databases 101 - An introduction to the world of Vector Databases
Vector Databases 101 - An introduction to the world of Vector DatabasesVector Databases 101 - An introduction to the world of Vector Databases
Vector Databases 101 - An introduction to the world of Vector DatabasesZilliz
 
My INSURER PTE LTD - Insurtech Innovation Award 2024
My INSURER PTE LTD - Insurtech Innovation Award 2024My INSURER PTE LTD - Insurtech Innovation Award 2024
My INSURER PTE LTD - Insurtech Innovation Award 2024The Digital Insurer
 
"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii Soldatenko"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii SoldatenkoFwdays
 
Unraveling Multimodality with Large Language Models.pdf
Unraveling Multimodality with Large Language Models.pdfUnraveling Multimodality with Large Language Models.pdf
Unraveling Multimodality with Large Language Models.pdfAlex Barbosa Coqueiro
 
Leverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage Cost
Leverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage CostLeverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage Cost
Leverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage CostZilliz
 
My Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 PresentationMy Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 PresentationRidwan Fadjar
 

Kürzlich hochgeladen (20)

Designing IA for AI - Information Architecture Conference 2024
Designing IA for AI - Information Architecture Conference 2024Designing IA for AI - Information Architecture Conference 2024
Designing IA for AI - Information Architecture Conference 2024
 
Install Stable Diffusion in windows machine
Install Stable Diffusion in windows machineInstall Stable Diffusion in windows machine
Install Stable Diffusion in windows machine
 
Are Multi-Cloud and Serverless Good or Bad?
Are Multi-Cloud and Serverless Good or Bad?Are Multi-Cloud and Serverless Good or Bad?
Are Multi-Cloud and Serverless Good or Bad?
 
Beyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
Beyond Boundaries: Leveraging No-Code Solutions for Industry InnovationBeyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
Beyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
 
SAP Build Work Zone - Overview L2-L3.pptx
SAP Build Work Zone - Overview L2-L3.pptxSAP Build Work Zone - Overview L2-L3.pptx
SAP Build Work Zone - Overview L2-L3.pptx
 
The Future of Software Development - Devin AI Innovative Approach.pdf
The Future of Software Development - Devin AI Innovative Approach.pdfThe Future of Software Development - Devin AI Innovative Approach.pdf
The Future of Software Development - Devin AI Innovative Approach.pdf
 
Search Engine Optimization SEO PDF for 2024.pdf
Search Engine Optimization SEO PDF for 2024.pdfSearch Engine Optimization SEO PDF for 2024.pdf
Search Engine Optimization SEO PDF for 2024.pdf
 
Vertex AI Gemini Prompt Engineering Tips
Vertex AI Gemini Prompt Engineering TipsVertex AI Gemini Prompt Engineering Tips
Vertex AI Gemini Prompt Engineering Tips
 
CloudStudio User manual (basic edition):
CloudStudio User manual (basic edition):CloudStudio User manual (basic edition):
CloudStudio User manual (basic edition):
 
Developer Data Modeling Mistakes: From Postgres to NoSQL
Developer Data Modeling Mistakes: From Postgres to NoSQLDeveloper Data Modeling Mistakes: From Postgres to NoSQL
Developer Data Modeling Mistakes: From Postgres to NoSQL
 
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
 
Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!
 
Bun (KitWorks Team Study 노별마루 발표 2024.4.22)
Bun (KitWorks Team Study 노별마루 발표 2024.4.22)Bun (KitWorks Team Study 노별마루 발표 2024.4.22)
Bun (KitWorks Team Study 노별마루 발표 2024.4.22)
 
Artificial intelligence in cctv survelliance.pptx
Artificial intelligence in cctv survelliance.pptxArtificial intelligence in cctv survelliance.pptx
Artificial intelligence in cctv survelliance.pptx
 
Vector Databases 101 - An introduction to the world of Vector Databases
Vector Databases 101 - An introduction to the world of Vector DatabasesVector Databases 101 - An introduction to the world of Vector Databases
Vector Databases 101 - An introduction to the world of Vector Databases
 
My INSURER PTE LTD - Insurtech Innovation Award 2024
My INSURER PTE LTD - Insurtech Innovation Award 2024My INSURER PTE LTD - Insurtech Innovation Award 2024
My INSURER PTE LTD - Insurtech Innovation Award 2024
 
"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii Soldatenko"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii Soldatenko
 
Unraveling Multimodality with Large Language Models.pdf
Unraveling Multimodality with Large Language Models.pdfUnraveling Multimodality with Large Language Models.pdf
Unraveling Multimodality with Large Language Models.pdf
 
Leverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage Cost
Leverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage CostLeverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage Cost
Leverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage Cost
 
My Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 PresentationMy Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 Presentation
 

Durian: a PHP 5.5 microframework with generator-style middleware

  • 1. Durian Building Singapore / Dave Cross / CC BY-NC-SA 2.0 DURIAN A PHP 5.5 microframework based on generator-style middleware http://durianphp.com
  • 2. BEFORE WE BEGIN… What the heck are generators ?
  • 3. GENERATORS • Introduced in PHP 5.5 (although HHVM had them earlier) • Generators are basically iterators with a simpler syntax • The mere presence of the yield keyword turns a closure into a generator constructor • Generators are forward-only (cannot be rewound) • You can send() values into generators • You can throw() exceptions into generators
  • 4. THE YIELD KEYWORD class MyIterator implements Iterator { private $values; ! public function __construct(array $values) { $this->values = $values; } public function current() { return current($this->values); } public function key() { return key($this->values); } public function next() { return next($this->values); } public function rewind() {} public function valid() { return null !== key($this->values); } }   $iterator = new MyIterator([1,2,3,4,5]);   while ($iterator->valid()) { echo $iterator->current(); $iterator->next(); } $callback = function (array $values) { foreach ($values as $value) { yield $value; } };   $generator = $callback([1,2,3,4,5]);   while ($generator->valid()) { echo $generator->current(); $generator->next(); }
  • 6. How do they handle middleware and routing ?
  • 7. EVENT LISTENERS $app->before(function (Request $request) use ($app) { $app['response_time'] = microtime(true); });   $app->get('/blog', function () use ($app) { return $app['blog_service']->getPosts()->toJson(); });   $app->after(function (Request $request, Response $response) use ($app) { $time = microtime(true) - $app['response_time']; $response->headers->set('X-Response-Time', $time); });
  • 8. THE DOWNSIDE • A decorator has to be split into two separate functions to wrap the main application • Data has to be passed between functions • Can be confusing to maintain
  • 9. HIERARCHICAL ROUTING $app->path('blog', function ($request) use ($app) { $time = microtime(true); $blog = BlogService::create()->initialise();   $app->path('posts', function () use ($app, $blog) { $posts = $blog->getAllPosts();   $app->get(function () use ($app, $posts) { return $app->template('posts/index', $posts->toJson()); }); });   $time = microtime(true) - $time; $this->response()->header('X-Response-Time', $time); });
  • 10. THE DOWNSIDE • Subsequent route and method declarations are now embedded inside a closure • Closure needs to be executed to proceed • Potentially incurring expensive initialisation or computations only to be discarded • Middleware code is still split across two locations
  • 11. “CALLBACK HELL” $app->path('a', function () use ($app) { $app->param('b', function ($b) use ($app) { $app->path('c', function () use ($b, $app) { $app->param('d', function ($d) use ($app) { $app->get(function () use ($d, $app) { $app->json(function () use ($app) { // ... }); }); }); }); }); });
  • 12. How about other languages ?
  • 13. KOA (NODEJS) var koa = require('koa'); var app = koa(); ! app.use(function *(next){ var start = new Date; yield next; var ms = new Date - start; console.log('%s %s - %s', this.method, this.url, ms); }); ! app.use(function *(){ this.body = 'Hello World'; }); ! app.listen(3000);
  • 14. MARTINI (GOLANG) package main import "github.com/codegangsta/martini" ! func main() { m := martini.Classic() ! m.Use(func(c martini.Context, log *log.Logger) { log.Println("before a request") c.Next() log.Println("after a request") }) ! m.Get("/", func() string { return "Hello world!" }) ! m.Run() }
  • 15. INTRODUCING DURIAN • Take advantage of PHP 5.4, 5.5 features • Unify interface across controllers and middleware • Avoid excessive nesting / callback hell • Use existing library components • None of this has anything to do with durians
  • 16. COMPONENTS • Application container: Pimple by @fabpot • Request/Response: Symfony2 HttpFoundation • Routing: FastRoute by @nikic • Symfony2 HttpKernelInterface (for stackphp compatibility)
  • 17. A DURIAN APPLICATION $app = new DurianApplication(); ! $app->route('/hello/{name}', function () { return 'Hello '.$this->param('name'); }); ! $app->run();
 • Nothing special there, basically the same syntax as every microframework ever
  • 18. HANDLERS • Simple wrapper around closures and generators • Handlers consist of the primary callback and an optional guard callback
 $responseHandler = $app->handler(function () { $time = microtime(true); yield; $time = microtime(true) - $time; $this->response()->headers->set('X-Response-Time', $time); }, function () use ($app) { return $app['debug']; });
  • 19. THE HANDLER STACK • Application::handle() iterates through a generator that produces Handlers to be invoked • Generators produced from handlers are placed into another stack to be revisited in reverse order • A Handler may produce a generator that produces more Handlers, which are fed back to the main generator • The route dispatcher is one such handler
  • 21. MODIFYING THE STACK $app['middleware.response_time'] = $app->handler(function () { $time = microtime(true); yield; $time = microtime(true) - $time; $this->response()->headers->set('X-Response-Time', $time); }, function () use ($app) { return $this->master() && $app['debug']; }); ! $app->handlers([ 'middleware.response_time', new DurianMiddlewareRouterMiddleware() ]); ! $app->after(new DurianMiddlewareResponseMiddleware()); ! $app->before(new DurianMiddlewareWhoopsMiddleware());
  • 22. ROUTE HANDLER • Apply the handler concept to route matching 
 $app->handler(function () { $this->response('Hello World!'); }, function () { $matcher = new RequestMatcher('^/$'); return $matcher->matches($this->request()); }); • Compare to 
 $app->route('/', function () { $this->response('Hello World!'); });
  • 23. ROUTE CHAINING $app['awesome_library'] = $app->share(function ($app) { return new MyAwesomeLibrary(); }); ! $app->route('/hello', function () use ($app) { $app['awesome_library']->performExpensiveOperation(); yield 'Hello '; $app['awesome_library']->performCleanUp(); })->route('/{name}', function () { return $this->last().$this->param('name'); })->get(function () { return ['method' => 'GET', 'message' => $this->last()]; })->post(function () { return ['method' => 'POST', 'message' => $this->last()]; });
  • 24. ROUTE DISPATCHING • This route definition: 
 $albums = $app->route('/albums', A)->get(B)->post(C); $albums->route('/{aid:[0-9]+}', D, E)->get(F)->put(G, H)->delete(I); • Gets turned into: 
 GET POST GET PUT DELETE /albums /albums /albums/{aid} /albums/{aid} /albums/{aid} => => => => => [A,B]" [A,C]" [A,D,E,F]" [A,D,E,G,H]" [A,D,E,I]
  • 25. • Route chaining isn’t mandatory ! • You can still use the regular syntax
 // Routes will support GET by default $app->route('/users'); ! // Methods can be declared without handlers $app->route('/users/{name}')->post(); ! // Declare multiple methods separated by pipe characters $app->route('/users/{name}/friends')->method('GET|POST');
  • 26. CONTEXT • Every handler is bound to the Context object using Closure::bind • A new context is created for every request or sub request Get the Request object $request = $this->request(); Get the Response $response = $this->response(); Set the Response $this->response("I'm a teapot", 418); Get the last handler output $last = $this->last(); Get a route parameter $id = $this->param('id'); Throw an error $this->error('Forbidden', 403);
  • 27. EXCEPTION HANDLING • Exceptions are caught and bubbled back up through all registered generators • Intercept them by wrapping the yield statement with a try/catch block
 $exceptionHandlerMiddleware = $app->handler(function () { try { yield; } catch (Exception $exception) { $this->response($exception->getMessage(), 500); } });
  • 28. AWESOME EXAMPLE Let’s add two integers together !
  • 29.
  • 30. $app->route('/add', function () use ($app) {
 
 $app['number_collection'] = $app->share(function ($app) { return new NumberCollection(); }); $app['number_parser'] = $app->share(function ($app) { return new SimpleNumberStringParser(); });" yield; $addition = new AdditionOperator('SimplePHPEasyPlusNumberSimpleNumber'); $operation = new ArithmeticOperation($addition); $engine = new Engine($operation); $calcul = new Calcul($engine, $app['number_collection']); $runner = new CalculRunner(); $runner->run($calcul); $result = $calcul->getResult(); $numericResult = $result->getValue(); $this->response('The answer is: ' . $numericResult);
 })->route('/{first:[0-9]+}', function () use ($app) {
 $firstParsedNumber = $app['number_parser']->parse($this->param('first')); $firstNumber = new SimpleNumber($firstParsedNumber); $firstNumberProxy = new CollectionItemNumberProxy($firstNumber); $app['number_collection']->add($firstNumberProxy);
 })->route('/{second:[0-9]+}', function () use ($app) {
 $secondParsedNumber = $app['number_parser']->parse($this->param('second')); $secondNumber = new SimpleNumber($secondParsedNumber); $secondNumberProxy = new CollectionItemNumberProxy($secondNumber); $app['number_collection']->add($secondNumberProxy);
 })->get();
  • 31. COMING SOON • Proper tests and coverage (!!!) • Handlers for format negotiation, session, locale, etc • Dependency injection through reflection (via trait) • Framework/engine-agnostic view composition and template rendering (separate project)