SlideShare a Scribd company logo
フラットなPHPから
 フレームワークへ
       株式会社 adingo
      前田 雅央 @brtriver
@brtriver
Steps


         フラットなPHP

             リファクタリング




          フレームワーク


        * フラットなPHP = 1ファイルで書かれたPHP
Steps
            フラットなPHP
             View部分の分離

        アプリケーション(ドメイン)部分の分離

          Viewにレイアウト機能を追加

             ページを追加する

          フロントコントローラー導入

            ライブラリを利用する


            フレームワーク
どのフレームワークを使う?


なぜフレームワークを使う?
Step 0




     DBからデータ取得し
          取得したデータを
         HTMLで表示する
<?php
$pdo = new PDO(
   'mysql:host=localhost;dbname=blog_db;charset=utf8',
                                                                           list.php
   'myuser',
   'mypassword',
   array(PDO::ATTR_EMULATE_PREPARES => false)
 );
$stmt = $pdo->query('SELECT id, title FROM post');
?>


<html>
  <head>
    <title>投稿の一覧</title>
  </head>
  <body>
    <h1>投稿の一覧</h1>
    <ul>
       <?php while ($row = $stmt->fetch(PDO::FETCH_ASSOC)): ?>
       <li>
          <a href="show.php?id=<?php echo htmlspecialchars($row['id'], ENT_QUOTES, 'utf-8') ?>">
             <?php echo htmlspecialchars($row['title'], ENT_QUOTES, 'utf-8') ?>
          </a>
       </li>
       <?php endwhile; ?>
    </ul>
  </body>
</html>
<?php
$pdo = new PDO(
   'mysql:host=localhost;dbname=blog_db;charset=utf8',
                                                                           list.php
   'myuser',
   'mypassword',
   array(PDO::ATTR_EMULATE_PREPARES => false)
 );
$stmt = $pdo->query('SELECT id, title FROM post');
?>


<html>
  <head>
    <title>投稿の一覧</title>
  </head>
  <body>
    <h1>投稿の一覧</h1>
    <ul>
       <?php while ($row = $stmt->fetch(PDO::FETCH_ASSOC)): ?>
       <li>
          <a href="show.php?id=<?php echo htmlspecialchars($row['id'], ENT_QUOTES, 'utf-8') ?>">
             <?php echo htmlspecialchars($row['title'], ENT_QUOTES, 'utf-8') ?>
          </a>
       </li>
       <?php endwhile; ?>
    </ul>
  </body>
</html>
<?php
$pdo = new PDO(
   'mysql:host=localhost;dbname=blog_db;charset=utf8',
                                                                           list.php
   'myuser',
   'mypassword',
   array(PDO::ATTR_EMULATE_PREPARES => false)
 );
$stmt = $pdo->query('SELECT id, title FROM post');
?>


<html>
  <head>
    <title>投稿の一覧</title>
  </head>
  <body>
    <h1>投稿の一覧</h1>
    <ul>
       <?php while ($row = $stmt->fetch(PDO::FETCH_ASSOC)): ?>
       <li>
          <a href="show.php?id=<?php echo htmlspecialchars($row['id'], ENT_QUOTES, 'utf-8') ?>">
             <?php echo htmlspecialchars($row['title'], ENT_QUOTES, 'utf-8') ?>
          </a>
       </li>
       <?php endwhile; ?>
    </ul>
  </body>
</html>
<?php
$pdo = new PDO(
   'mysql:host=localhost;dbname=blog_db;charset=utf8',
                                                                           list.php
   'myuser',


DBからデータ取得
 );
   'mypassword',
   array(PDO::ATTR_EMULATE_PREPARES => false)


$stmt = $pdo->query('SELECT id, title FROM post');
?>


<html>
  <head>
    <title>投稿の一覧</title>
  </head>
  <body>
    <h1>投稿の一覧</h1>
    <ul>
       <?php while ($row = $stmt->fetch(PDO::FETCH_ASSOC)): ?>
       <li>
          <a href="show.php?id=<?php echo htmlspecialchars($row['id'], ENT_QUOTES, 'utf-8') ?>">
             <?php echo htmlspecialchars($row['title'], ENT_QUOTES, 'utf-8') ?>
          </a>
       </li>
       <?php endwhile; ?>
    </ul>
  </body>
</html>
<?php
$pdo = new PDO(
   'mysql:host=localhost;dbname=blog_db;charset=utf8',
                                                                           list.php
   'myuser',


DBからデータ取得
 );
   'mypassword',
   array(PDO::ATTR_EMULATE_PREPARES => false)


$stmt = $pdo->query('SELECT id, title FROM post');
?>


<html>
  <head>
    <title>投稿の一覧</title>
  </head>
  <body>
    <h1>投稿の一覧</h1>
    <ul>
       <?php while ($row = $stmt->fetch(PDO::FETCH_ASSOC)): ?>



             取得したデータを表示
       <li>
          <a href="show.php?id=<?php echo htmlspecialchars($row['id'], ENT_QUOTES, 'utf-8') ?>">
             <?php echo htmlspecialchars($row['title'], ENT_QUOTES, 'utf-8') ?>
          </a>
       </li>
       <?php endwhile; ?>
    </ul>
  </body>
</html>
クライアント             サーバー




          リクエスト
                  PHP +
Browser
                  HTML
          レスポンス
                  list.php
Good

       シンプル
       1ファイルたったの26行
Bad
アプリケーションの拡張性が無い


      体系化されていない
       再利用性がない
体系化されていない




フォームの送信を行うコードの追加したい...

            どこに書く?



   同じファイル?別ファイルで書く?
コードの再利用性が低い
 新しい別ファイルでlist.phpのコードを利用
 できない。




     新しいページを コピペで作成
クライアント                     サーバー


             エ スト       PHP + HTML
           リク

                 ポ ンス
            レス            list.php
 Browser




                                     Bad
クライアント                     サーバー


             エ スト       PHP + HTML
           リク

                 ポ ンス
            レス            list.php
 Browser                             COPY




                                     Bad
クライアント                      サーバー


             エ スト        PHP + HTML
           リク

                  ポ ンス
             レス            list.php
 Browser                              COPY
           リクエ
                スト

                         PHP + HTML
           レスポ
               ンス

                          list2.php



                                      Bad
Step 1




         View部分の分離
show.php
<?php
$pdo = new PDO(
   'mysql:host=localhost;dbname=blog_db;charset=utf8',
   'myuser',
   'mypassword',
   array(PDO::ATTR_EMULATE_PREPARES => false)
 );
$stmt = $pdo->query('SELECT id, title FROM post');
?>


<html>
  <head>
    <title>投稿の一覧</title>
  </head>
  <body>
    <h1>投稿の一覧</h1>
    <ul>
       <?php while ($row = $stmt->fetch(PDO::FETCH_ASSOC)): ?>
       <li>
          <a href="show.php?id=<?php echo htmlspecialchars($row['id'], ENT_QUOTES, 'utf-8') ?>">
             <?php echo htmlspecialchars($row['title'], ENT_QUOTES, 'utf-8') ?>
          </a>
       </li>
       <?php endwhile; ?>
    </ul>
  </body>
</html>
show.php
<?php
$pdo = new PDO(
   'mysql:host=localhost;dbname=blog_db;charset=utf8',
   'myuser',



 );
   'mypassword',
                            ロジック部分
   array(PDO::ATTR_EMULATE_PREPARES => false)


$stmt = $pdo->query('SELECT id, title FROM post');
?>


