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
,该元素将被丢弃。