Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Silex (phpday)
Search
Igor Wiedler
May 29, 2012
Programming
11
1.4k
Silex (phpday)
Igor Wiedler
May 29, 2012
Tweet
Share
More Decks by Igor Wiedler
See All by Igor Wiedler
Redis Bedtime Stories
igorw
1
290
Wide Event Analytics (LISA19)
igorw
4
910
a day in the life of a request
igorw
0
130
production: an owner's manual
igorw
0
150
The Power of 2
igorw
0
280
LISP 1.5 Programmer's Manual: A Dramatic Reading
igorw
0
400
The Moral Character of Software
igorw
1
260
interdisciplinary computing (domcode)
igorw
0
270
miniKanren (clojure berlin)
igorw
1
280
Other Decks in Programming
See All in Programming
Hack Claude Code with Claude Code
choplin
5
2.3k
AIプログラマーDevinは PHPerの夢を見るか?
shinyasaita
1
230
PipeCDのプラグイン化で目指すところ
warashi
1
280
Blazing Fast UI Development with Compose Hot Reload (droidcon New York 2025)
zsmb
1
300
設計やレビューに悩んでいるPHPerに贈る、クリーンなオブジェクト設計の指針たち
panda_program
6
2.2k
ソフトウェア品質を数字で捉える技術。事業成長を支えるシステム品質の マネジメント
takuya542
2
14k
AIと”コードの評価関数”を共有する / Share the "code evaluation function" with AI
euglena1215
1
170
dbt民主化とLLMによる開発ブースト ~ AI Readyな分析サイクルを目指して ~
yoshyum
3
1k
RailsGirls IZUMO スポンサーLT
16bitidol
0
190
AIともっと楽するE2Eテスト
myohei
7
2.8k
なぜ適用するか、移行して理解するClean Architecture 〜構造を超えて設計を継承する〜 / Why Apply, Migrate and Understand Clean Architecture - Inherit Design Beyond Structure
seike460
PRO
3
780
VS Code Update for GitHub Copilot
74th
2
660
Featured
See All Featured
I Don’t Have Time: Getting Over the Fear to Launch Your Podcast
jcasabona
32
2.4k
Into the Great Unknown - MozCon
thekraken
40
1.9k
Music & Morning Musume
bryan
46
6.6k
How to Create Impact in a Changing Tech Landscape [PerfNow 2023]
tammyeverts
53
2.9k
Designing for Performance
lara
610
69k
Visualizing Your Data: Incorporating Mongo into Loggly Infrastructure
mongodb
46
9.6k
Typedesign – Prime Four
hannesfritz
42
2.7k
What's in a price? How to price your products and services
michaelherold
246
12k
ReactJS: Keep Simple. Everything can be a component!
pedronauck
667
120k
Keith and Marios Guide to Fast Websites
keithpitt
411
22k
Improving Core Web Vitals using Speculation Rules API
sergeychernyshev
18
980
The Invisible Side of Design
smashingmag
301
51k
Transcript
None
• phpBB • Symfony2 • Silex • Composer igorw @igorwesome
None
$s=stream_socket_server('tcp://127.0.0.1:81'); while($c=stream_socket_accept($s)) fwrite($c,"HTTP/1.1 200 OK\r\nContent-Length: 2\r\n\r\nHi");
require __DIR__.'/c.php'; if (!is_callable($c = @$_GET['c'] ?: function() { echo
'Woah!'; })) throw new Exception('Error'); $c();
Silex Symfony2 μ-framework
Silex is not Symfony
Microframework
None
What? • Bare bones • Routes mapped to controllers •
The ‘C’ of ‘MVC’ • REST • Single file app (ish)
Why?
Sometimes a full-stack framework is too much for a simple
task.
simple
What makes silex special?
• concise • extensible • testable
• concise • extensible • testable
• concise • extensible • testable
• concise • extensible • testable
• concise • extensible • testable
Http Kernel Interface
Response handle(Request $request)
client
request client
reponse client request
clean
PSR-0
None
Silex is not Symfony
Silex is a user interface for Symfony
require_once __DIR__.'/silex.phar'; $app = new Silex\Application(); $app->get('/', function() { return
"Hello world!"; });
Phar require_once __DIR__.'/silex.phar'; $app = new Silex\Application(); $app->get('/', function() {
return "Hello world!"; });
Phar require_once __DIR__.'/silex.phar'; $app = new Silex\Application(); $app->get('/', function() {
return "Hello world!"; }); = FUBAR
Composer require_once 'vendor/autoload.php'; $app = new Silex\Application(); $app->get('/', function() {
return "Hello world!"; });
Application require_once 'vendor/autoload.php'; $app = new Silex\Application(); $app->get('/', function() {
return "Hello world!"; });
require_once 'vendor/autoload.php'; $app = new Silex\Application(); $app->get('/', function() { return
"Hello world!"; }); Controller
$app->run();
None
<IfModule mod_rewrite.c> RewriteEngine On RewriteBase /some/path RewriteCond %{REQUEST_FILENAME} !-f RewriteCond
%{REQUEST_FILENAME} !-d RewriteRule ^(.*)$ index.php [QSA,L] </IfModule>
server { index index.php location / { try_files $uri $uri/
/index.php; } location ~ index\.php$ { fastcgi_pass /var/run/php5-fpm.sock; fastcgi_index index.php; include fastcgi_params; } }
Wait a minute!
Lambdas λ
$(function () { $("a").on("click", function (event) { alert("Thanks for visiting!");
}); });
PHP 5.3
$f = function ($a, $b) { return $a + $b;
}; $f(1, 2);
lazy $f = function () { exit; };
nested $f = function () { return function () {
return true; }; }; $g = $f(); $value = $g();
scope $outer = 'world'; $f = function () use ($outer)
{ $inner = 'hello'; return "$inner $outer"; }; => "hello world"
scope $helloWorld = function () { $outer = 'world'; $f
= function () use ($outer) { $inner = 'hello'; return "$inner $outer"; }; return $f(); }
passing $output = function ($info) { echo $info."\n"; }; $doStuff
= function ($output) { $output('doing some magic'); doMagic(); $output('did some magic'); };
factory $userFactory = function ($name) { return new User($name); };
// ... $user = $userFactory($_POST['name']);
event listener $emitter = new EventEmitter(); $emitter->on('user.create', function (User $user)
{ $msg = sprintf("User %s created.", $user->name); log($msg); });
Usage
$app->get('/', function () { return "Hello world!"; });
Dynamic Routing
$app->get('/hello/{name}', function ($name) use ($app) { return "Hello ".$app->escape($name); });
$app->get('/hello/{name}', function ($name) use ($app) { return "Hello ".$app->escape($name); });
Controllers
assert $app->get('/blog/{id}', function ($id) { ... }) ->assert('id', '\d+');
value $app->get('/{page}', function ($page) { ... }) ->value('page', 'index');
bind $app->get('/', function () { ... }) ->bind('homepage'); $app['url_generator']->generate('homepage')
bind $app->get('/blog/{id}', function ($id) { ... }) ->bind('blog.post'); $app['url_generator'] ->generate('blog.post',
array('id' => $id))
convert $app->get('/blog/{post}', function (Post $post) { ... }) ->convert('post', function
($post) use ($app) { $id = (int) $post; return $app['posts']->find($id); });
Before & After
$app->before(function () { ... }); $app->get('/', function () { ...
}); $app->after(function () { ... });
$app->before(function (Request $request) { $loggedIn = $request ->getSession() ->get('logged_in'); if
(!$loggedIn) { return new RedirectResponse('/login'); } });
$app->after(function (Request $request, Response $response) { // tweak the Response
});
Methods
• get • post • put • delete • head
• options
$app->get('/posts/{id}', ...); $app->post('/posts', ...); $app->put('/posts/{id}', ...); $app->delete('/post/{id}', ...);
use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; $app->post('/message', function (Request $request) { mail(
'
[email protected]
', 'New message', $request->get('body') ); return new Response('Email has been sent!', 201); });
Caching
Error Handling
use Symfony\Component\HttpFoundation\Response; $app->error(function (\Exception $e, $code) { return new Response('Whoops!',
$code); });
$app->abort(404, "Could not find the thing.");
$app['debug'] = true;
Redirecting
$app->get('/', function () use ($app) { return $app->redirect('/hello'); });
Pimple
~50 NCLOC
$container = new Pimple();
$app = new Silex\Application();
Parameters $app['some_parameter'] = 'value'; $app['asset.host'] = 'http://cdn.mysite.com/'; $app['database.dsn'] = 'mysql:dbname=myapp';
Services $app['some_service'] = function () { return new Service(); };
$service = $app['some_service'];
Dependencies $app['some_service'] = function ($app) { return new Service( $app['some_other_service'],
$app['some_service.config'] ); };
Shared $app['some_service'] = $app->share(function () { return new Service(); });
Protected $app['lambda_parameter'] = $app->protect( function ($a, $b) { return $a
+ $b; }); // will not execute the lambda $add = $app['lambda_parameter']; // calling it now echo $add(2, 3);
Exposed Services • debug • request • autoloader • routes
• controllers • dispatcher • resolver • kernel
Service Providers
interface ServiceProviderInterface { function register(Application $app); }
Core Service Providers • doctrine • form • http cache
• monolog • session • swiftmailer • symfony bridges • translation • twig • url generator • validator
3rd Party • doctrine orm • propel • pomm (postgres)
• predis • mongo • KyotoTycoon • memcache • rest • markdown • gravatar • buzz • config • solr • profiler • ...
Redis
$app->register(new PredisServiceProvider());
$app->get('/{id}', function ($id) use ($app) { $key = 'pastes:'.$id; $paste
= $app['predis']->hgetall($key); ... });
None
• smallish sites • well-defined scope • prototyping • restful
apis When to use
and many more...
None
New feature: Streaming
$app->get('/some-video', function () use ($app) { $file = $app['app.video_filename']; $stream
= function () use ($file) { readfile($file); }; return $app->stream( $stream, 200, array('Content-Type' => 'video/mpeg') ); });
New feature: Middlewares
$mustBeLogged = function (Request $request) use ($app) { if (!$app['session']->has('userId'))
{ return $app->redirect('/user/login'); } }; $app->get('/user/my-profile', function () { ... }) ->middleware($mustBeLogged);
New feature: JSON helper
$app->get('/users/{id}', function ($id) use ($app) { $user = getUser($id); if
(!$user) { $message = 'The user was not found.'; $error = array('message' => $message); return $app->json($error, 404); } return $app->json($user); });
New feature: Finish filter
$app->finish(function () { // send e-mails // very slow query
// some slow API calls });
New feature: Composer
None
{ "minimum-stability": "dev", "require": { "silex/silex": "1.0.*@dev" } } composer.json
$ php composer.phar install
require 'vendor/autoload.php';
on github fabpot/Silex fabpot/Pimple
silex.sensiolabs.org
Ω
Questions? joind.in/6391 @igorwesome speakerdeck.com /u/igorw