<html>
  <head>
    <title>投稿の一覧</title>
  </head>
  <body>
    <h1>投稿の一覧</h1>
    <ul>
       <?php while ($row = $stmt->fetch(PDO::FETCH_ASSOC)): ?>
       <li>
          <a href="show.php?id=<?php echo htmlspecialchars($row['id'], ENT_QUOTES, 'utf-8') ?>">
             <?php echo htmlspecialchars($row['title'], ENT_QUOTES, 'utf-8') ?>
          </a>
       </li>
       <?php endwhile; ?>
    </ul>
  </body>
</html>
show.php
<?php
$pdo = new PDO(
   'mysql:host=localhost;dbname=blog_db;charset=utf8',
   'myuser',



 );
   'mypassword',
                            ロジック部分
   array(PDO::ATTR_EMULATE_PREPARES => false)


$stmt = $pdo->query('SELECT id, title FROM post');
?>


<html>
  <head>
    <title>投稿の一覧</title>
  </head>
  <body>
    <h1>投稿の一覧</h1>
    <ul>
                 View(HTML)部分
       <?php while ($row = $stmt->fetch(PDO::FETCH_ASSOC)): ?>
       <li>
          <a href="show.php?id=<?php echo htmlspecialchars($row['id'], ENT_QUOTES, 'utf-8') ?>">
             <?php echo htmlspecialchars($row['title'], ENT_QUOTES, 'utf-8') ?>
          </a>
       </li>
       <?php endwhile; ?>
    </ul>
  </body>
</html>
show.php
<?php
$pdo = new PDO(
   'mysql:host=localhost;dbname=blog_db:charset=utf8',
   'myuser',
   'mypassword',
   array(PDO::ATTR_EMULATE_PREPARES => false)
 );
$stmt = $pdo->query('SELECT id, title FROM post');


// HTML部分のコードを読み込む
require 'templates/list.php';

                        別ファイルに分離
show.php
<?php
$pdo = new PDO(
   'mysql:host=localhost;dbname=blog_db:charset=utf8',
   'myuser',
   'mypassword',  ロジック部分
   array(PDO::ATTR_EMULATE_PREPARES => false)
 );
$stmt = $pdo->query('SELECT id, title FROM post');


// HTML部分のコードを読み込む
require 'templates/list.php';

                        別ファイルに分離
クライアント                サーバー




          リクエスト   controller
Browser              PHP
                      list.php
クライアント                サーバー




          リクエスト   controller
Browser              PHP
                      list.php
クライアント                 サーバー




           リクエスト   controller
Browser               PHP
                       list.php




          レスポンス
                   view
                     HTML
                   template/list.php
クライアント                   サーバー




           リクエスト    controller
Browser                  PHP
                         list.php




          レスポンス
                    view
                         json
                   template/list-json.php
Good
       View部分の分離



   テンプレートの変更に強い
Step 2




  アプリケーション(ドメイン)
      部分の分離
index.php
<?php
$pdo = new PDO(
   'mysql:host=localhost;dbname=blog_db:charset=utf8',
   'myuser',
   'mypassword',
   array(PDO::ATTR_EMULATE_PREPARES => false)
 );
$stmt = $pdo->query('SELECT id, title FROM post');
index.php
<?php
$pdo = new PDO(
   'mysql:host=localhost;dbname=blog_db:charset=utf8',

         データベースへ接続する
   'myuser',
   'mypassword',
   array(PDO::ATTR_EMULATE_PREPARES => false)
 );
$stmt = $pdo->query('SELECT id, title FROM post');
index.php
<?php
$pdo = new PDO(
   'mysql:host=localhost;dbname=blog_db:charset=utf8',

         データベースへ接続する
   'myuser',
   'mypassword',
   array(PDO::ATTR_EMULATE_PREPARES => false)
 );

         全てのポストを取得する
$stmt = $pdo->query('SELECT id, title FROM post');
ドメイン
  データベースへの接続する
  全てのポストを取得する



   model.php に分離
<?php


// model.php


function get_database_connection()
{
  $pdo = new PDO(
   'mysql:host=localhost;dbname=blog_db;charset=utf8',
   'myuser',
   'mypassword',
   array(PDO::ATTR_EMULATE_PREPARES => false)
  );
  return $pdo;                                   get_database_connection
}


function get_all_posts()
{
  $pdo = get_database_connection();


    $stmt = $pdo->query('SELECT id, title FROM post');
    $posts = array();
    while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
      $posts[] = $row;
    }                                                    get_all_posts
    return $posts;
}
                                                         model.php
リファクタリング後のlist.php

<?php
require 'model.php';


$posts = get_all_posts();


require 'templates/list.php';


                       コントローラーは制御するだけ
リファクタリング後のlist.php

<?php
require 'model.php';            ロジック読込

$posts = get_all_posts();


require 'templates/list.php';


                       コントローラーは制御するだけ
リファクタリング後のlist.php

<?php
require 'model.php';            ロジック読込

$posts = get_all_posts();   全ポストを取得

require 'templates/list.php';


                       コントローラーは制御するだけ
リファクタリング後のlist.php

<?php
require 'model.php';            ロジック読込

$posts = get_all_posts();   全ポストを取得

require 'templates/list.php';    ビュー読込


                       コントローラーは制御するだけ
Good
アプリケーション(ドメイン)部分の分離


 コントローラが本来のコントローラーに


       シンプルなMVC
クライアント        サーバー




              リクエスト
                      controller
   Browser                   PHP
                             list.php



             レスポンス
                      view
                             HTML
                      template/list.php
クライアント        サーバー
                                        model
                                           Logic
                get_all_posts             model.php


              リクエスト
                      controller
   Browser                   PHP
                             list.php
                                                $POSTS


             レスポンス
                      view
                             HTML
                      template/list.php
Step 3




 Viewにレイアウト機能を追加
レイアウト機能

   Viewの共通部分を再利用できる仕組み
   <html>
     <head>
       <title>トップページ</title>
     </head>
     <body>
       <h1>こんにちは!こんにちは!</h1>
     </body>
   </html>

            template/layout.php
レイアウト機能

   Viewの共通部分を再利用できる仕組み
   <html>
     <head>
       <title>トップページ</title>
     </head>
     <body>
       <h1>こんにちは!こんにちは!</h1>
     </body>
                     動的部分を決定
   </html>

            template/layout.php
レイアウト機能

    PHPで書き換え
   <html>
     <head>
       <title><?php echo $title ?></title>
     </head>
     <body>
       <?php echo $content ?>
     </body>
   </html>

                 template/layout.php
ob_start() ... ob_get_clean()
<?php $title = '投稿のリスト' ?>                                 list.php

<?php ob_start() ?>
   <h1>投稿のリスト</h1>
   <ul>
     <?php foreach ($posts as $post): ?>
     <li>
        <a href="show.php?id=<?php echo
htmlspecialchars($post['id'], ENT_QUOTES, 'utf-8') ?>">
           <?php echo htmlspecialchars($post['title'], ENT_QUOTES,
'utf-8') ?>
        </a>
     </li>
     <?php endforeach; ?>
   </ul>
<?php $content = ob_get_clean() ?>


<?php include 'layout.php' ?>
ob_start() ... ob_get_clean()
<?php $title = '投稿のリスト' ?>                                 list.php

<?php ob_start() ?>
   <h1>投稿のリスト</h1>
   <ul>
     <?php foreach ($posts as $post): ?>
     <li>
        <a href="show.php?id=<?php echo
htmlspecialchars($post['id'], ENT_QUOTES, 'utf-8') ?>">
           <?php echo htmlspecialchars($post['title'], ENT_QUOTES,
'utf-8') ?>
        </a>
     </li>
     <?php endforeach; ?>
   </ul>
