karriere / json-decoder
JsonDecoder 实现允许您将 JSON 数据转换为 PHP 类对象
Requires
- php: 8.0.* | 8.1.* | 8.2.*
- php-di/phpdoc-reader: ^2.1
Requires (Dev)
- laravel/pint: ^1.5 | ^1.6
- pestphp/pest: ^1.22
- phpstan/phpstan: ^1.10
README
PHP 的 JsonDecoder
此包包含一个 JsonDecoder 实现,允许您将 JSON 数据转换为 php 类对象,而不是 stdclass
。
安装
您可以通过 composer 安装此包
composer require karriere/json-decoder
使用方法
默认情况下,解码器将遍历所有定义的 JSON 字段,并尝试在给定的类类型实例上设置这些值。这种行为的变化允许在像 Laravel 的 Eloquent 模型这样的使用 魔法 __get
和 __set
函数的类上使用 json-decoder
。
如果找到与 JSON 字段同名或显式定义了 绑定
的属性,它将解码到定义的位置。否则,属性将仅创建和分配(如果您使用的是 PHP 8.2,则需要 #[AllowDynamicProperties]
属性)。
JsonDecoder
类可以接收一个名为 shouldAutoCase
的参数。如果设置为 true,它将尝试在未注册其他绑定的情况下自动从 snake-case 或 kebap-case 查找 camel-case 版本,并且如果找到其中一个变体,它将使用 AliasBinding
。
简单示例
假设您有一个类似下面的 Person
类
#[AllowDynamicProperties] class Person { public int $id; public string $name; public ?string $lastname = ''; }
以下代码将转换给定的 JSON 数据到 Person
的一个实例。
$jsonDecoder = new JsonDecoder(); $jsonData = '{"id": 1, "name": "John Doe", "lastname": null, "dynamicProperty": "foo"}'; $person = $jsonDecoder->decode($jsonData, Person::class);
请注意,由于 PHP 8.2 中动态属性已被弃用,因此如果您仍希望使用这些动态属性,您必须在类中添加 PHP 属性 AllowDynamicProperties
。如果您使用的是 PHP 8.2(以及更高版本)且未使用 AllowDynamicProperties
属性,则所有动态属性都将被忽略。
更复杂的使用案例
让我们通过一个名为 address 的属性扩展前面的示例。此地址字段应包含 Address
的一个实例。从版本 4 开始,您可以使用引入的 scanAndRegister
方法自动根据类注释生成转换器。从版本 5 开始,您还可以使用属性类型而不是类注释。
class Person { public int $id; public string $name; /** * @var Address */ public $address; public ?Address $typedAddress = null; }
对于此类定义,我们可以如下解码 JSON 数据
$jsonDecoder = new JsonDecoder(); $jsonDecoder->scanAndRegister(Person::class); $jsonData = '{"id": 1, "name": "John Doe", "address": {"street": "Samplestreet", "city": "Samplecity"}, , "typedAddress": {"street": "Samplestreet", "city": "Samplecity"}}'; $person = $jsonDecoder->decode($jsonData, Person::class);
定义转换器
如果您不使用注释或需要更灵活的 Transformer
,您还可以创建一个自定义转换器。让我们看看没有注释的先前示例。
class Person { public int $id; public string $name; public mixed $address; }
要能够将地址数据转换为 Address
类对象,您需要为 Person
定义一个转换器
转换器接口定义了两个方法
- register:在这里,您注册您的字段、数组、别名和回调绑定
- transforms:给出全限定类名,例如:Your\Namespace\Class
class PersonTransformer implements Transformer { public function register(ClassBindings $classBindings) { $classBindings->register(new FieldBinding('address', 'address', Address::class)); } public function transforms() { return Person::class; } }
注册转换器后,JsonDecoder
将使用定义的转换器
$jsonDecoder = new JsonDecoder(); $jsonDecoder->register(new PersonTransformer()); $jsonData = '{"id": 1, "name": "John Doe"}'; $person = $jsonDecoder->decode($jsonData, Person::class);
处理私有和受保护属性
从版本4开始,JsonDecoder
类将自动处理private
和protected
属性。
元素数组的转换
如果你的JSON在根级别包含元素数组,你可以使用decodeMultiple
方法将JSON数据转换为类的对象数组。
$jsonDecoder = new JsonDecoder(); $jsonData = '[{"id": 1, "name": "John Doe"}, {"id": 2, "name": "Jane Doe"}]'; $personArray = $jsonDecoder->decodeMultiple($jsonData, Person::class);
文档
转换绑定
以下Binding
实现可用:
FieldBinding
为给定类型定义JSON字段到属性的绑定。
签名
new FieldBinding(string $property, ?string $jsonField = null, ?string $type = null, bool $isRequired = false);
这定义了属性$property
到具有$jsonField
数据的类实例$type
的字段映射。
ArrayBinding
定义了给定类型的数组字段绑定。
签名
new ArrayBinding(string $property, ?string $jsonField = null, ?string $type = null, bool $isRequired = false);
这定义了属性$property
到具有$jsonField
数据的类实例类型$type
的数组字段映射。
AliasBinding
定义了JSON字段到属性绑定。
签名
new AliasBinding(string $property, ?string $jsonField = null, bool $isRequired = false);
DateTimeBinding
定义了JSON字段到属性绑定,并将给定的字符串转换为DateTime
实例。
签名
new DateTimeBinding(string $property, ?string $jsonField = null, bool $isRequired = false, $dateTimeFormat = DateTime::ATOM);
CallbackBinding
定义了一个属性绑定,它将回调结果集作为其值。
签名
new CallbackBinding(string $property, private Closure $callback);
许可
Apache License 2.0 请参阅LICENSE获取更多信息。