SlideShare una empresa de Scribd logo
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

Más contenido relacionado

La actualidad más candente

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
 

La actualidad más candente (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
 

Similar a 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
 

Similar a 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)
 

Último

UiPath Test Automation using UiPath Test Suite series, part 1
UiPath Test Automation using UiPath Test Suite series, part 1UiPath Test Automation using UiPath Test Suite series, part 1
UiPath Test Automation using UiPath Test Suite series, part 1DianaGray10
 
How Red Hat Uses FDO in Device Lifecycle _ Costin and Vitaliy at Red Hat.pdf
How Red Hat Uses FDO in Device Lifecycle _ Costin and Vitaliy at Red Hat.pdfHow Red Hat Uses FDO in Device Lifecycle _ Costin and Vitaliy at Red Hat.pdf
How Red Hat Uses FDO in Device Lifecycle _ Costin and Vitaliy at Red Hat.pdfFIDO Alliance
 
WSO2CONMay2024OpenSourceConferenceDebrief.pptx
WSO2CONMay2024OpenSourceConferenceDebrief.pptxWSO2CONMay2024OpenSourceConferenceDebrief.pptx
WSO2CONMay2024OpenSourceConferenceDebrief.pptxJennifer Lim
 
Powerful Start- the Key to Project Success, Barbara Laskowska
Powerful Start- the Key to Project Success, Barbara LaskowskaPowerful Start- the Key to Project Success, Barbara Laskowska
Powerful Start- the Key to Project Success, Barbara LaskowskaCzechDreamin
 
Extensible Python: Robustness through Addition - PyCon 2024
Extensible Python: Robustness through Addition - PyCon 2024Extensible Python: Robustness through Addition - PyCon 2024
Extensible Python: Robustness through Addition - PyCon 2024Patrick Viafore
 
Agentic RAG What it is its types applications and implementation.pdf
Agentic RAG What it is its types applications and implementation.pdfAgentic RAG What it is its types applications and implementation.pdf
Agentic RAG What it is its types applications and implementation.pdfChristopherTHyatt
 
Buy Epson EcoTank L3210 Colour Printer Online.pdf
Buy Epson EcoTank L3210 Colour Printer Online.pdfBuy Epson EcoTank L3210 Colour Printer Online.pdf
Buy Epson EcoTank L3210 Colour Printer Online.pdfEasyPrinterHelp
 
The Value of Certifying Products for FDO _ Paul at FIDO Alliance.pdf
The Value of Certifying Products for FDO _ Paul at FIDO Alliance.pdfThe Value of Certifying Products for FDO _ Paul at FIDO Alliance.pdf
The Value of Certifying Products for FDO _ Paul at FIDO Alliance.pdfFIDO Alliance
 
Connecting the Dots in Product Design at KAYAK
Connecting the Dots in Product Design at KAYAKConnecting the Dots in Product Design at KAYAK
Connecting the Dots in Product Design at KAYAKUXDXConf
 
Introduction to Open Source RAG and RAG Evaluation
Introduction to Open Source RAG and RAG EvaluationIntroduction to Open Source RAG and RAG Evaluation
Introduction to Open Source RAG and RAG EvaluationZilliz
 
Intro in Product Management - Коротко про професію продакт менеджера
Intro in Product Management - Коротко про професію продакт менеджераIntro in Product Management - Коротко про професію продакт менеджера
Intro in Product Management - Коротко про професію продакт менеджераMark Opanasiuk
 
Introduction to FDO and How It works Applications _ Richard at FIDO Alliance.pdf
Introduction to FDO and How It works Applications _ Richard at FIDO Alliance.pdfIntroduction to FDO and How It works Applications _ Richard at FIDO Alliance.pdf
Introduction to FDO and How It works Applications _ Richard at FIDO Alliance.pdfFIDO Alliance
 
Speed Wins: From Kafka to APIs in Minutes
Speed Wins: From Kafka to APIs in MinutesSpeed Wins: From Kafka to APIs in Minutes
Speed Wins: From Kafka to APIs in Minutesconfluent
 
Salesforce Adoption – Metrics, Methods, and Motivation, Antone Kom
Salesforce Adoption – Metrics, Methods, and Motivation, Antone KomSalesforce Adoption – Metrics, Methods, and Motivation, Antone Kom
Salesforce Adoption – Metrics, Methods, and Motivation, Antone KomCzechDreamin
 
AI presentation and introduction - Retrieval Augmented Generation RAG 101
AI presentation and introduction - Retrieval Augmented Generation RAG 101AI presentation and introduction - Retrieval Augmented Generation RAG 101
AI presentation and introduction - Retrieval Augmented Generation RAG 101vincent683379
 
Secure Zero Touch enabled Edge compute with Dell NativeEdge via FDO _ Brad at...
Secure Zero Touch enabled Edge compute with Dell NativeEdge via FDO _ Brad at...Secure Zero Touch enabled Edge compute with Dell NativeEdge via FDO _ Brad at...
Secure Zero Touch enabled Edge compute with Dell NativeEdge via FDO _ Brad at...FIDO Alliance
 
A Business-Centric Approach to Design System Strategy
A Business-Centric Approach to Design System StrategyA Business-Centric Approach to Design System Strategy
A Business-Centric Approach to Design System StrategyUXDXConf
 
Strategic AI Integration in Engineering Teams
Strategic AI Integration in Engineering TeamsStrategic AI Integration in Engineering Teams
Strategic AI Integration in Engineering TeamsUXDXConf
 
Structuring Teams and Portfolios for Success
Structuring Teams and Portfolios for SuccessStructuring Teams and Portfolios for Success
Structuring Teams and Portfolios for SuccessUXDXConf
 
