> ## Content Index
> Fetch the complete content index at: https://blog.hinablue.me/llms.txt
> Use this file to discover other available public pages before exploring further.

# [PHP note.] 微型專案 Part 1
- URL: https://blog.hinablue.me/php-note-micro-project-note-part-1/
- Published: 2011-11-20T15:38:00.000Z
- Updated: 2026-06-25T09:32:02.000Z
- Author: Hina Chen

這是技術外加嘴砲文。

專案就是這樣，從許多大中小型的 Framework 挑一個適合的來用，萬一沒有中意的，那只好-複製貼上-自己刻一個比較快。當然，不是什麼時候都可以重造輪子的，案子很急很趕-屎都在門邊-的時候，挑幾個小型的 Framework 快速上手應該是比較好的解法。

那我寫這個幹麼（被揍飛！

## 需求認知

快速開發，又得要考慮多人同時進行，版本控制就很重要，git 當然是不二選擇。除了 git 我想不到其他的辦法，沒辦法，誰叫 git 這麼好用呢。版本控制確定了，那麼就得決定專案需求的方向。各大類型的 Framework 總是免不了一大堆的設定、Controllers、Modules、Views、Plugins 等等，當我不需要得時候，是不是能有一個檔案搞定的解法呢？

又，資料庫怎麼辦？在 gitHub 上面不乏有許多小型的資料庫工具可用，像是以 [@pct](http://deep.tw/?ref=blog.hinablue.me) 的 [4money](https://github.com/pct/4money?ref=blog.hinablue.me) 專案所使用的 [Idiorm](https://github.com/j4mie/idiorm?ref=blog.hinablue.me) 就是一個不錯的工具。~~當然，如果你想自己用 PDO 來刻也是可以的~~。

那，Views 怎麼辦呢？用 Smarty 嗎？還是？

## 確認需求

所以，我決定這麼做：
- 自己刻一個簡易的 Bootstrap，然後可以使用 Controllers, Plugins, Modules 等等。
- 資料庫使用 idiorm。
- Views 直接使用 PHP（其實 PHP 本身就是樣板引擎）。
我要做一個 RESTful 的 API 介面，其實用不太到 Views 的功能，所以才會選擇用 PHP 自己刻。那麼，Bootstrap 該怎麼開始比較好？ 

## 自己刻，比較快？

真的嗎？

首先，我知道 RESTful 的 API 需要回傳 HTTP 狀態碼，然後要將 body 填入回傳的資訊。我們有兩種方法，一種是 JSON，另一種是 XML，所以我們就會有兩種回傳資訊的功能。

HTTP 狀態碼則可以用 header() 來送，簡單明瞭（喂

```php
<?php 
  header('HTTP/1.0 400 BAD REQUEST');
?>

```

那麼，Bootstrap 還是沒有解決啊？

```php
<?php 
  class Controller {
      public function __construct() {
      }
  }
  class Container extends Controller {
      public function __construct() {
      }
      public function startup() {
          // 開始跑
      }
  }
  $container = new Container();
  $container->startup();
?>

```

那我們的 Controllers 呢？舉一個簡單的例子，我們開一個目錄叫做 controllers，然後裡面放了個 Api.php 這樣。

```php
<?php 
  class Api extends Controller {
      public function __construct() {
      }
      public function startup() {
          // 開始跑
      }
  }
?>

```

然後訪問 index.php 的時候，發現 Api.php 並不會動，那一定是有什麼-奇怪的東西混進來了-寫錯了。所以我們再來看一下 index.php 是不是有漏掉的地方。

```php
<?php 
  class Controller {
      public function __construct() {
      }
  }
  class Container extends Controller {
      private $controller;
      public function __construct() {
      }
      public function startup() {
          // 開始跑
          require_once 'controllers/Api.php';
          $this->controller = new Api;
          $this->controller->startup();
      }
  }
  $container = new Container();
  $container->startup();
?>

```

疑？那最近每一套 Framework 都很夯的 Routing 功能，或是去除掉 index.php 的動作要怎麼做呢？當然，如果你有用過 Rewrite Engine 的話，這個問題應該很快就能夠解決。要怎麼把網址拆開來，依照 Controller/Method/Value1/Value2 來傳遞到你的 Controller 裡面，這就是請自己努力的地方了。而其實，你也可以參考各大 Framework 的作法，也是可以學到一點東西的。

所以，我把網址所傳入的東西依照 Controller/Method/Value1/Value2 拆開來了，那麼，我們的 Container 就可以這樣改寫：

```php
<?php 
  class Container extends Controller {
      private $controller;
      private $segments;
      public function __construct() {
      }
      public function startup() {
          // 開始跑
          // 做了一狗票的事情，把網址轉成下列格式，存入 segments 中。
          // Controller/Method/Value1/Value2
          // 所以我們就把 Controller 提出來
          $controllerName = ucfirst(strtolower(array_shift($this->segments)));
          $controllerPath = dirname(__FILE__) . DIRECTORY_SEPArATOR . 'controllers'. DIRECTORY_SEPARATOR . $controllerName . '.php';
          if (file_exists($controllerPath)) {
              require_once $controllerPath;
              $this->controller = new $controllerName;
              $this->controller->startup();
          } else {
              die('Controller does not exists.');
          }
      }
  }
?>

```

方法呼叫也是一樣，繼續改寫 Container 的部份：

```php
<?php 
          if (file_exists($controllerPath)) {
              require_once $controllerPath;
              $this->controller = new $controllerName;
              $this->controller->startup();
              $methodName = ucfirst(strtolower(array_shift($this->segments)));
              if (method_exists($this->controller, $methodName)) {
                  $this->controller->$methodName();
              } else {
                  die('Controller's method does not exists.');
              }
          } else {
              die('Controller does not exists.');
          }
?>

```

傳值呢？我們有好多好多的值要傳，怎麼傳？在 PHP 中有一個方法，叫做 [call\_user\_func\_array](http://php.net/manual/en/function.call-user-func-array.php?ref=blog.hinablue.me)，使用的方式也很簡單，我們看 code 比較快：

```php
<?php 
              if (method_exists($this->controller, $methodName)) {
                  // 原本的呼叫方式我們不要用了
                  // $this->controller->$methodName();
                  call_user_func_array( array(&$this->controller, $methodName), $this->segments );
              } else {
                  die('Controller's method does not exists.');
              }
?>

```

那，如果我要回傳呢？我們在這裡用 JSON 回傳的方式來舉例說明。我們寫一個靜態方法在 Controller 裡面，用靜態的方式來呼叫就好了。

```php
  <?php 
  class Controller {
      public function __construct() {
      }
      public static function responseJSON($data = null) {
          if ($data !== null) {
              if (!is_array($data)) {
                  $data = array((string) $data);
              }
              if ($data = json_encode($data)) {
                  header("pragma: no-cache");
                  header("cache-control: no-store, no-cache, max-age=0, must-revalidate");
                  header("content-type: text/x-json; charset=utf-8");
                  header("X-JSON: ". $data);
                  echo $data;
                  exit;
              } else {
                  die('JSON object invalid.');
              }
          } else {
              die('JSON object invalid.');
          }
      }
  }
  // ... 後面省略一萬行
  ?>

```

你可以這麼做：

```php
  <?php 
  class Api extends Controller {
      public function __construct() {
      }
      public function startup() {
          // 開始跑
      }
      public function ThereIsTheTest() {
          // 這裡省略一萬行
          $data = array('value' => 'There is the test');
          Controller::responseJSON($data);
      }
  }
  ?>

```

是的，這樣一個簡易的 Bootstrap 就完成了。

## 錯誤控制

上面看到不少 die()，寫太多的話你以後要除錯真的會 DIE！不過這個下次再談（疑）。

## 資料控制

idiorm 我們下次見（喂喂）。

## 小結

以入門者來說，要寫一個簡易的控制器並不是難事，你看**像我這種弱雞**都寫得出類似 RESTful API 的東西了，可見這並非太過於困難。-只要有心，人人都可以自己刻-。程式碼的部份無法交代太多，不過，已經有一個專案是以這種類似模式在開發，然後最近要正式上線測試了。

所以說，在程式上還是有很多眉眉角角是必須要去注意的。就像是你永遠沒辦法預防使用者在 ajax 的時候，按下 ESC 或是 F5 鍵一樣（這在瀏覽器動作上，是有可能中斷 ajax 傳輸的操作）。

這是一個很入門的輪子，就像是 @pct 說得，**如果沒有辦法改變世界，那最起碼改變自己的人生**。