<?php $content = ob_get_clean() ?>


<?php include 'layout.php' ?>
ob_start() ... ob_get_clean()
<?php $title = '投稿のリスト' ?>                                 list.php

<?php ob_start() ?>
   <h1>投稿のリスト</h1>
   <ul>
     <?php foreach ($posts as $post): ?>
     <li>
        <a href="show.php?id=<?php echo
htmlspecialchars($post['id'], ENT_QUOTES, 'utf-8') ?>">
           <?php echo htmlspecialchars($post['title'], ENT_QUOTES,
'utf-8') ?>
        </a>
     </li>
     <?php endforeach; ?>
   </ul>
<?php $content = ob_get_clean() ?>


<?php include 'layout.php' ?>
ob_start() ... ob_get_clean()
<?php $title = '投稿のリスト' ?>                                 list.php

<?php ob_start() ?>
   <h1>投稿のリスト</h1>
   <ul>
     <?php foreach ($posts as $post): ?>
     <li>
        <a href="show.php?id=<?php echo
htmlspecialchars($post['id'], ENT_QUOTES, 'utf-8') ?>">
           <?php echo htmlspecialchars($post['title'], ENT_QUOTES,
'utf-8') ?>
        </a>
     </li>
     <?php endforeach; ?>
   </ul>
<?php $content = ob_get_clean() ?>
                                       出力せずにバッファリング
<?php include 'layout.php' ?>
ob_start() ... ob_get_clean()
<?php $title = '投稿のリスト' ?>                                 list.php

<?php ob_start() ?>
   <h1>投稿のリスト</h1>
   <ul>
     <?php foreach ($posts as $post): ?>
     <li>
        <a href="show.php?id=<?php echo
htmlspecialchars($post['id'], ENT_QUOTES, 'utf-8') ?>">
           <?php echo htmlspecialchars($post['title'], ENT_QUOTES,
'utf-8') ?>
        </a>
     </li>
     <?php endforeach; ?>
   </ul>
<?php $content = ob_get_clean() ?>
                                       出力せずにバッファリング
<?php include 'layout.php' ?>
クライアント        サーバー
                                        model
                get_all_posts              Logic
                                           model.php


              リクエスト
                      controller
   Browser                   PHP
                             list.php

                                                $POSTS

             レスポンス
                      view
                          HTML
                      template/list.php
クライアント        サーバー
                                        model
                get_all_posts               Logic
                                            model.php


              リクエスト
                      controller
   Browser                   PHP
                             list.php

                                                 $POSTS

             レスポンス
                      view
                          HTML
                      template/list.php

                                        layout
                                           HTML
                                           layout.php
Good
  テンプレートの可用性がUP


Bad
 テンプレートエンジンの機能より劣る
     Smarty, Twig...
テンプレートエンジンのメリット

   Pure PHP
<title><?php echo htmlspecialchars($title, ENT_QUOTES, 'utf-8') ?></title>




   Twig (escape)
                     <title>{{ title }}</title>


   Twig (un escape)
                  <title>{{ title¦raw }}</title>
Step 4




       ページを追加する
   blogの詳細ページ(show)
list.phpと同じ仕組を作る
<?php


require_once 'model.php';


$post = get_post_by_id($_GET['id']);


require 'templates/show.php';     特定の記事を取得




                            show.php
クライアント        サーバー
                                      model
               get_post_by_id              Logic
                                            model.php


              リクエスト
                       controller
   Browser                    PHP
                           show.php

                                               $POST


             レスポンス
                       view
                           HTML
                      template/show.php

                                      layout
                                          HTML
                                          layout.php
クライアント         controller
                                             サーバー
                      PHP
                                            get_all_posts
                      list.php

            view
                 HTML              $POSTS

            template/list.php


             layout                   model
  Browser           HTML                    Logic
                      layout.php            model.php



             view
                                    $POST
                   HTML
            tempalte/show.php

                 controller
                                       get_post_by_id
                        PHP
                      show.php
クライアント         controller
                                             サーバー
                      PHP
                                            get_all_posts
                      list.php

            view
                      一覧表示処理
                 HTML              $POSTS

            template/list.php


             layout                   model
  Browser           HTML                    Logic
                      layout.php            model.php



             view
                                    $POST
                   HTML
            tempalte/show.php

                 controller
                                       get_post_by_id
                        PHP
                      show.php
クライアント         controller
                                             サーバー
                      PHP
                                            get_all_posts
                      list.php

            view
                      一覧表示処理
                 HTML              $POSTS

            template/list.php


             layout                   model
  Browser           HTML                    Logic
                      layout.php            model.php



             view
                                    $POST
                   HTML
                      詳細表示処理
            tempalte/show.php

                 controller
                                       get_post_by_id
                        PHP
                      show.php
クライアント         controller
                                             サーバー
                      PHP
                                            get_all_posts
                      list.php

            view
                      一覧表示処理
                 HTML              $POSTS

            template/list.php


             layout                   model
  Browser           HTML                    Logic
                      layout.php            model.php



             view
                                    $POST
                   HTML
                      詳細表示処理
            tempalte/show.php

                 controller
                                       get_post_by_id
                        PHP
                      show.php
Good
 Model, Layoutが共通化できている




Bad
   リクエストを受けるPHPは
    model.phpを忘れずに
  requireしなければならない
Step 5




    フロントコントローラー
フロントコントローラー?




      全てのリクエストを
       最初に必ず受ける
      1つのPHPファイル
Before
クライアント                                   サーバー
         http://example.com/list.php
                         controller
                              PHP
                              list.php


   Browser
Before
クライアント                                   サーバー
         http://example.com/list.php
                         controller
                              PHP
                              list.php


   Browser
                         controller
                              PHP
                             show.php

    http://example.com/show.php?id=5
After
クライアント                             サーバー



             front controller   controllers
   Browser         PHP              PHP
                 index.php      controllers.php
After
クライアント                                              サーバー

http://example.com/index.php/list         list_action()

                       front controller          controllers
    Browser                  PHP                     PHP
                           index.php             controllers.php
After
クライアント                                               サーバー

http://example.com/index.php/list          list_action()

                       front controller           controllers
    Browser                  PHP                      PHP
                           index.php              controllers.php



                                          show_action(5)

http://example.com/index.php/show?id=5
フロントコントローラー (routing)
require_once 'model.php';
require_once 'controllers.php';


// リクエストを内部的にルーティング
$uri = $_SERVER['REQUEST_URI'];
if ($uri === ('/index.php/list')) {
   list_action();
} elseif ( preg_match("#^/index.php/show#", $uri) &&
isset($_GET['id'])) {
   show_action($_GET['id']);
} else {
   header('Status: 404 Not Found');
   echo '<html><body><h1>ページが見つかりません</h1></
body></html>';
}
                                            index.php
フロントコントローラー (routing)
require_once 'model.php';
require_once 'controllers.php';


// リクエストを内部的にルーティング
$uri = $_SERVER['REQUEST_URI'];
if ($uri === ('/index.php/list')) {
   list_action();
} elseif ( preg_match("#^/index.php/show#", $uri) &&
isset($_GET['id'])) {
   show_action($_GET['id']);
} else {
   header('Status: 404 Not Found');
   echo '<html><body><h1>ページが見つかりません</h1></
body></html>';
}
                                            index.php
フロントコントローラー (routing)
require_once 'model.php';
require_once 'controllers.php';


// リクエストを内部的にルーティング
$uri = $_SERVER['REQUEST_URI'];
if ($uri === ('/index.php/list')) {
   list_action();
} elseif ( preg_match("#^/index.php/show#", $uri) &&
isset($_GET['id'])) {
   show_action($_GET['id']);
} else {
   header('Status: 404 Not Found');
   echo '<html><body><h1>ページが見つかりません</h1></
body></html>';
}
                                            index.php