Optimizing NoSQL Performance Through Observability
Optimizing NoSQL Performance Through ObservabilityOptimizing NoSQL Performance Through Observability
Optimizing NoSQL Performance Through ObservabilityScyllaDB
 

Último (20)

UiPath Test Automation using UiPath Test Suite series, part 1
UiPath Test Automation using UiPath Test Suite series, part 1UiPath Test Automation using UiPath Test Suite series, part 1
UiPath Test Automation using UiPath Test Suite series, part 1
 
How Red Hat Uses FDO in Device Lifecycle _ Costin and Vitaliy at Red Hat.pdf
How Red Hat Uses FDO in Device Lifecycle _ Costin and Vitaliy at Red Hat.pdfHow Red Hat Uses FDO in Device Lifecycle _ Costin and Vitaliy at Red Hat.pdf
How Red Hat Uses FDO in Device Lifecycle _ Costin and Vitaliy at Red Hat.pdf
 
WSO2CONMay2024OpenSourceConferenceDebrief.pptx
WSO2CONMay2024OpenSourceConferenceDebrief.pptxWSO2CONMay2024OpenSourceConferenceDebrief.pptx
WSO2CONMay2024OpenSourceConferenceDebrief.pptx
 
Powerful Start- the Key to Project Success, Barbara Laskowska
Powerful Start- the Key to Project Success, Barbara LaskowskaPowerful Start- the Key to Project Success, Barbara Laskowska
Powerful Start- the Key to Project Success, Barbara Laskowska
 
Extensible Python: Robustness through Addition - PyCon 2024
Extensible Python: Robustness through Addition - PyCon 2024Extensible Python: Robustness through Addition - PyCon 2024
Extensible Python: Robustness through Addition - PyCon 2024
 
Agentic RAG What it is its types applications and implementation.pdf
Agentic RAG What it is its types applications and implementation.pdfAgentic RAG What it is its types applications and implementation.pdf
Agentic RAG What it is its types applications and implementation.pdf
 
Buy Epson EcoTank L3210 Colour Printer Online.pdf
Buy Epson EcoTank L3210 Colour Printer Online.pdfBuy Epson EcoTank L3210 Colour Printer Online.pdf
Buy Epson EcoTank L3210 Colour Printer Online.pdf
 
The Value of Certifying Products for FDO _ Paul at FIDO Alliance.pdf
The Value of Certifying Products for FDO _ Paul at FIDO Alliance.pdfThe Value of Certifying Products for FDO _ Paul at FIDO Alliance.pdf
The Value of Certifying Products for FDO _ Paul at FIDO Alliance.pdf
 
Connecting the Dots in Product Design at KAYAK
Connecting the Dots in Product Design at KAYAKConnecting the Dots in Product Design at KAYAK
Connecting the Dots in Product Design at KAYAK
 
Introduction to Open Source RAG and RAG Evaluation
Introduction to Open Source RAG and RAG EvaluationIntroduction to Open Source RAG and RAG Evaluation
Introduction to Open Source RAG and RAG Evaluation
 
Intro in Product Management - Коротко про професію продакт менеджера
Intro in Product Management - Коротко про професію продакт менеджераIntro in Product Management - Коротко про професію продакт менеджера
Intro in Product Management - Коротко про професію продакт менеджера
 
Introduction to FDO and How It works Applications _ Richard at FIDO Alliance.pdf
Introduction to FDO and How It works Applications _ Richard at FIDO Alliance.pdfIntroduction to FDO and How It works Applications _ Richard at FIDO Alliance.pdf
Introduction to FDO and How It works Applications _ Richard at FIDO Alliance.pdf
 
Speed Wins: From Kafka to APIs in Minutes
Speed Wins: From Kafka to APIs in MinutesSpeed Wins: From Kafka to APIs in Minutes
Speed Wins: From Kafka to APIs in Minutes
 
Salesforce Adoption – Metrics, Methods, and Motivation, Antone Kom
Salesforce Adoption – Metrics, Methods, and Motivation, Antone KomSalesforce Adoption – Metrics, Methods, and Motivation, Antone Kom
Salesforce Adoption – Metrics, Methods, and Motivation, Antone Kom
 
AI presentation and introduction - Retrieval Augmented Generation RAG 101
AI presentation and introduction - Retrieval Augmented Generation RAG 101AI presentation and introduction - Retrieval Augmented Generation RAG 101
AI presentation and introduction - Retrieval Augmented Generation RAG 101
 
Secure Zero Touch enabled Edge compute with Dell NativeEdge via FDO _ Brad at...
Secure Zero Touch enabled Edge compute with Dell NativeEdge via FDO _ Brad at...Secure Zero Touch enabled Edge compute with Dell NativeEdge via FDO _ Brad at...
Secure Zero Touch enabled Edge compute with Dell NativeEdge via FDO _ Brad at...
 
A Business-Centric Approach to Design System Strategy
A Business-Centric Approach to Design System StrategyA Business-Centric Approach to Design System Strategy
A Business-Centric Approach to Design System Strategy
 
Strategic AI Integration in Engineering Teams
Strategic AI Integration in Engineering TeamsStrategic AI Integration in Engineering Teams
Strategic AI Integration in Engineering Teams
 
Structuring Teams and Portfolios for Success
Structuring Teams and Portfolios for SuccessStructuring Teams and Portfolios for Success
Structuring Teams and Portfolios for Success
 
Optimizing NoSQL Performance Through Observability
Optimizing NoSQL Performance Through ObservabilityOptimizing NoSQL Performance Through Observability
Optimizing NoSQL Performance Through Observability
 

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)