自研 PHP 框架 1.0_system 資料夾說明

student33發表於2019-12-22

目錄結構

  • system
    • constant.php
    • function.php
    • url.php

system資料夾用來放置構建框架環境的所有檔案。

1.0 版本中只提供了路由解析功能,由 url.php 提供;constant.php 用來定義常量,function.php 則是框架級的函式庫,與之對應,APP 中可以定義應用級的函式庫,如果存在應用級的函式庫,兩者之間的關係是上下級。

constant.php 和 function.php 與 url.php 分屬於不同的功能劃分。

從功能劃分角度來看,constant.php 和 function.php 都是必須存在且唯一的,屬於框架配置;url.php 屬於框架功能,與它處於同一級別的還可以有很多其他的功能元件。

功能元件這個概念,為構建超大型的專案提供了一種相當效率的解決思路。
不同的功能被抽象成一個個零部件,通過組合使用這些功能元件,完成業務需求。並且隨著功能元件的不斷增加,後續的需求研發會越發簡單起來,主要的精力放在演算法即可,用輪子就好,無需再花費相當的精力去造輪子。
這裡要特別提及 composer,PHP 專案利用 composer 包管理器可以非常便利的利用別人造的輪子,基本上可以無痛的嵌入到自己的專案當中,使用別人的勞動成果是非常有效的一種方式,可以讓我們更高效的利用自己的時間,提升效率。

Constant.php 說明

<?php
// 字尾
define('EXT','.php');

// 路徑
define('ROOT',__DIR__.'/../');
define('APP',ROOT.'app/');
define('SYSTEM',ROOT.'system/');

1.0 版本只設定了上訴的常量,有兩個部分:字尾和路徑。

抽象的來看,路徑可以看成一個必需的大類,其他是另一大類。

字尾只是包含在其他當中的一個細分,除了字尾之外,還可以定義同級的常量,比如作業系統、分隔符等等,存在很多與字尾同級的其他常量,設不設定以及如何設定,並沒有定法。

在我看來,這完全取決於開發者(想怎麼玩就怎麼玩)。但是路徑,是一個必備的部分,無論哪一個框架都必然存在,好處很明顯,可以大大的簡化路徑書寫時的複雜度(寫的少),而且可以使用更具辨識度的名稱。

Function.php 說明

<?php
function vd($data)
{
    echo '<pre>';
    var_dump($data);
    echo '</pre>';
}

function vde($data)
{
    vd($data);
    exit;
}

1.0 版本就設定了兩個框架級函式,照搬 TP 的命名,vd 和 vde。

在 1.0 demo 中並不屬於必需,列舉在這裡,只是說明,框架中會有一個或多個檔案用來存放框架級的函式。

只所以說一個或多個,取決於框架的複雜程度以及開發者的喜好,列舉 TP 的做法來進行一個對比,TP 中的框架級函式都在一個檔案中,按類別進行了區分,寫法如下:

<?php

//時間函式
...

//檔案函式
...

//字串函式
...

如果函式庫豐富(幾十上百個函式),即使是在 IDE 中,也是相當難使用的,尤其是在學習使用的時候。針對這種情況,可以進行進一步的劃分。

如上,將時間函式放到一個檔案當中,將檔案函式放到另一個檔案當中,每一個檔案存放一個類別,可以更好的幫助定位,而且單個檔案並不會很大。

究竟使用何種方式,還是取決於開發者的那靈光一閃。(很多的設計,並沒有那麼多的為什麼,就像 Python 取名一樣,作者喜歡看這個肥皂劇,所以就有了這麼個名字,事實往往就是這麼的平淡無奇)

Url.php 說明

這裡介紹 url.php 這個功能元件,下面會列舉具體的程式碼,並詳細說明為什麼這樣設計,以及是否還有其他的方案。