フロントコントローラー (routing)
require_once 'model.php';
require_once 'controllers.php';


// リクエストを内部的にルーティング
$uri = $_SERVER['REQUEST_URI'];
if ($uri === ('/index.php/list')) {
   list_action();
} elseif ( preg_match("#^/index.php/show#", $uri) &&
isset($_GET['id'])) {
   show_action($_GET['id']);
} else {
   header('Status: 404 Not Found');
   echo '<html><body><h1>ページが見つかりません</h1></
body></html>';
}
                                            index.php
フロントコントローラー (routing)
require_once 'model.php';
require_once 'controllers.php';


// リクエストを内部的にルーティング
$uri = $_SERVER['REQUEST_URI'];
if ($uri === ('/index.php/list')) {
   list_action();                   一覧表示へのリクエスト
} elseif ( preg_match("#^/index.php/show#", $uri) &&
isset($_GET['id'])) {
   show_action($_GET['id']);
} else {
   header('Status: 404 Not Found');
   echo '<html><body><h1>ページが見つかりません</h1></
body></html>';
}
                                        index.php
フロントコントローラー (routing)
require_once 'model.php';
require_once 'controllers.php';


// リクエストを内部的にルーティング
$uri = $_SERVER['REQUEST_URI'];
if ($uri === ('/index.php/list')) {
   list_action();                   一覧表示へのリクエスト
} elseif ( preg_match("#^/index.php/show#", $uri) &&
isset($_GET['id'])) {
   show_action($_GET['id']);        記事詳細へのリクエスト
} else {
   header('Status: 404 Not Found');
   echo '<html><body><h1>ページが見つかりません</h1></
body></html>';
}
                                        index.php
フロントコントローラー (routing)
require_once 'model.php';
require_once 'controllers.php';


// リクエストを内部的にルーティング
$uri = $_SERVER['REQUEST_URI'];
if ($uri === ('/index.php/list')) {
   list_action();                   一覧表示へのリクエスト
} elseif ( preg_match("#^/index.php/show#", $uri) &&
isset($_GET['id'])) {
   show_action($_GET['id']);        記事詳細へのリクエスト
} else {
   header('Status: 404 Not Found');
   echo '<html><body><h1>ページが見つかりません</h1></
body></html>';                        想定外のリクエスト
}
                                        index.php
フロントコントローラー(アクション)
<?php                              controllers.php
// controllers.php
function list_action()
{
   $posts = get_all_posts();
   require 'templates/list.php';
}


function show_action($id)
{
  $post = get_post_by_id($id);
  require 'templates/show.php';
}
フロントコントローラー(アクション)
<?php                            controllers.php
// controllers.php
function list_action()
{
   $posts = get_all_posts();
   require 'templates/list.php';
}                              一覧表示へのリクエスト

function show_action($id)
{
  $post = get_post_by_id($id);
  require 'templates/show.php';
}
フロントコントローラー(アクション)
<?php                            controllers.php
// controllers.php
function list_action()
{
   $posts = get_all_posts();
   require 'templates/list.php';
}                              一覧表示へのリクエスト

function show_action($id)
{
  $post = get_post_by_id($id);
  require 'templates/show.php';
}                              記事詳細へのリクエスト
Good
   設定の読込などの集中管理
       ルーティング機能
Point

   クラスはまだ使ってません


     クラスで書かなくても
   ある程度の体系化は可能です
Step6




        ライブラリを利用する
ライブラリを利用する




 HttpFoundation Component
HttpFoundation Component を使うことで....




  Webアプリケーションで必須な
$_GET, $_POST, レスポンスデータ
    をオブジェクトで扱える
HttpFoundation Component を使うことで....


Pure PHP

   $id = (isset($_GET[ id ]))? $_GET[ id ]: 0;




 Object
          $id = $request->query( id , 0);
HttpFoundation Component を
    採用しているプロジェクト


       Symfony2
          Silex
        Drupal8
        phpBB4
          ppi2
        Laravel4
         Zikula
           ... more
HttpFoundation Component は
   今後のデファクトスタンダート

                   Laravel4




                              ??



                      FuelPHP2
Pure PHP

// リクエストを内部的にルーティング
$uri = $_SERVER['REQUEST_URI'];
if ($uri === ('/index.php/list')) {
   list_action();
} elseif ( preg_match("#^/index.php/show#", $uri) &&
isset($_GET['id'])) {
   show_action($_GET['id']);
} else {
   header('Status: 404 Not Found');
   echo '<html><body><h1>ページが見つかりません</h1></body></html>';
}

                                           index.php
Symfony component

$request = Request::createFromGlobals();


$uri = $request->getPathInfo();
if ($uri === '/') {
   $response = list_action();
} elseif ($uri === '/show' && $request->query->has('id')) {
   $response = show_action($request->query->get('id'));
} else {
   $html = '<html><body><h1>Page Not Found</h1></body></
html>';
   $response = new Response($html, 404);
}


$response->send();                         index.php
Symfony component

$request = Request::createFromGlobals();


$uri = $request->getPathInfo();
if ($uri === '/') {
   $response = list_action();
} elseif ($uri === '/show' && $request->query->has('id')) {
   $response = show_action($request->query->get('id'));
} else {
   $html = '<html><body><h1>Page Not Found</h1></body></
html>';
   $response = new Response($html, 404);
}


$response->send();                         index.php
<?php                              controllers.php
// controllers.php
function list_action()
{
   $posts = get_all_posts();
   require 'templates/list.php';
}
<?php                              controllers.php
// controllers.php
function list_action()
{
   $posts = get_all_posts();
   require 'templates/list.php';
}

                     テンプレートをレンダリング (echo)
Controllers
function list_action()
{
  $posts = get_all_posts();
  $html = render_template('templates/list.php', array('posts' =>
$posts));
  return new Response($html);
}


function render_template($path, $params)
{
  extract($params, EXTR_SKIP);
  ob_start();
  require $path;
  $html = ob_get_clean();


    return $html;
}
Controllers
function list_action()
{
  $posts = get_all_posts();
  $html = render_template('templates/list.php', array('posts' =>
$posts));
  return new Response($html);
}
                              Responseオブジェクトを返す
function render_template($path, $params)
{
  extract($params, EXTR_SKIP);
  ob_start();
  require $path;
  $html = ob_get_clean();


    return $html;
}
Controllers
function list_action()
{
  $posts = get_all_posts();
  $html = render_template('templates/list.php', array('posts' =>
$posts));
  return new Response($html);
}
                              Responseオブジェクトを返す
function render_template($path, $params)
{
  extract($params, EXTR_SKIP);
  ob_start();
  require $path;
  $html = ob_get_clean();


    return $html;
}
Controllers
function list_action()
{
  $posts = get_all_posts();
  $html = render_template('templates/list.php', array('posts' =>
$posts));
  return new Response($html);
}
                              Responseオブジェクトを返す
function render_template($path, $params)
{
  extract($params, EXTR_SKIP);
  ob_start();
  require $path;
  $html = ob_get_clean();


    return $html;
}
                             典型的なPHPテンプレートパターン
CakePHP




DietCake
CakePHP




DietCake
CakePHP




DietCake
Good
  簡易的なフレームワークが完成
       車輪の再開発を防ぐ
      必要な機能だけ利用できる
        再利用性が高い

