Upgrade to Pro — share decks privately, control downloads, hide ads and more …

PHPer人生、一度はフレームワークを作っておこう!

uzulla
April 16, 2016

 PHPer人生、一度はフレームワークを作っておこう!

PHPカンファレンス北海道 2016 発表資料
20160416

uzulla

April 16, 2016
Tweet

More Decks by uzulla

Other Decks in Programming

Transcript

  1. ༗໊ͳFW Symfony, Laravel, Lumen, Slim Framework, Yii, PHPixie, FuelPHP, CodeIgniter,

    CakePHP, ZendFramework, Phalcon, Nette, Silex, fatfree, limonade, DietCake, DietCube, Lithium, Aura, Ethna, etc. etc. 㙽ʹ֯୔ࢁ
  2. FWΛ࢖͏ཧ༝ - ੜ࢈ੑͷ޲্ - ܾ·Γ੾ͬͨίʔυΛॻ͔ͣʹࡁΉ - ྑ͋͘Δػೳ͸ϓϥάΠϯ͕͋Δ͜ͱ΋ - ʮ੍ݶʯ͕Ͱ͖Δ͜ͱͰɺઃܭ͕͠΍͍͢ -

    ඼࣭ͷ޲্ - ϩδοΫʹूதͰ͖ɺ৽نίʔυྔΛݮΒͤΔ - ʮྑ͍ઃܭʯ͔Βဃ཭ͮ͠Β͘ͳΔ - ηΩϡϦςΟϗʔϧ͕উखʹຒΊΒΕ͍ͯΔࣄ΋ଟ͍ - େن໛։ൃͷجૅʹͳΓ΍͍͢ - νʔϜʹن໿Λཁٻ͠΍͍͢ - ʢେ఍ʣγοΧϦͨ͠υΩϡϝϯτ͕ଘࡏ͢ΔͷͰֶशɾڭҭ͠΍͍͢
  3. ʮςϯϓϨʔτΤϯδϯ΋ॏཁͩʯ » ςϯϓϨʔτΤϯδϯͱͯ͠PHP͸ΞϧςΟϝοτ » ηΩϡΞ͞Λపఈ͢Δͷ͕Ή͔ͣ͗͢͠Δ <?php echo $_GET['foo']; ?> »

    ͜͜ʹ͍Δਓ͕ॻ͘ͱ͸ࢥ͑ͳ͍͕ɺ΢οΧϦॻ͚ ͪΌ͏ » ʢBlogΧελϜҊ݅ͩͱׂͱݟΔ…ίϫΠ…ʣ » ʮੈքฏ࿨ͷҝʹPHPͷྗΛ෧ҹ͢Δඞཁ͕͋Δʯ
  4. ׬!

  5. Routing, Middleware, Controllers, Requests, Responses, Views, Blade Templates, Authentication, Authorization,

    Artisan Console, Billing, Cache, Collections, Elixir, Encryption, Errors & Logging, Events, Filesystem / Cloud Storage, Hashing, Helpers, Localization, Mail, Package Development, Pagination, Queues, Redis, Session, SSH Tasks, Task Scheduling, Testing, Validation, Query Builder, Migrations, Seeding, Eloquent ORM,
  6. <?php // index.php require_once(dirname(dirname(__FILE__)) . "/app/ore.php"); define("DB_DSN", 'sqlite:' . dirname(dirname(__FILE__))

    . "/db.sqlite"); option('HTML_TITLE', "ͳ͔ͭ͠ͷੈքͰ͢"); route('/', 'post_list'); route('/post/create', 'post_create'); route('/post/:id', 'post_show'); route('/reset', 'post_reset'); run(); ?>
  7. function route($path = null, $func_name = null) { // ؔ਺ऴྃ࣌ʹ΋ফ͑ͳ͍഑ྻͱͯ͠$route_listΛએݴ

    static $route_list = array(); // $keyͱ$val྆ํʹԿ͔ೖ͍ͬͯΕ͹ɺ$pathΛΩʔʹ$func_nameΛอଘ if (!is_null($path) && !is_null($func_name)) $route_list[$path] = $func_name; // Ҿ਺ࢦఆແ͠ͳΒɺ$route_listΛ·Δ͝ͱฦ͢ if (is_null($path)) return $route_list; // $pathҾ਺͕༗ΓɺͦͷΩʔ͕route_listʹ͋Ε͹ɺͦΕΛฦ͢ if (isset($route_list[$path])) return $route_list[$path]; // Έ͔ͭΒͳ͔ͬͨͷͰɺnullΛฦ͢ return null; }
  8. function find_match_path() { $uri = $_SERVER['REQUEST_URI']; foreach (path_regex() as $path

    => $regex) { if (preg_match($regex, $uri, $matches)) { $match_path = $path; break; } } if (!isset($match_path)) { return 'notfound'; } foreach ($matches as $k => $v) { if (preg_match('/^[0-9]/u', $k)) { continue; } option($k, urldecode($v)); } return $match_path; }
  9. function path_regex() { $regex_list = array(); foreach (route() as $route

    => $cb) { $regex_list[$route] = '#\A' . preg_replace_callback( '#:([\w]+)#', function ($m) { return "(?P<{$m[1]}>[^/]+)"; }, $route ) . '\z#'; // ex: #\A/post/(?P<id>[^/]+)\z# } return $regex_list; }
  10. ػೳ (ݱ࣮) » ϧʔλʔ » TwigͬΆ͍ςϯϓϨʔτΤϯδϯ × » ϩΨʔ »

    PSR-7ɺMiddlewareରԠ˚ » ίϯςφʢϩέʔλʣ » ηογϣϯ ˚
  11. <?php //index.php declare(strict_types=1); include __DIR__."/../vendor/autoload.php"; // Route ొ࿥ $router =

    new \Ore2\Router(); $router->get('/', function(){ return $this->html('<span style="color:red">123</span>'); }); $router->get('/name/:name', function(){ return $this->html("hello {$this->c->routeParams['name']}"); }); $router->get('/sample', '\\MyApp\\SampleAction::sample'); $router->get('/sample_json', '\\MyApp\\SampleAction::sampleJson'); // PSR-7ΦϒδΣΫτͷϑΝΫτϦΛ࣮૷͢ΔͷఘΊ·ͨ͠ $request = \Zend\Diactoros\ServerRequestFactory::fromGlobals(); $response = new \Zend\Diactoros\Response(); // route ղܾ $match_result = $router->findMatch($request->getMethod(), $request->getRequestTarget()); // ֤छϔϧύʔΛίϯςφʹ͍ΕΔ $container = new \Ore2\Container(); $container->config = require __DIR__."/../settings.php"; $container->session = new \Ore2\Session(new \Ore2\Session\Storage\PHPSession()); $container->template = new \Ore2\Template($container->config['template']); $container->logger = new \Ore2\Logger(); // ΞΫγϣϯΛ࡞੒ $action = $match_result->buildAction($container); // Middlewareͱ࣮ͯ͠ߦ $seqencer = new \Ore2\MiddlewareSequencer([ new \Ore2\Transmitter(), $action ]); $seqencer($request, $response);
  12. » ίϯςφ͸ҙຯͳ͘PSR-11(Draft)ʹ΋ରԠ͠ɺ ArrayAccessͱ__get/set΋࣮૷ » Session͸(ҰԠ)PSR-7Ͱಈ͘Α͏ʹ࡞੒ » CSRFΨʔυ΍ྫ֎τϥοϓ౳ΛPSR-7 Middleware ͱ࣮ͯ͠૷ »

    relay(relayphp.com)෩ͷϛυϧ΢ΣΞ࣮ߦػೳΛ ༻ҙ » ϧʔτઃఆͰɺΞΫγϣϯʹΫϩʔδϟΛ౉ͯ͠΋ bindToͰ$thisܦ༝Ͱ৭ʑ৮ΕΔ » etc,etc
  13. ͳʹ͕خ͍͠ͷʁ » ී௨͸ɺಛʹ͏Ε͘͠ͳ͍ » ݸਓతʹ͸ » ΦϨΦϨFWѪ޷Ոతʹ͸ָʹςετͰ͖ͦ͏ » ଞͷݴޠͬΆͯࣗ͘વʹײͯ͡خ͍͠ »

    ReactPHP౳ΞϓϦέʔγϣϯαʔόʔ͕ରԠ͢ Ε͹ָͦ͠͏ʂ=>࣮ࡍπΠʔτΛݟͨ » Middleware͕ͨͷͦ͠͏
  14. // ZendͷPSR-7࣮૷ $request = \Zend\Diactoros\ServerRequestFactory::fromGlobals(); $response = new \Zend\Diactoros\Response(); //

    ΞΫγϣϯΛϧʔλʔͰܾఆ ΞΫγϣϯ = ϧʔλʔ($request); // ࣮ߦ $response = ΞΫγϣϯ($request, $response); // ԿΒ͔ͷํ๏Ͱ$responseΛૹ৴ ૹ৴͢Δ܅($response);
  15. // request͔ΒPOSTऔಘྫ $name = $request->parsedBody['name'] ?? ''; // ϨεϙϯεΦϒδΣΫτ࡞੒ $response

    = $response ->withStatus(200); ->withHeader('Content-Type', 'text/html'); $body = new \Zend\Diactoros\Stream('php://memory', 'w'); $body->write("Hello world"); $response = $response->withBody($body); return $response; // ͜ͷޙͰૹ৴܅ͳͲͰૹ৴͞ΕΔ
  16. PSR-7 middlewareʹ͍ͭͯ » ঢ়ଶ͕άϩʔόϧม਺͔ΒҾ͖͸͕͞ΕͨͷͰɺϑΟ ϧλʔΈ͍ͨͳ͜ͱ͕΍Γ΍͍͢ » Rack Middleware΍Plack Middleware »

    ʮͦ͜ΒͷFWʹ΋ϛυϧ΢ΣΞ͋Δ͡ΌΜʁʯ ʮͦΕ͕શ෦ͷFWͰڞ௨ͷIFʹͳΕ͹ɺເ͕ʁʯ ʮʮ޿͕Δʂʂʯʯ
  17. » Ore » 9 commits / 588 ++ / 168

    -- » Ore2 » 62 commits / 4,106 ++ / 1,063 --
  18. <?php include __DIR__."/../vendor/autoload.php"; \MyApp\Db::$pdo = new \PDO("sqlite:".__DIR__."/../db.sqlite"); $container = [

    'template' => new Twig_Environment( new Twig_Loader_Filesystem(__DIR__."/../template") ) ]; $routing_map = [ ['GET', '/', '\MyApp\Post::showList' ], ['GET', '/post/:id', '\MyApp\Post::show', ['id' => '/^(\d+)$/']], ['POST', '/post/create', '\MyApp\Post::create' ], ['GET', '/reset', '\MyApp\Post::reset' ], '#404' => '\MyApp\Post::notfound' ]; $router = new \Teto\Routing\Router($routing_map); $action = $router->match($_SERVER['REQUEST_METHOD'], $_SERVER['REQUEST_URI']); if (!preg_match('|\A([\\a-zA-Z0-9_]*)::([a-zA-Z0-9_]+)\z|u', $action->value, $matches)) throw new \InvalidArgumentException('invalid action string:' . $action->value); $method_name = $matches[2]; (new $matches[1]($container))->$method_name($action->param);
  19. » 2 commits / 398 ++ / 0 -- »

    ੡࡞࣌ؒ30෼͆ʂ » ୹͍ʂ
  20. ׬