自己動手寫 PHP 框架(一)

沙袋發表於2017-04-20

作者:沙袋

作為PHP Coder的入門進階,自己動手寫一個MVC框架可以從各方面鞏固和加深你對PHP的理解,還能瞭解一些架構方面的基礎知識。

1. 什麼是MVC

MVC(Model-View-Controller,模型-檢視-控制器)是PHP最常見的一種開發模式。它將程式劃分為三層。

  • 最上面的一層,是直接面向終端使用者的"檢視層"(View)。它負責給使用者提供操作介面,是程式的外殼。
  • 最底下的一層,是核心的"模型層"(Model),負責檢索、組織和處理程式所需的資料或資訊。
  • 中間的一層,就是"控制層"(Controller),它負責根據使用者從"檢視層"輸入的指令,選取"模型層"中的資料,然後根據業務邏輯對其進行相應的操作,併產生最終結果。

2. 起步

檔案結構如下
框架檔案結構

www目錄將作為網站的根目錄,可以在Apache或Nginx的vhost配置中將www指定為Document Root,將核心程式碼放在根目錄以外,使得使用者無法直接訪問到核心程式碼,提高整站的安全性。

3. 入口

既然www是根目錄,那www下的index.php就可以作為整站的入口,當然,你也可以在www下繼續寫usercenter.php、admin.php等來作為其它模組的入口,你只需要制定規則就好。

而作為入口,由於它可以接收到發往它的所有資料,因此可以按照框架制定的路由規則對資料進行分發處理。因此,在入口,需要引入初始化程式,然後進行路由分發。

/* Nova/www/index.php */
<?php
//給目錄定義一些常量
define('ROOT_DIR', __DIR__.'/..');
define('APP_DIR', ROOT_DIR.'/Application');
define('CONFIG_DIR', ROOT_DIR.'/config');
define('FRAMEWORK_DIR', ROOT_DIR.'/Framework');
define('LOG_DIR', ROOT_DIR.'/logs');
define('WWW_DIR', __DIR__.'/');
//設定一下站點的時區
define('TIMEZONE', 'Asia/Shanghai');
ini_set('data.timezone', TIMEZONE);
//引入初始化程式
require FRAMEWORK_DIR.'/init.php';

4. 初始化程式

/* Nova/Framework/init.php */
<?php
namespace Nova\Framework;

//引入配置檔案
require CONFIG_DIR . '/config.php';
引入自動載入類
require 'Autoloader.php';

//初始化自動載入
Autoloader::init();
//啟用Session
Session::start();

//啟動核心處理程式
$core = new Core;
$core->run();

初始化的過程涉及到了自動載入類及Session的處理,這兩部分我們稍後介紹。先來說說核心處理程式,我把路由分發邏輯放在了這裡。

5. 核心處理程式

/* Nova/Framework/Core.php */
<?php
namespace Nova\Framework;

class Core
{
    public function run()
    {
        $this->setReporting();
        $this->route();
    }

    /**
     * 設定整站的錯誤報告等級
     */
    public function setReporting()
    {
        if (DEBUG_MODE === true) {
            error_reporting(E_ALL);
            ini_set('display_errors', 'On');
        } else {
            error_reporting(E_ALL);
            ini_set('display_errors', 'Off');
            ini_set('log_errors', 'On');
            ini_set('error_log', LOG_DIR . 'error.log');
        }
    }

    /**
     * 路由規則
     *
     * 使用$_REQUEST['act']來定位控制器的類
     * 使用$_REQUEST['st']來定位具體的方法
     */
    public function route()
    {
        //如果$_REQUEST中沒有'act',則設定預設act為index
        if (!isset($_REQUEST['act'])) {
            $_REQUEST['act'] = 'index';
        }

        //如果$_REQUEST中沒有'st',則設定預設act為main
        if (!isset($_REQUEST['st'])) {
            $_REQUEST['st'] = 'main';
        }
        //根據act定位控制器類
        $className = 'Nova\\Application\\Controllers\\' . $_REQUEST['act'];
        //判斷控制器類是否存在,不存在則報404
        if (!class_exists($className)) {
            header('HTTP/1.1 404 Not Found');
            die($className);
        }

        //生成目標控制器類物件
        $obj = new $className();

        //判斷方法是否存在,不存在則報404
        if (!method_exists($obj, $_REQUEST['st'])) {
            header('HTTP/1.1 404 Not Found');
            exit;
        }
        //執行目標方法
        $obj->$_REQUEST['st']();
    }
}

你可以在Github上檢視Nova專案的原始碼。

如果你有任何問題或建議,可以掃描下方二維碼或者微信搜尋[phpjiagoushier],關注我的微信公眾號[PHP架構],與我交流互動。
phpjiagoushier

相關文章