Bad
必要以上の機能が含まれるかもしれない
クライアント             サーバー
                                                model
                                                     Logic
                                                     model.php
                            list_action()

            リクエスト front controller          controllers
  Browser               PHP                    PHP
                    index.php           controllers.php


                              show_action()



              レスポンス
                             view
                                     HTML
                            template/show.php

                                                layout
                                                      HTML
                                                   layout.php
クライアント              サーバー
                                        Model
                    MVC

            リクエスト
  Browser
                           controller




             レスポンス


                              view
Final




        フレームワークを使う
            とは?
フレームワークを使う




    フレームワークを使っても
    やりたいことは変わらない
フレームワークを使う




  作りたいのはアプリケーション
フレームワークを使う




     ルーティング
     規約
     コントローラー
     バリデーター
     ......
Silexで書き換えると...
$app = new SilexApplication();
.....
$app->get('/show', function(Application $app, Request $request)
{
    $get_post_by_id = $app['model.post_by_id'];
    $post = $get_post_by_id($request->query->get('id'));
    return $app->render('templates/show.twig',
                         array('post' => $post));
});
フラットなPHPからSymfony2へ

 フラットなPHPからSliexへ

  フラットなPHPからSlimへ

           詳しくはぐぐってみてください
フレームワークを使う




  自分でゼロから作らなくて良い


   万能なフレームワークは無い
   実際に使って思想を理解する
まとめ


  フラットなPHPのデメリット
フレームワークの本来の仕事は何か?


使われるのではなく使うこと
thank you.

More Related Content