<?php
/**
 * url解析器
 */

 class url
 {
    //  模組
    private static $module = 'admin';
    // 控制器
    private static $controller = 'index';
    // 方法
    private static $func = 'index';
    // 需要載入的檔案路徑
    private static $path = 'admin/controller/index';

    /**
     * 從超全域性變數獲取模組/控制器/方法
     */
    public static function analyse($data = [])
    {
        // module,controller,function  one of them exists
        if(!empty($data['PATH_INFO'])){
            $arr = explode('/',ltrim($data['PATH_INFO'],'/'));
            $num = count($arr);//module,controller,function,can exists or not

            switch($num){
                case 1:
                    self::$module = $arr[0];// the rest use index
                    self::$path = $arr[0].'/controller/index';
                break;
                case 2:
                    self::$module = $arr[0];
                    self::$controller = $arr[1];
                    self::$path = $arr[0].'/controller/'.$arr[1];
                break;
                case 3:
                    self::$module = $arr[0];
                    self::$controller = $arr[1];
                    self::$func = $arr[2];
                    self::$path = $arr[0].'/controller/'.$arr[1];
                break;
            }
        }
    }

    /**
     * get param
     */
    public function get($parse_name)
    {
        return self::$$parse_name;
    }

    /**
     * set param
     */
    public function set($parse_name,$parse_value)
    {
        self::$$parse_name = $parse_value;
    }
 }

首先是功能模組的命名,也就是類名,準確的反應功能是非常重要的。

好的命名,在使用過程中會減少許多無謂的消耗,能夠從名字上判斷出功能的,就不需要進入檔案檢視具體的實現,這只是看起來不起眼但實際上是相當提升效率的操作。

往下是類的屬性定義部分,我這裡的設計將模組,控制器以及方法完全分開,單獨進行了處理,並且設計了一個變數用來儲存應用檔案的路徑。

這裡的設計,要關注的點是 url.php 這個功能元件被設計用來幹什麼,其內部的具體實現都是基於這個目的來的,1.0 demo 中,url.php 被設計用來解析超全域性陣列得到具體的路由資訊,這是我們的目的

明確了這個目的之後,再往下就是對抽象目標的具體建模。
為了達到拿到路由資訊的目的,屬性定義可以有各種各樣的實現方法,如將所有的變數都可以放到一個陣列當中,而不是拆開來做。具體選擇哪種做法,需要根據場景來進行設計。
比如我現在做的這個框架 demo,只需要跑通流程就可以,並需要考慮的太多,如果是商用的,情況肯定是不一樣的,需要考慮實際的使用情況,如何設計會更便捷、更易於使用,從這樣的一個角度出發,可能用陣列來進行組織可能是更好的解決方法,使用時,不會像這種設計這樣麻煩,後面說明方法設計時,會進一步解釋。

繼續往下就到了方法部分。

其中 get 和 set 我認為應該成為一種標配,類中所有屬性值的設定和取用都應該通過對外統一的介面來操作,統一、規範和標準的目的是為了工程實踐中的便捷,所有的類屬性的取用設定都使用同樣的方式,會減少學習成本,這是採用這種設計的主要理由。

接下來就到了本功能元件最重要的部分,function analyse

關注點依然要放在其目的上,而不是其實現細節,因為實現的細節會因屬性設計部分的變更而變更,目前呈現的這種形式是由屬性設計而決定的,這一點一定要特別清楚,當在學習其他框架時無需太關注於其中的細節,只需要弄明白當前功能元件實現的功能是什麼即可。

在這裡,analyse 所做的就是根據請求拿到需要執行檔案的路由。

最後還有一點要進行說明:

pubic static function analyse($data = []){
    ...
}

這裡使用的是 static,只所以這樣設計,是為了使用靜態的一個特性,在執行靜態方法時不需要建立一個物件,然後藉助物件來呼叫方法,會讓指令碼變得簡潔、易懂。

比如,index.php 中就可以這樣寫:

...
// 解析陣列拿到路徑
url::analyse($_SERVER);
...

看起來非常的簡潔,less is more。

PS:本系列文章最佳閱讀方式,IDE+本地執行環境,IDE中閱讀可配合 demo 執行增進理解,GitHub地址

城裡的野山參

相關文章