PHP 用 Enum 限定引數型別

麥索發表於2019-03-04

痛點

PHP 是一門若型別語言,這是大家都知道的,弱型別讓我們在編寫程式碼時很舒服,但是維護它卻變得不那麼舒服,一個小型的 PHP 專案只有有限的幾個程式設計師去維護的話,其實這個問題並不明顯,也不會成為困難,但是當專案變大,協作的人數變多的時候這就是一個需要去正式的問題。

PHP 7 和 PHP < 7

在PHP 7 之前我們對引數沒有太多的限定。


function test(array $arr, AppModelUser $user)
{

}複製程式碼

PHP 7 之前我們只能對形參做這樣的限制,無法限定基礎型別。而 PHP7 之後我們可以對引數進行基礎型別限制了。

function test(array $arr, AppModelUser $user, string $string, int $int, bool $bool, float $float) : int 
{

}複製程式碼

可以對形參進行基礎型別進行限制,並且方法和函式的返回值也可以提前告知。

這樣的好處就是多少協作時,不需要他人呼叫一個他不熟悉或者從來沒有用過的方法或者函式的時候去找到定義的人進行溝通,程式碼已經告訴他需要傳遞什麼樣的引數給函式,減少了多餘的協作溝通成本。

當然無論是 PHP 7 還是 php 5.* 其實都有一個庫可以做到這些功能,那就是 SPL Type ,但是這個庫雖然以 SPL 命名但並不和 SPL 一樣預設整合 PHP 裡,它不是 PHP 的核心元件一部份,因此需要獨立去安裝。

當你使用 PHP 5.* 而不是 PHP 7 的時候,想要達到引數限定可以去安裝它。若你使用 PHP 7 這個庫的功能其實已經沒什麼用了,唯一還用的就是 SplEnum 這個類。

SplEnum 這個類實現了其他程式語言的列舉功能,那麼列舉有什麼用呢,我們可以假設這樣一個場景,我們有一個很大的專案,有百人的開發團隊或者更多,作為最初專案的文章模組的設計開發者你定義了一個建立文章的方法,這個方法需要兩個引數。一個引數是外部表單提交或者其他途徑獲得的資料,一個是將要建立的文章的型別。

你可以通過文件、資料庫註釋、方法註釋等一系列方法告訴呼叫者該如何傳參,但是如果有的人這些都沒讀或者懶得去看那麼你該如何限定他們用不正確的方法呼叫這個方法呢?

似乎好像沒有辦法了。

但是這個類就可以幫助我們,這裡我使用了一個和擴充套件同樣功能的PHP程式碼實現的包 https://github.com/myclabs/php-enum

<?php

---- # 1.定義 Enum 部分
namespace Type;

require `./vendor/autoload.php`;



class ArticleTypeEnum extends MyCLabsEnumEnum
{
    const GENERAL = 1;
    const JOB = 2;
    const DISCUSS = 3;
    const SHARE = 4;
    const COURSE = 5;
    const LIFE = 6;
    const SPECIAL_COLUMN  = 7;
}

---- # 2.定義方法部分

function createArticle(array $data, ArticleTypeEnum $articleTypeEnum){
    // 建立對應的型別的文章
}

---- # 3.呼叫部分

try{
    testTypeEnum($data, new ArticleTypeEnum(ArticleTypeEnum::COURSE));
}catch (Exception $exception){
    echo $exception->getMessage();
}複製程式碼

我在第一部分定義了列舉類,整合列舉基類 MyCLabsEnumEnum ,在類中定義了幾個文字型別常量。

第二部分是一個虛擬碼的一個建立文章的方法。

第三部分是呼叫部分,可以看見因為第二個引數已經被限定為列舉類,所以我必須傳遞一個列舉型別例項給建立方法,如果傳遞的不是列舉類的例項,那麼程式就會丟擲異常。

很簡單的我就可以將外部呼叫時要建立的文章型別限定在規定範圍內而不會出現未知的引數,或者一些髒資料進入到資料庫中去,同時程式碼層面就告訴呼叫者應該如何去傳遞引數。

在傳遞第二個引數的時候你可能覺得麻煩,其實這個庫作者已經想到了。

<?php

---- # 3.呼叫部分

try{
    testTypeEnum($data, ArticleTypeEnum::GENERAL());
}catch (Exception $exception){
    echo $exception->getMessage();
}複製程式碼

這樣就可以了,這是利用 PHP 的魔術方法 __callStatic() 實現的呼叫相應常量。

這樣我們就可以在程式碼層面控制引數型別以提高我們的程式可維護性了。

相關文章