フラットなPHPからフレームワークへ

  • 1. フラットなPHPから フレームワークへ 株式会社 adingo 前田 雅央 @brtriver
  • 3. Steps フラットなPHP リファクタリング フレームワーク * フラットなPHP = 1ファイルで書かれたPHP
  • 4. Steps フラットなPHP View部分の分離 アプリケーション(ドメイン)部分の分離 Viewにレイアウト機能を追加 ページを追加する フロントコントローラー導入 ライブラリを利用する フレームワーク
  • 6. Step 0 DBからデータ取得し 取得したデータを HTMLで表示する
  • 7. <?php $pdo = new PDO( 'mysql:host=localhost;dbname=blog_db;charset=utf8', list.php 'myuser', 'mypassword', array(PDO::ATTR_EMULATE_PREPARES => false) ); $stmt = $pdo->query('SELECT id, title FROM post'); ?> <html> <head> <title>投稿の一覧</title> </head> <body> <h1>投稿の一覧</h1> <ul> <?php while ($row = $stmt->fetch(PDO::FETCH_ASSOC)): ?> <li> <a href="show.php?id=<?php echo htmlspecialchars($row['id'], ENT_QUOTES, 'utf-8') ?>"> <?php echo htmlspecialchars($row['title'], ENT_QUOTES, 'utf-8') ?> </a> </li> <?php endwhile; ?> </ul> </body> </html>
  • 8. <?php $pdo = new PDO( 'mysql:host=localhost;dbname=blog_db;charset=utf8', list.php 'myuser', 'mypassword', array(PDO::ATTR_EMULATE_PREPARES => false) ); $stmt = $pdo->query('SELECT id, title FROM post'); ?> <html> <head> <title>投稿の一覧</title> </head> <body> <h1>投稿の一覧</h1> <ul> <?php while ($row = $stmt->fetch(PDO::FETCH_ASSOC)): ?> <li> <a href="show.php?id=<?php echo htmlspecialchars($row['id'], ENT_QUOTES, 'utf-8') ?>"> <?php echo htmlspecialchars($row['title'], ENT_QUOTES, 'utf-8') ?> </a> </li> <?php endwhile; ?> </ul> </body> </html>
  • 9. <?php $pdo = new PDO( 'mysql:host=localhost;dbname=blog_db;charset=utf8', list.php 'myuser', 'mypassword', array(PDO::ATTR_EMULATE_PREPARES => false) ); $stmt = $pdo->query('SELECT id, title FROM post'); ?> <html> <head> <title>投稿の一覧</title> </head> <body> <h1>投稿の一覧</h1> <ul> <?php while ($row = $stmt->fetch(PDO::FETCH_ASSOC)): ?> <li> <a href="show.php?id=<?php echo htmlspecialchars($row['id'], ENT_QUOTES, 'utf-8') ?>"> <?php echo htmlspecialchars($row['title'], ENT_QUOTES, 'utf-8') ?> </a> </li> <?php endwhile; ?> </ul> </body> </html>
  • 10. <?php $pdo = new PDO( 'mysql:host=localhost;dbname=blog_db;charset=utf8', list.php 'myuser', DBからデータ取得 ); 'mypassword', array(PDO::ATTR_EMULATE_PREPARES => false) $stmt = $pdo->query('SELECT id, title FROM post'); ?> <html> <head> <title>投稿の一覧</title> </head> <body> <h1>投稿の一覧</h1> <ul> <?php while ($row = $stmt->fetch(PDO::FETCH_ASSOC)): ?> <li> <a href="show.php?id=<?php echo htmlspecialchars($row['id'], ENT_QUOTES, 'utf-8') ?>"> <?php echo htmlspecialchars($row['title'], ENT_QUOTES, 'utf-8') ?> </a> </li> <?php endwhile; ?> </ul> </body> </html>
  • 11. <?php $pdo = new PDO( 'mysql:host=localhost;dbname=blog_db;charset=utf8', list.php 'myuser', DBからデータ取得 ); 'mypassword', array(PDO::ATTR_EMULATE_PREPARES => false) $stmt = $pdo->query('SELECT id, title FROM post'); ?> <html> <head> <title>投稿の一覧</title> </head> <body> <h1>投稿の一覧</h1> <ul> <?php while ($row = $stmt->fetch(PDO::FETCH_ASSOC)): ?> 取得したデータを表示 <li> <a href="show.php?id=<?php echo htmlspecialchars($row['id'], ENT_QUOTES, 'utf-8') ?>"> <?php echo htmlspecialchars($row['title'], ENT_QUOTES, 'utf-8') ?> </a> </li> <?php endwhile; ?> </ul> </body> </html>
  • 12. クライアント サーバー リクエスト PHP + Browser HTML レスポンス list.php
  • 13. Good シンプル 1ファイルたったの26行
  • 14. Bad アプリケーションの拡張性が無い 体系化されていない 再利用性がない
  • 15. 体系化されていない フォームの送信を行うコードの追加したい... どこに書く? 同じファイル?別ファイルで書く?
  • 17. クライアント サーバー エ スト PHP + HTML リク ポ ンス レス list.php Browser Bad
  • 18. クライアント サーバー エ スト PHP + HTML リク ポ ンス レス list.php Browser COPY Bad
  • 19. クライアント サーバー エ スト PHP + HTML リク ポ ンス レス list.php Browser COPY リクエ スト PHP + HTML レスポ ンス list2.php Bad
  • 20. Step 1 View部分の分離
  • 21. show.php <?php $pdo = new PDO( 'mysql:host=localhost;dbname=blog_db;charset=utf8', 'myuser', 'mypassword', array(PDO::ATTR_EMULATE_PREPARES => false) ); $stmt = $pdo->query('SELECT id, title FROM post'); ?> <html> <head> <title>投稿の一覧</title> </head> <body> <h1>投稿の一覧</h1> <ul> <?php while ($row = $stmt->fetch(PDO::FETCH_ASSOC)): ?> <li> <a href="show.php?id=<?php echo htmlspecialchars($row['id'], ENT_QUOTES, 'utf-8') ?>"> <?php echo htmlspecialchars($row['title'], ENT_QUOTES, 'utf-8') ?> </a> </li> <?php endwhile; ?> </ul> </body> </html>
  • 22. show.php <?php $pdo = new PDO( 'mysql:host=localhost;dbname=blog_db;charset=utf8', 'myuser', ); 'mypassword', ロジック部分 array(PDO::ATTR_EMULATE_PREPARES => false) $stmt = $pdo->query('SELECT id, title FROM post'); ?> <html> <head> <title>投稿の一覧</title> </head> <body> <h1>投稿の一覧</h1> <ul> <?php while ($row = $stmt->fetch(PDO::FETCH_ASSOC)): ?> <li> <a href="show.php?id=<?php echo htmlspecialchars($row['id'], ENT_QUOTES, 'utf-8') ?>"> <?php echo htmlspecialchars($row['title'], ENT_QUOTES, 'utf-8') ?> </a> </li> <?php endwhile; ?> </ul> </body> </html>
  • 23. show.php <?php $pdo = new PDO( 'mysql:host=localhost;dbname=blog_db;charset=utf8', 'myuser', ); 'mypassword', ロジック部分 array(PDO::ATTR_EMULATE_PREPARES => false) $stmt = $pdo->query('SELECT id, title FROM post'); ?> <html> <head> <title>投稿の一覧</title> </head> <body> <h1>投稿の一覧</h1> <ul> View(HTML)部分 <?php while ($row = $stmt->fetch(PDO::FETCH_ASSOC)): ?> <li> <a href="show.php?id=<?php echo htmlspecialchars($row['id'], ENT_QUOTES, 'utf-8') ?>"> <?php echo htmlspecialchars($row['title'], ENT_QUOTES, 'utf-8') ?> </a> </li> <?php endwhile; ?> </ul> </body> </html>
  • 24. show.php <?php $pdo = new PDO( 'mysql:host=localhost;dbname=blog_db:charset=utf8', 'myuser', 'mypassword', array(PDO::ATTR_EMULATE_PREPARES => false) ); $stmt = $pdo->query('SELECT id, title FROM post'); // HTML部分のコードを読み込む require 'templates/list.php'; 別ファイルに分離
  • 25. show.php <?php $pdo = new PDO( 'mysql:host=localhost;dbname=blog_db:charset=utf8', 'myuser', 'mypassword', ロジック部分 array(PDO::ATTR_EMULATE_PREPARES => false) ); $stmt = $pdo->query('SELECT id, title FROM post'); // HTML部分のコードを読み込む require 'templates/list.php'; 別ファイルに分離
  • 26. クライアント サーバー リクエスト controller Browser PHP list.php
  • 27. クライアント サーバー リクエスト controller Browser PHP list.php
  • 28. クライアント サーバー リクエスト controller Browser PHP list.php レスポンス view HTML template/list.php
  • 29. クライアント サーバー リクエスト controller Browser PHP list.php レスポンス view json template/list-json.php
  • 30. Good View部分の分離 テンプレートの変更に強い
  • 31. Step 2 アプリケーション(ドメイン) 部分の分離
  • 32. index.php <?php $pdo = new PDO( 'mysql:host=localhost;dbname=blog_db:charset=utf8', 'myuser', 'mypassword', array(PDO::ATTR_EMULATE_PREPARES => false) ); $stmt = $pdo->query('SELECT id, title FROM post');
  • 33. index.php <?php $pdo = new PDO( 'mysql:host=localhost;dbname=blog_db:charset=utf8', データベースへ接続する 'myuser', 'mypassword', array(PDO::ATTR_EMULATE_PREPARES => false) ); $stmt = $pdo->query('SELECT id, title FROM post');
  • 34. index.php <?php $pdo = new PDO( 'mysql:host=localhost;dbname=blog_db:charset=utf8', データベースへ接続する 'myuser', 'mypassword', array(PDO::ATTR_EMULATE_PREPARES => false) ); 全てのポストを取得する $stmt = $pdo->query('SELECT id, title FROM post');
  • 35. ドメイン データベースへの接続する 全てのポストを取得する model.php に分離
  • 36. <?php // model.php function get_database_connection() { $pdo = new PDO( 'mysql:host=localhost;dbname=blog_db;charset=utf8', 'myuser', 'mypassword', array(PDO::ATTR_EMULATE_PREPARES => false) ); return $pdo; get_database_connection } function get_all_posts() { $pdo = get_database_connection(); $stmt = $pdo->query('SELECT id, title FROM post'); $posts = array(); while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) { $posts[] = $row; } get_all_posts return $posts; } model.php
  • 37. リファクタリング後のlist.php <?php require 'model.php'; $posts = get_all_posts(); require 'templates/list.php'; コントローラーは制御するだけ
  • 38. リファクタリング後のlist.php <?php require 'model.php'; ロジック読込 $posts = get_all_posts(); require 'templates/list.php'; コントローラーは制御するだけ
  • 39. リファクタリング後のlist.php <?php require 'model.php'; ロジック読込 $posts = get_all_posts(); 全ポストを取得 require 'templates/list.php'; コントローラーは制御するだけ
  • 40. リファクタリング後のlist.php <?php require 'model.php'; ロジック読込 $posts = get_all_posts(); 全ポストを取得 require 'templates/list.php'; ビュー読込 コントローラーは制御するだけ
  • 42. クライアント サーバー リクエスト controller Browser PHP list.php レスポンス view HTML template/list.php
  • 43. クライアント サーバー model Logic get_all_posts model.php リクエスト controller Browser PHP list.php $POSTS レスポンス view HTML template/list.php
  • 45. レイアウト機能 Viewの共通部分を再利用できる仕組み <html> <head> <title>トップページ</title> </head> <body> <h1>こんにちは!こんにちは!</h1> </body> </html> template/layout.php
  • 46. レイアウト機能 Viewの共通部分を再利用できる仕組み <html> <head> <title>トップページ</title> </head> <body> <h1>こんにちは!こんにちは!</h1> </body> 動的部分を決定 </html> template/layout.php
  • 47. レイアウト機能 PHPで書き換え <html> <head> <title><?php echo $title ?></title> </head> <body> <?php echo $content ?> </body> </html> template/layout.php
  • 48. ob_start() ... ob_get_clean() <?php $title = '投稿のリスト' ?> list.php <?php ob_start() ?> <h1>投稿のリスト</h1> <ul> <?php foreach ($posts as $post): ?> <li> <a href="show.php?id=<?php echo htmlspecialchars($post['id'], ENT_QUOTES, 'utf-8') ?>"> <?php echo htmlspecialchars($post['title'], ENT_QUOTES, 'utf-8') ?> </a> </li> <?php endforeach; ?> </ul> <?php $content = ob_get_clean() ?> <?php include 'layout.php' ?>
  • 49. ob_start() ... ob_get_clean() <?php $title = '投稿のリスト' ?> list.php <?php ob_start() ?> <h1>投稿のリスト</h1> <ul> <?php foreach ($posts as $post): ?> <li> <a href="show.php?id=<?php echo htmlspecialchars($post['id'], ENT_QUOTES, 'utf-8') ?>"> <?php echo htmlspecialchars($post['title'], ENT_QUOTES, 'utf-8') ?> </a> </li> <?php endforeach; ?> </ul> <?php $content = ob_get_clean() ?> <?php include 'layout.php' ?>
  • 50. ob_start() ... ob_get_clean() <?php $title = '投稿のリスト' ?> list.php <?php ob_start() ?> <h1>投稿のリスト</h1> <ul> <?php foreach ($posts as $post): ?> <li> <a href="show.php?id=<?php echo htmlspecialchars($post['id'], ENT_QUOTES, 'utf-8') ?>"> <?php echo htmlspecialchars($post['title'], ENT_QUOTES, 'utf-8') ?> </a> </li> <?php endforeach; ?> </ul> <?php $content = ob_get_clean() ?> <?php include 'layout.php' ?>
  • 51. ob_start() ... ob_get_clean() <?php $title = '投稿のリスト' ?> list.php <?php ob_start() ?> <h1>投稿のリスト</h1> <ul> <?php foreach ($posts as $post): ?> <li> <a href="show.php?id=<?php echo htmlspecialchars($post['id'], ENT_QUOTES, 'utf-8') ?>"> <?php echo htmlspecialchars($post['title'], ENT_QUOTES, 'utf-8') ?> </a> </li> <?php endforeach; ?> </ul> <?php $content = ob_get_clean() ?> 出力せずにバッファリング <?php include 'layout.php' ?>
  • 52. ob_start() ... ob_get_clean() <?php $title = '投稿のリスト' ?> list.php <?php ob_start() ?> <h1>投稿のリスト</h1> <ul> <?php foreach ($posts as $post): ?> <li> <a href="show.php?id=<?php echo htmlspecialchars($post['id'], ENT_QUOTES, 'utf-8') ?>"> <?php echo htmlspecialchars($post['title'], ENT_QUOTES, 'utf-8') ?> </a> </li> <?php endforeach; ?> </ul> <?php $content = ob_get_clean() ?> 出力せずにバッファリング <?php include 'layout.php' ?>
  • 53. クライアント サーバー model get_all_posts Logic model.php リクエスト controller Browser PHP list.php $POSTS レスポンス view HTML template/list.php
  • 54. クライアント サーバー model get_all_posts Logic model.php リクエスト controller Browser PHP list.php $POSTS レスポンス view HTML template/list.php layout HTML layout.php
  • 55. Good テンプレートの可用性がUP Bad テンプレートエンジンの機能より劣る Smarty, Twig...
  • 56. テンプレートエンジンのメリット Pure PHP <title><?php echo htmlspecialchars($title, ENT_QUOTES, 'utf-8') ?></title> Twig (escape) <title>{{ title }}</title> Twig (un escape) <title>{{ title¦raw }}</title>
  • 57. Step 4 ページを追加する blogの詳細ページ(show)
  • 58. list.phpと同じ仕組を作る <?php require_once 'model.php'; $post = get_post_by_id($_GET['id']); require 'templates/show.php'; 特定の記事を取得 show.php
  • 59. クライアント サーバー model get_post_by_id Logic model.php リクエスト controller Browser PHP show.php $POST レスポンス view HTML template/show.php layout HTML layout.php
  • 60. クライアント controller サーバー PHP get_all_posts list.php view HTML $POSTS template/list.php layout model Browser HTML Logic layout.php model.php view $POST HTML tempalte/show.php controller get_post_by_id PHP show.php
  • 61. クライアント controller サーバー PHP get_all_posts list.php view 一覧表示処理 HTML $POSTS template/list.php layout model Browser HTML Logic layout.php model.php view $POST HTML tempalte/show.php controller get_post_by_id PHP show.php
  • 62. クライアント controller サーバー PHP get_all_posts list.php view 一覧表示処理 HTML $POSTS template/list.php layout model Browser HTML Logic layout.php model.php view $POST HTML 詳細表示処理 tempalte/show.php controller get_post_by_id PHP show.php
  • 63. クライアント controller サーバー PHP get_all_posts list.php view 一覧表示処理 HTML $POSTS template/list.php layout model Browser HTML Logic layout.php model.php view $POST HTML 詳細表示処理 tempalte/show.php controller get_post_by_id PHP show.php
  • 64. Good Model, Layoutが共通化できている Bad リクエストを受けるPHPは model.phpを忘れずに requireしなければならない
  • 65. Step 5 フロントコントローラー
  • 66. フロントコントローラー? 全てのリクエストを 最初に必ず受ける 1つのPHPファイル
  • 67. Before クライアント サーバー http://example.com/list.php controller PHP list.php Browser
  • 68. Before クライアント サーバー http://example.com/list.php controller PHP list.php Browser controller PHP show.php http://example.com/show.php?id=5
  • 69. After クライアント サーバー front controller controllers Browser PHP PHP index.php controllers.php
  • 70. After クライアント サーバー http://example.com/index.php/list list_action() front controller controllers Browser PHP PHP index.php controllers.php
  • 71. After クライアント サーバー http://example.com/index.php/list list_action() front controller controllers Browser PHP PHP index.php controllers.php show_action(5) http://example.com/index.php/show?id=5
  • 72. フロントコントローラー (routing) require_once 'model.php'; require_once 'controllers.php'; // リクエストを内部的にルーティング $uri = $_SERVER['REQUEST_URI']; if ($uri === ('/index.php/list')) { list_action(); } elseif ( preg_match("#^/index.php/show#", $uri) && isset($_GET['id'])) { show_action($_GET['id']); } else { header('Status: 404 Not Found'); echo '<html><body><h1>ページが見つかりません</h1></ body></html>'; } index.php
  • 73. フロントコントローラー (routing) require_once 'model.php'; require_once 'controllers.php'; // リクエストを内部的にルーティング $uri = $_SERVER['REQUEST_URI']; if ($uri === ('/index.php/list')) { list_action(); } elseif ( preg_match("#^/index.php/show#", $uri) && isset($_GET['id'])) { show_action($_GET['id']); } else { header('Status: 404 Not Found'); echo '<html><body><h1>ページが見つかりません</h1></ body></html>'; } index.php
  • 74. フロントコントローラー (routing) require_once 'model.php'; require_once 'controllers.php'; // リクエストを内部的にルーティング $uri = $_SERVER['REQUEST_URI']; if ($uri === ('/index.php/list')) { list_action(); } elseif ( preg_match("#^/index.php/show#", $uri) && isset($_GET['id'])) { show_action($_GET['id']); } else { header('Status: 404 Not Found'); echo '<html><body><h1>ページが見つかりません</h1></ body></html>'; } index.php
  • 75. フロントコントローラー (routing) require_once 'model.php'; require_once 'controllers.php'; // リクエストを内部的にルーティング $uri = $_SERVER['REQUEST_URI']; if ($uri === ('/index.php/list')) { list_action(); } elseif ( preg_match("#^/index.php/show#", $uri) && isset($_GET['id'])) { show_action($_GET['id']); } else { header('Status: 404 Not Found'); echo '<html><body><h1>ページが見つかりません</h1></ body></html>'; } index.php
  • 76. フロントコントローラー (routing) require_once 'model.php'; require_once 'controllers.php'; // リクエストを内部的にルーティング $uri = $_SERVER['REQUEST_URI']; if ($uri === ('/index.php/list')) { list_action(); 一覧表示へのリクエスト } elseif ( preg_match("#^/index.php/show#", $uri) && isset($_GET['id'])) { show_action($_GET['id']); } else { header('Status: 404 Not Found'); echo '<html><body><h1>ページが見つかりません</h1></ body></html>'; } index.php
  • 77. フロントコントローラー (routing) require_once 'model.php'; require_once 'controllers.php'; // リクエストを内部的にルーティング $uri = $_SERVER['REQUEST_URI']; if ($uri === ('/index.php/list')) { list_action(); 一覧表示へのリクエスト } elseif ( preg_match("#^/index.php/show#", $uri) && isset($_GET['id'])) { show_action($_GET['id']); 記事詳細へのリクエスト } else { header('Status: 404 Not Found'); echo '<html><body><h1>ページが見つかりません</h1></ body></html>'; } index.php
  • 78. フロントコントローラー (routing) require_once 'model.php'; require_once 'controllers.php'; // リクエストを内部的にルーティング $uri = $_SERVER['REQUEST_URI']; if ($uri === ('/index.php/list')) { list_action(); 一覧表示へのリクエスト } elseif ( preg_match("#^/index.php/show#", $uri) && isset($_GET['id'])) { show_action($_GET['id']); 記事詳細へのリクエスト } else { header('Status: 404 Not Found'); echo '<html><body><h1>ページが見つかりません</h1></ body></html>'; 想定外のリクエスト } index.php
  • 79. フロントコントローラー(アクション) <?php controllers.php // controllers.php function list_action() { $posts = get_all_posts(); require 'templates/list.php'; } function show_action($id) { $post = get_post_by_id($id); require 'templates/show.php'; }
  • 80. フロントコントローラー(アクション) <?php controllers.php // controllers.php function list_action() { $posts = get_all_posts(); require 'templates/list.php'; } 一覧表示へのリクエスト function show_action($id) { $post = get_post_by_id($id); require 'templates/show.php'; }
  • 81. フロントコントローラー(アクション) <?php controllers.php // controllers.php function list_action() { $posts = get_all_posts(); require 'templates/list.php'; } 一覧表示へのリクエスト function show_action($id) { $post = get_post_by_id($id); require 'templates/show.php'; } 記事詳細へのリクエスト
  • 82. Good 設定の読込などの集中管理 ルーティング機能
  • 83. Point クラスはまだ使ってません クラスで書かなくても ある程度の体系化は可能です
  • 84. Step6 ライブラリを利用する
  • 86. HttpFoundation Component を使うことで.... Webアプリケーションで必須な $_GET, $_POST, レスポンスデータ をオブジェクトで扱える
  • 87. HttpFoundation Component を使うことで.... Pure PHP $id = (isset($_GET[ id ]))? $_GET[ id ]: 0; Object $id = $request->query( id , 0);
  • 88. HttpFoundation Component を 採用しているプロジェクト Symfony2 Silex Drupal8 phpBB4 ppi2 Laravel4 Zikula ... more
  • 89. HttpFoundation Component は 今後のデファクトスタンダート Laravel4 ?? FuelPHP2
  • 90. Pure PHP // リクエストを内部的にルーティング $uri = $_SERVER['REQUEST_URI']; if ($uri === ('/index.php/list')) { list_action(); } elseif ( preg_match("#^/index.php/show#", $uri) && isset($_GET['id'])) { show_action($_GET['id']); } else { header('Status: 404 Not Found'); echo '<html><body><h1>ページが見つかりません</h1></body></html>'; } index.php
  • 91. Symfony component $request = Request::createFromGlobals(); $uri = $request->getPathInfo(); if ($uri === '/') { $response = list_action(); } elseif ($uri === '/show' && $request->query->has('id')) { $response = show_action($request->query->get('id')); } else { $html = '<html><body><h1>Page Not Found</h1></body></ html>'; $response = new Response($html, 404); } $response->send(); index.php
  • 92. Symfony component $request = Request::createFromGlobals(); $uri = $request->getPathInfo(); if ($uri === '/') { $response = list_action(); } elseif ($uri === '/show' && $request->query->has('id')) { $response = show_action($request->query->get('id')); } else { $html = '<html><body><h1>Page Not Found</h1></body></ html>'; $response = new Response($html, 404); } $response->send(); index.php
  • 93. <?php controllers.php // controllers.php function list_action() { $posts = get_all_posts(); require 'templates/list.php'; }
  • 94. <?php controllers.php // controllers.php function list_action() { $posts = get_all_posts(); require 'templates/list.php'; } テンプレートをレンダリング (echo)
  • 95. Controllers function list_action() { $posts = get_all_posts(); $html = render_template('templates/list.php', array('posts' => $posts)); return new Response($html); } function render_template($path, $params) { extract($params, EXTR_SKIP); ob_start(); require $path; $html = ob_get_clean(); return $html; }
  • 96. Controllers function list_action() { $posts = get_all_posts(); $html = render_template('templates/list.php', array('posts' => $posts)); return new Response($html); } Responseオブジェクトを返す function render_template($path, $params) { extract($params, EXTR_SKIP); ob_start(); require $path; $html = ob_get_clean(); return $html; }
  • 97. Controllers function list_action() { $posts = get_all_posts(); $html = render_template('templates/list.php', array('posts' => $posts)); return new Response($html); } Responseオブジェクトを返す function render_template($path, $params) { extract($params, EXTR_SKIP); ob_start(); require $path; $html = ob_get_clean(); return $html; }
  • 98. Controllers function list_action() { $posts = get_all_posts(); $html = render_template('templates/list.php', array('posts' => $posts)); return new Response($html); } Responseオブジェクトを返す function render_template($path, $params) { extract($params, EXTR_SKIP); ob_start(); require $path; $html = ob_get_clean(); return $html; } 典型的なPHPテンプレートパターン
  • 102. Good 簡易的なフレームワークが完成 車輪の再開発を防ぐ 必要な機能だけ利用できる 再利用性が高い Bad 必要以上の機能が含まれるかもしれない
  • 103. クライアント サーバー model Logic model.php list_action() リクエスト front controller controllers Browser PHP PHP index.php controllers.php show_action() レスポンス view HTML template/show.php layout HTML layout.php
  • 104. クライアント サーバー Model MVC リクエスト Browser controller レスポンス view
  • 105. Final フレームワークを使う とは?
  • 106. フレームワークを使う フレームワークを使っても やりたいことは変わらない
  • 108. フレームワークを使う ルーティング 規約 コントローラー バリデーター ......
  • 109. Silexで書き換えると... $app = new SilexApplication(); ..... $app->get('/show', function(Application $app, Request $request) { $get_post_by_id = $app['model.post_by_id']; $post = $get_post_by_id($request->query->get('id')); return $app->render('templates/show.twig', array('post' => $post)); });
  • 110. フラットなPHPからSymfony2へ フラットなPHPからSliexへ フラットなPHPからSlimへ 詳しくはぐぐってみてください
  • 111. フレームワークを使う 自分でゼロから作らなくて良い 万能なフレームワークは無い 実際に使って思想を理解する

