php實現hack中的Shape特性

x3d發表於2016-07-31

用php進行靜態型別程式設計,估計是我的一個心結。

依次有幾篇文章都記錄了我的一些探索:

從PHP 7 開始,PHP支援函式和方法的引數及返回值的標量型別標註,逐漸走出了這一步。

但資料傳遞的過程中,基礎的標量型別很多時候是不夠用的。比如引數太多的時候,一般用陣列或物件的方式傳遞,二者中用得最多是陣列 – 萬能的陣列,但陣列的結構不明確,在資料傳遞的過程中,對於DTO(Data Transfer Object,資料傳輸物件)相應資料結構的理解和驗證,往往需要額外花費不少時間和精力。在我看來,Hack 語言的Shape型別很好的解決了這個問題。

hack中Shape的用法如下:

type customer = shape(`id` => int, `name` => string);

function create_user(int $id, string $name): customer {
  return shape(`id` => $id, `name` => $name);
}

function ts_shape(): void {
  $c = create_user(0, "James");
  var_dump($c[`id`]);
  var_dump($c[`name`]);
}

ts_shape();
Output
int(0)
string(5) "James"

今天動手實現類似hack中的Shape定義,hack中shape本質上是一個陣列。

Shapes 是一種特殊的別名型別,代表結構固化的陣列 – 固定的鍵名和型別。定義的Shape可用於型別標註場合。

藉助於php的gettype函式,實現類似強型別的概念,不做型別casting。

支援php的基本型別:int、bool、float、string,及array、object、null。

基本用法:

class Customer extends Shape
{
    public function __construct(array $data) {
        parent::__construct(
            [`id` => self::int, `name` => self::string, `categories` => self::array],
            $data
        );
    }
}

//資料訪問與陣列一樣,只是一言不合就會拋異常,確保在開發階段,做好資料型別分析和轉換

$customer = new Customer([`id` => 102, `name` => `jimmy`, `categories` => [10, 21, 22]]);//如果categories寫成categories2,meta中定義的categories就會被填充一個對應的預設值。

$customer[`id`] = 103; //如果傳`103`就會拋異常
var_dump($customer[`id`]);
var_dump($customer[`categories`]);
echo count($customer);
var_dump($customer->toArray());//PHP的array強轉還不支援魔術方法定製toArray行為,只能由使用者自行呼叫了

完整程式碼的檢視地址:https://github.com/web3d/lang/blob/master/src/AppserverIo/Lang/Shape.php


相關文章