netresearch / jsonmapper
将嵌套 JSON 结构映射到 PHP 类
Requires
- php: >=7.1
- ext-json: *
- ext-pcre: *
- ext-reflection: *
- ext-spl: *
Requires (Dev)
- phpunit/phpunit: ~7.5 || ~8.0 || ~9.0 || ~10.0
- squizlabs/php_codesniffer: ~3.5
- dev-master
- v5.0.0
- v4.5.0
- v4.4.1
- v4.4.0
- v4.3.0
- v4.2.0
- v4.1.0
- v4.0.0
- v3.1.1
- v3.1.0
- v3.0.0
- v2.1.0
- v2.0.0
- v1.6.0
- v1.5.2
- v1.5.1
- v1.5.0
- v1.4.0
- v1.3.0
- v1.2.0
- v1.1.1
- v1.1.0
- v1.0.0
- v0.11.0
- v0.10.0
- v0.9.0
- v0.8.0
- v0.7.0
- v0.6.1
- v0.6.0
- v0.5.0
- v0.4.4
- v0.4.3
- v0.4.2
- v0.4.1
- v0.4.0
- v0.3.0
- v0.2.1
- v0.2.0
- v0.1.3
- v0.1.2
- v0.1.1
- v0.1.0
This package is auto-updated.
Last update: 2024-09-08 10:20:15 UTC
README
将来自 JSON 网服务的数据转换为嵌套对象和数组 - 使用您自己的模型类。
从基础对象开始,它将 JSON 数据映射到类属性上,将它们转换为正确的简单类型或对象。
这与 PHP 的 SoapClient
提供的本地 SOAP 参数映射类似,但用于 JSON。它不依赖于任何模式,只依赖于您的 PHP 类定义。
类型检测通过解析类型声明和类属性的 @var
文档注释以及设置方法中的类型提示来实现。
您不需要通过添加 JSON 特定代码来修改您的模型类;它通过解析已存在的文档注释自动工作。
此库没有依赖。
关键词:反序列化,活化
内容
利弊
好处
- IDE 中的自动完成
- 轻松向数据模型类添加便捷方法
- 您的 JSON API 可能会更改,但您的模型可以保持不变 - 不会破坏使用模型类的应用程序。
缺点
模型类需要手动编写
由于 JsonMapper 不依赖于任何模式信息(例如来自 json-schema),因此模型类不能自动生成。
用法
基本用法
- 安装
netresearch/jsonmapper
使用 composer - 创建一个
JsonMapper
对象实例 - 根据您的数据调用
map
或mapArray
方法
映射普通对象
<?php require 'autoload.php'; $mapper = new JsonMapper(); $contactObject = $mapper->map($jsonContact, new Contact()); // or as classname $contactObject = $mapper->map($jsonContact, Contact::class);
映射对象数组
<?php require 'autoload.php'; $mapper = new JsonMapper(); $contactsArray = $mapper->mapArray( $jsonContacts, array(), 'Contact' );
除了 array()
,您还可以使用 ArrayObject
和其派生类,以及实现 ArrayAccess
的类。
示例
来自地址簿网络服务的 JSON
{ "name":"Sheldon Cooper", "address": { "street": "2311 N. Los Robles Avenue", "city": "Pasadena" } }
您本地的 Contact
类
<?php class Contact { /** * Full name */ public string $name; public ?Address $address; }
您本地的 Address
类
<?php class Address { public $street; public $city; public function getGeoCoords() { //do something with $street and $city } }
您的应用程序代码
<?php $json = json_decode(file_get_contents('http://example.org/sheldon.json')); $mapper = new JsonMapper(); $contact = $mapper->map($json, new Contact()); echo "Geo coordinates for " . $contact->name . ": " . var_export($contact->address->getGeoCoords(), true);
属性类型映射
JsonMapper
使用以下顺序的几个来源来检测属性的正确类型
设置方法(
set
+ucwords($propertyname)
)下划线 "
_
" 和连字符 "-
" 将下一个字母转换为大写。属性foo_bar-baz
导致设置方法setFooBarBaz
。如果方法签名中有类型提示,则使用该类型
public function setPerson(Contact $person) {...}
检查方法的文档注释以查找
@param $type
注释/** * @param Contact $person Main contact for this application */ public function setPerson($person) {...}
如果无法检测到类型,则将纯 JSON 值传递给设置方法。
类属性类型(自 PHP 7.4 以来)
public Contact $person;
构造函数属性提升类型(自 PHP 8.0 以来)
public function __construct(protected Contact $person) {}
@var $type
类属性文档注释/** * @var \my\application\model\Contact */ public $person;
属性必须是公开的才能直接使用。您还可以使用 $bIgnoreVisibility 来使用受保护和私有属性。
如果无法检测到类型,属性将获得纯JSON值设置。
如果找不到属性,JsonMapper 将尝试以不区分大小写的方式找到该属性。然后 JSON 属性
isempty
将映射到 PHP 属性isEmpty
。注意
必须提供完全限定的命名空间以使类型工作。相对类名在当前类命名空间中评估,而不考虑可能存在的任何导入。
PHP 不通过反射提供导入;注释文本仅包含类型的文字文本。出于性能原因,JsonMapper 不会自行解析源代码以检测和扩展任何导入。
支持的类型名称
简单类型
字符串
bool
、boolean
int
、integer
double
、float
数组
对象
混合
类名称,包括和不包括命名空间
Contact
- 如果 JSON 值是null
,则抛出异常
简单类型和类名称的数组
int[]
Contact[]
多维数组
int[][]
TreeDeePixel[][][]
简单类型和类名称的 ArrayObjects
ContactList[Contact]
NumberList[int]
带和不带命名空间的受支持枚举
Suit:string|Suit:int
- 如果 JSON 值不在枚举中,则抛出异常
可空类型
int|null
或?int
- 如果 JSON 中的值为null
,则将是null
,否则它将是整数Contact|null
或?Contact
- 如果 JSON 中的值为null
,则将是null
,否则它将是类型为Contact
的对象
ArrayObjects 和扩展类被视为数组。
没有类型或类型为 mixed
的变量将直接设置 JSON 值,而无需任何转换。
有关更多信息,请参阅 phpdoc 的类型文档。
简单类型映射
注意
由于安全原因,从版本 5 开始默认禁用此功能。有关详细信息,请参阅 $bStrictObjectTypeChecking。
当应该创建一个对象但 JSON 仅包含简单类型(例如字符串、浮点数、布尔值)时,此值将传递给类的构造函数。示例
PHP 代码
public DateTime $date;
JSON
{"date":"2014-05-15"}
这将导致调用 new DateTime('2014-05-15')
。
类映射
当变量定义为抽象类或接口的对象时,JsonMapper 通常会尝试直接实例化这些类并崩溃。
使用 JsonMapper 的 $classMap
属性,您可以指定哪些类应被实例化
$jm = new JsonMapper(); $jm->classMap['Foo'] = 'Bar'; $jm->map(...);
这将创建类型为 Bar
的对象,当变量定义为类型为 Foo
时。
如果实际实现类需要动态确定(例如在联合的情况下),还可以使用可调用。映射类(下面的示例中的 'Foo')和 Json 数据作为参数传递到调用中。
$mapper = function ($class, $jvalue) { // examine $class and $jvalue to figure out what class to use... return 'DateTime'; }; $jm = new JsonMapper(); $jm->classMap['Foo'] = $mapper; $jm->map(...);
可空
除非 PHP 类属性具有可空类型 - 例如 Contact|null
或 ?Contact
,否则 JsonMapper 在 JSON 属性为 null
时抛出异常。
如果您的 API 中包含许多可能为 null
的字段,并且您不希望使所有类型定义都为可空的,请设置
$jm->bStrictNullTypes = false;
从 5.0.0 版本开始,如果类型不是可空的 - 例如 array[?string]
或 array[string|null]
,则数组中的 null
值会导致 JsonMapper_Exception
。
要恢复以前的行为(允许 null,即使未声明),请设置
$jm->bStrictNullTypesInArrays = false;
日志记录
JsonMapper的setLogger()
方法支持所有与PSR-3兼容的日志记录实例。
被记录的事件
- JSON数据包含一个键,但类中没有相应的属性或设置方法。
- 由于它们是受保护的或私有的,因此不能从外部设置设置器或属性。
处理无效或缺失数据
在开发过程中,API经常会发生变化。为了通知此类更改,可以配置JsonMapper在数据缺失或尚未知的情况下抛出异常。
未知属性
当JsonMapper看到JSON数据中定义的PHP类中未定义的属性时,您可以通过设置$bExceptionOnUndefinedProperty
让它抛出异常。
$jm = new JsonMapper(); $jm->bExceptionOnUndefinedProperty = true; $jm->map(...);
您还可以通过将callable设置到$undefinedPropertyHandler
来自定义处理这些属性。
/** * Handle undefined properties during JsonMapper::map() * * @param object $object Object that is being filled * @param string $propName Name of the unknown JSON property * @param mixed $jsonValue JSON value of the property * * @return void */ function setUndefinedProperty($object, $propName, $jsonValue) { $object->{'UNDEF' . $propName} = $jsonValue; } $jm = new JsonMapper(); $jm->undefinedPropertyHandler = 'setUndefinedProperty'; $jm->map(...);
或者,如果您希望JsonMapper为您处理设置器,您可以从$undefinedPropertyHandler
返回一个字符串,该字符串将用作属性名。
/** * Handle undefined properties during JsonMapper::map() * * @param object $object Object that is being filled * @param string $propName Name of the unknown JSON property * @param mixed $jsonValue JSON value of the property * * @return void */ function fixPropName($object, $propName, $jsonValue) { return ucfirst($propName); } $jm = new JsonMapper(); $jm->undefinedPropertyHandler = 'fixPropName'; $jm->map(...);
缺失属性
注意
这仅在$bStrictObjectTypeChecking保持启用时有效。
您可以通过在它们的docblock中放置@required
来将PHP类中的属性标记为“必需”。
/** * @var string * @required */ public $someDatum;
如果JSON数据不包含此属性,并且激活了$bExceptionOnMissingData
,JsonMapper将在出现JsonMapper_Exception
时抛出异常。
$jm = new JsonMapper(); $jm->bExceptionOnMissingData = true; $jm->map(...);
选项$bRemoveUndefinedAttributes
会导致JsonMapper在最终对象中删除不在JSON数据中的属性。
$jm = new JsonMapper(); $jm->bRemoveUndefinedAttributes = true; $jm->map(...);
私有属性和函数
您可以通过将$bIgnoreVisibility
设置为true来允许将映射到私有和受保护的属性和设置器方法。
$jm = new JsonMapper(); $jm->bIgnoreVisibility = true; $jm->map(...);
简单类型而不是对象
当变量的类型是类且JSON数据是简单类型(如string
)时,如果配置为这样做,JsonMapper可以将此值传递给类的构造函数。
$jm = new JsonMapper(); $jm->bStrictObjectTypeChecking = false; $jm->map(...);
这可以用于从日期字符串自动初始化DateTime对象。
虽然禁用这种严格对象类型检查可能会导致问题。
- 当类没有构造函数或没有构造函数参数时,值将会丢失。
- 当构造函数有多个必需参数时,它将崩溃。
- 当构造函数的参数类型与JSON中的数据类型不匹配时,它将崩溃。
@required
属性将不会被填充。
注意
从版本5开始,默认值从false
更改为true
,以提高安全性。
现在,如果您想将简单类型传递给类构造函数,您必须选择启用。
传递数组到 map()
您可能希望将通过调用得到的数组数据传递给map()
。
json_decode($jsonString, true)
默认情况下,JsonMapper会抛出异常,因为map()
需要对象作为第一个参数。您可以通过将$bEnforceMapType
设置为false
来规避这一点。
$jm = new JsonMapper(); $jm->bEnforceMapType = false; $jm->map(...);
映射后回调
JsonMapper能够在映射完成后直接调用每个对象的自定义方法。
$jm = new JsonMapper(); $jm->postMappingMethod = 'afterMapping'; $jm->map(...);
现在,对于每个映射的对象(如果类具有该方法),都会调用afterMapping()
。
您可以向后映射回调传递额外的参数。
$jm = new JsonMapper(); $jm->postMappingMethod = 'afterMapping'; $jm->postMappingMethodArguments = [23, 'foo']; $jm->map(...);
安装
通过Packagist使用Composer。
$ composer require netresearch/jsonmapper
相关软件
替代方案
- Java的Jackson的数据绑定。
- PHP的Johannes Schmitt序列化器。
- PHP的metassione。
- PHP的Cartographer。
- PHP的数据传输对象。
- PHP的Valinor。
- 一个同名的具有依赖关系的 JsonMapper 库。
关于 JsonMapper
许可证
JsonMapper 采用 OSL 3.0 许可协议。
编码风格
JsonMapper 遵循 PEAR 编码标准。