Editor's Notes

  1. \n
  2. \n
  3. \n
  4. \n
  5. \n
  6. \n
  7. \n
  8. \n
  9. \n
  10. \n
  11. \n
  12. \n
  13. \n
  14. \n
  15. \n
  16. \n
  17. \n
  18. \n
  19. \n
  20. \n
  21. \n
  22. \n
  23. \n
  24. \n
  25. \n
  26. \n
  27. \n
  28. \n
  29. \n
  30. \n
  31. \n
  32. \n
  33. \n
  34. \n
  35. \n
  36. \n
  37. \n
  38. \n
  39. \n
  40. \n
  41. \n
  42. \n
  43. \n
  44. \n
  45. \n
  46. \n
  47. \n
  48. \n
  49. \n
  50. \n
  51. \n
  52. \n
  53. \n
  54. \n
  55. \n
  56. \n
  57. \n
  58. \n
  59. \n
  60. \n
  61. \n
  62. \n
  63. \n
  64. \n
  65. \n
  66. \n
  67. \n
  68. \n
  69. \n
  70. \n
  71. \n
  72. \n
  73. \n
  74. \n
  75. \n
  76. \n
  77. \n
  78. \n
  79. \n
  80. \n
  81. \n
  82. \n
  83. \n
  84. \n
  85. \n
  86. \n
  87. \n
  88. \n
  89. \n
  90. \n
  91. \n
  92. \n
  93. \n