jsonobject
jsonobject
是一個 PHP 類,用於簡化來自 JSON 定義的物件的使用。這個想法來自於在 python 中使用pydantic
,以及它解析和驗證 json 資料為物件的能力。
jsonobject
我必須使用 PHP 的 API,該 API 傳回了jsonobject 。所以我需要將它們解析為我可以在應用程式中使用的 PHP 物件。
工作流程是
jsonobject
解析 JSON 定義讓我們看下面的 JSON 範例:
{
"id" : 0 ,
"name" : " John Doe " ,
"age" : 42 ,
"emails" : [
" [email protected] " ,
" [email protected] "
],
"address" : {
"street" : " My street " ,
"number" : 42 ,
"city" : " My city " ,
"country" : " My country "
}
}
使用jsonobject
,我將能夠使用以下類別定義我的資料模型:
class User extends jsonobject {
const ATTRIBUTES = [
' id ' => ' int ' ,
' name ' => ' str ' ,
' age ' => ' int ' ,
' emails ' => ' list[str] ' ,
' address? ' => ' Address ' ,
];
}
class Address extends jsonobject {
const ATTRIBUTES = [
' street ' => ' str ' ,
' number ' => ' int ' ,
' city ' => ' str ' ,
' country ' => ' str ' ,
];
}
然後加入以下命令:
$ user = User:: fromObject ( json_decode ( $ json_text_definition ));
jsonobject
類別將把內容解析為對象,我們將能夠使用它定義的屬性:
echo ( $ user -> name );
定義的類別還可以具有使實現應用程式的資料模型更容易的方法。例如,可以像這樣定義User
類別:
class User extends jsonobject {
const ATTRIBUTES = [
' id ' => ' int ' ,
' name ' => ' str ' ,
' age ' => ' int ' ,
' emails ' => ' list[str] ' ,
' address? ' => ' Address ' ,
];
public function isAdult () {
return $ this -> age >= 18 ;
}
}
jsonobject
jsonobject
類別的想法是使用它來將json資料解析為物件。因此這些物件可能包含其他有助於實現應用程式的資料模型的方法。
當解析 json 物件(或陣列)時,會根據ATTRIBUTES
常數中定義的型別遞歸解析其內容。如果資料無效,因為它不包含預期值,則會引發異常。
要使用jsonobject必須子類化jsonobject
並為該類別定義ATTRIBUTES
常數,以便它定義該類別物件所需的屬性以及每個屬性的類型。
ATTRIBUTES
常數是一個關聯數組,其中鍵是每個屬性的名稱,值是每個屬性的類型。
可能的類型可以是:
jsonobject
的子類別。定義屬性名稱時,可以加?
位於名稱末尾以指示該屬性是可選的。例如屬性名稱address?
用例部分中的內容是可選的。
每個欄位都被認為是強制性的,因此它必須存在於解析的物件(或陣列)中。此外,該物件必須是定義的類型(即它必須由特定類型正確解析)。
任何非可選屬性都被視為強制屬性。這有兩點特別令人感興趣:
fromArray
或fromObject
函數)。jsonobject
的物件或陣列表示時當從外部結構建立物件時, jsonobject
將處理每個必填欄位。如果缺少其中任何一個,就會引發異常。
在下一個範例中,由於未提供必填欄位年齡,因此將引發異常。
class User extends jsonobject {
const ATTRIBUTES = [
" name " => " str " ,
" age " => " int " ,
];
}
( . . . )
$ user = User:: fromArray ([ " name " => " John " ]);
當將物件轉換為陣列或物件(或取得其 json 表示形式)時,必填欄位將獲得預設值,即使未設定也是如此。
所以在下一個例子中
class User extends jsonobject {
const ATTRIBUTES = [
" name " => " str " ,
" age " => " int " ,
" birthDate? " => " str "
];
}
$ user = new User ();
echo (( string ) $ user );
輸出將是
{
"name" : " " ,
"age" : 0
}
因為雖然名稱和年齡屬性是強制性的,並且它們具有預設值(即數字為 0,字串、列表或字典為空),但屬性birthDate不是強制性的,並且尚未設定。所以它不會在輸出中生成。
null
在考慮屬性是否可選時,將值設為null的問題具有特殊意義。
人們可能會認為,如果我們將一個值設為null,則表示取消設定該值,因此它應該只適用於可選值,而不適用於強制值。
在jsonobject
中,我們有一個不同的概念,因為將屬性設為null意味著“將值設為null ”,而不是取消設定該屬性。為了取消設定屬性,我們應該使用 unset 函數或類似的函數。
jsonobject
也可以取消設定值。對於可選屬性,這表示刪除該值,因此它在陣列表示形式或物件中不會有任何值(如果檢索該值,它將設定為null )。
但對於強制屬性,取消設定意味著將其值重設為預設值。這表示它將初始化為類型的預設值(即數字為 0,列表、字串或字典等為空)或其ATTRIBUTES
常數中的預設值。
jsonobject
也能夠從其父類別繼承屬性。舉個例子:
class Vehicle extends jsonobject {
const ATTRIBUTES = [
" brand " => " str " ,
" color " => " str "
]
}
class Car extends Vehicle {
const ATTRIBUTES = [
" wheels " => " int "
]
}
class Boat extends Vehicle {
const ATTRIBUTES = [
" length " => " float "
]
}
在此範例中,類Vehicle
僅具有品牌和顏色屬性,但類Car
將具有品牌、顏色和車輪屬性,而類Boat
將具有品牌、顏色和長度屬性。
可以使用靜態方法::fromArray
或::fromObject
建立來自jsonobject
子類別的對象,從json解析的對象開始。
在前面的範例中,如果我們有一個包含以下內容的檔案car.json :
{
"brand" : " BMW " ,
"color" : " black "
}
我們可以使用下面的程式碼來取得Vehicle
類別的實例:
$ json = file_get_contents ( " car.json " );
$ vehicle = Vehicle:: fromArray (( array ) json_decode ( $ json , true ));
另一種方法是實例化對象,如下例所示
* PHP 8以上:
$ car = new Car (brand: " BMW " , color: " black " , wheels: 4 );
*以前的 PHP 版本:
$ car = new Car ([ " brand " => " BMW " , " color " => " black " , " wheels " => 4 ]);
jsonobject
jsonobject
是該函式庫的核心類別。其方法有:
__construct($data)
- 根據給定資料建立一個新對象__get($name)
- 傳回具有給定名稱的屬性的值__set($name, $value)
- 設定具有給定名稱的屬性的值__isset($name)
- 如果設定了給定名稱的屬性,則傳回 true__unset($name)
- 取消設定可選屬性的值(或重設強制屬性的值)。toArray()
- 傳回一個包含物件資料的關聯數組。此陣列是遞歸創建的,存取每個屬性的每個子屬性。toObject()
- 傳回一個對象,並將該對象的資料作為屬性。此陣列是遞歸創建的,存取每個屬性的每個子屬性。toJson()
- 傳回一個 json 字串,其中包含作為標準物件的物件表示。::fromArray($data)
- 透過將給定的關聯數組解析為類別中定義的屬性來建立一個物件。每個屬性都會根據定義的類型進行遞歸解析。::fromObject($data)
- 透過將給定物件解析為類別中定義的屬性來建立物件。每個屬性都會根據定義的類型進行遞歸解析。 JsonDict
該物件用於處理來自 json 定義的字典。 JsonDict
類別的類型是每個元素都必須來自給定類型。
JsonDict
物件可以用作類似陣列的物件(例如 $jsonDict["key1"]),但是(在撰寫本文時)不會檢查插入字典中的元素的類型。此類型用於在建立字典時解析內容(例如使用fromArray
靜態函數)或將內容轉儲到陣列或物件(例如使用toArray
函數)。
方法有:
toArray()
toObject()
::fromArray($data)
::fromObject($data)
這些方法的解釋方式與jsonobject
的情況相同。並且字典中元素的類型可能指的是在解析內容時將遞歸地考慮的複雜類型。
例如型別list[list[int]]
將用於解析[ [ 1, 2, 3], [ 4, 5, 6 ]]
JsonArray
該物件與JsonDict
非常相似,只是索引必須是整數。在這種情況下$value["key1"]
將產生異常。
在這種情況下,也實現了向數組追加元素的功能(即[]
)。
定義類別時,可以初始化新建立的物件的值以及那些可選屬性。
有兩種方法:
### 使用類別屬性
可以使用類別屬性來初始化物件的值,因此,如果在類別中設定了屬性的值,則如果定義了該屬性,它將作為屬性複製到實例中。
例如
class User extends jsonobject {
const ATTRIBUTES = [
' id ' => ' int ' ,
' name ' => ' str ' ,
' age ' => ' int ' ,
' emails ' => ' list[str] ' ,
' address? ' => ' Address ' ,
' sex? ' => ' str '
];
public $ sex = " not revealed " ;
}
現在,屬性sex
被初始化為不顯示而不是null 。
實作的方法是為物件的型別定義一個元組[ <type>, <default value> ]
。舉下一個例子:
class User extends jsonobject {
const ATTRIBUTES = [
' id ' => ' int ' ,
' name ' => ' str ' ,
' age ' => ' int ' ,
' emails ' => ' list[str] ' ,
' address? ' => ' Address ' ,
' sex? ' => [ ' str ' , ' not revealed ' ]
];
}
檢索使用者資料時,屬性sex
是可選的。使用該類別的這個新定義,如果未設定sex
,則該值將設定為「未顯示」而不是null
。
一個重要的特性是,如果設定為<default value> 的字串對應於物件的某個方法,則在取得該值時將呼叫該方法(如果尚未設定),並且為該屬性設定的值將被調用。
例如
class User extends jsonobject {
const ATTRIBUTE = [
...
' birthDay? ' => [ ' str ' , ' computeBirthDate ' ]
]
function computeBirthDate () {
$ now = new DateTime ();
$ now ->sub( DateInterval ::createFromDateString("{ $ this -> age } years"));
return $ now ->format("Y-m-d");
}
}
在這個例子中,如果我們沒有設定birthDate
屬性但它被檢索,它將透過當前日期減去年齡來計算。
如果想要將任意物件解析為jsonobject
,可以使用函數jsonobject ::parse_typed_value
。這對於能夠從任何類型轉換為jsonobject
類型非常重要。
例如
$ myobject = jsonobject :: parse_typed_value ( " list[str] " , [ " my " , " name " , " is " , " John " ]);
將會取得JsonList<str>
類型的物件。
該庫的預設行為是確保為屬性設定的值與其定義的類型相符。但這意味著,由於float
不是int
,因此將 float 設為0
將失敗,因為0
是整數。在這種情況下,使用者必須在分配值之前強制轉換它們。若要控制是否嚴格檢查型,可以使用常數STRICT_TYPE_CHECKING
。
如果
STRICT_TYPE_CHECKING
設為True
,則類型將被嚴格檢查,例如將9.3
指派給int
將引發例外狀況。如果設定為False
,數字類型將相互轉換。因此,例如,如果我們將9.3
分配給int
它將自動截斷為9
。
其他重要的類型檢查是將空值(即""
或null
)指派給數字類型時。在這種情況下,我們有常數STRICT_TYPE_CHECKING_EMPTY_ZERO
。
如果
STRICT_TYPE_CHECKING_EMPTY_ZERO
設定為True
(預設行為),則在將空值指派給數字類型時,它將被視為0
。即,將空字串或null
值指派給int
屬性,將意味著指派0
。如果設定為False
,程式庫將檢查類型並最終引發異常。
現在JsonList
也可以使用負索引,因此-1
將是最後一個元素, -2
將是倒數第二個元素,等等。
JsonList
物件包含用於排序或篩選的函數。
public function sort(callable $callback = null) : JsonList
:使用給定的回呼對清單進行排序。如果沒有給出回調,它將使用預設的比較函數對列表進行排序。public function filter(callable $callback) : JsonList
:使用給定的回呼過濾清單。回調必須傳回一個布林值。如果回呼傳回true
,則該元素將包含在結果清單中。如果傳回false
,該元素將被丟棄。