获取从 JSON Web 服务检索的数据并将其转换为嵌套对象和数组 - 使用您自己的模型类。
从基本对象开始,它将 JSON 数据映射到类属性上,将它们转换为正确的简单类型或对象。
它有点像 PHP 的SoapClient
为您提供的本机 SOAP 参数映射,但针对的是 JSON。它不依赖于任何模式,只依赖于 PHP 类定义。
类型检测通过解析类属性的类型声明和@var
docblock 注释以及 setter 方法中的类型提示来工作。
您不必通过添加 JSON 特定代码来修改模型类;它通过解析已经存在的文档块来自动工作。
该库没有依赖项。
关键词:反序列化、水化
内容
map()
模型类需要手写
由于JsonMapper不依赖于任何模式信息(例如来自json-schema),因此无法自动生成模型类。
netresearch/jsonmapper
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
类。
来自地址簿 Web 服务的 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
使用多个源按以下顺序检测属性的正确类型:
Setter 方法 ( set
+ ucwords($propertyname)
)
下划线“ _
”和连字符“ -
”使下一个字母大写。属性foo_bar-baz
导致 setter 方法setFooBarBaz
。
如果方法签名中有类型提示,则使用其类型:
公共函数 setPerson(联系人 $person) {...}
检查该方法的文档块是否有@param $type
注释:
/** * @param Contact $person 此应用程序的主要联系人 */ 公共函数 setPerson($person) {...}
如果无法检测到类型,则将纯 JSON 值传递给 setter 方法。
类属性类型(自 PHP 7.4 起):
公共联系人$人;
构造函数属性提升类型(自 PHP 8.0 起):
公共函数 __construct(受保护的联系人 $person) {}
类属性的@var $type
docblock注释:
/** * @var myapplicationmodelContact */ 公共$人;
该财产必须是公共的才能直接使用。您还可以使用 $bIgnoreVisibility 来利用受保护的私有属性。
如果无法检测到类型,则该属性将获取纯 JSON 值集。
如果找不到属性,JsonMapper 会尝试以不区分大小写的方式查找该属性。然后,JSON 属性isempty
将映射到 PHP 属性isEmpty
。
笔记
您必须提供完全限定的命名空间才能使类型正常工作。相对类名在当前类命名空间的上下文中进行评估,而不考虑可能存在的任何导入。
PHP 不通过反射提供导入;注释文本仅包含类型的文字文本。出于性能原因,JsonMapper 不会自行解析源代码来检测和扩展任何导入。
简单类型
string
bool
, boolean
int
, integer
double
float
array
object
mixed
类名,带命名空间和不带命名空间
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
类型的对象ArrayObject 和扩展类被视为数组。
无类型或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 (...);
当变量定义为Foo
类型时,这将创建Bar
类型的对象。
如果需要动态确定实际的实现类(例如在联合的情况下),也可以使用可调用对象。映射的类(下面示例中的“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 (...);
当 JSON 属性为null
时,JsonMapper 会引发异常,除非 PHP 类属性具有可为 null 的类型 - 例如Contact|null
或?Contact
。
如果您的 API 包含许多可能为null
字段,并且您不希望所有类型定义都可为空,请设置:
$ jm -> bStrictNullTypes = false ;
从版本 5.0.0 开始,数组中的null
值会导致JsonMapper_Exception
,除非类型可为 null - 例如array[?string]
或array[string|null]
。
要恢复以前的行为(即使没有声明也允许空值)设置:
$ jm -> bStrictNullTypesInArrays = false ;
JsonMapper 的setLogger()
方法支持所有 PSR-3 兼容的记录器实例。
记录的事件:
在开发过程中,API 经常发生变化。为了获得有关此类更改的通知,可以将 JsonMapper 配置为在数据丢失或未知的情况下抛出异常。
当 JsonMapper 看到 JSON 数据中未在 PHP 类中定义的属性时,可以通过设置$bExceptionOnUndefinedProperty
让它抛出异常:
$ jm = new JsonMapper ();
$ jm -> bExceptionOnUndefinedProperty = true ;
$ jm -> map (...);
您还可以选择通过将可调用设置为$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 为您处理 setter,您可以从$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 保持启用状态时才有效。
PHP 类中的属性可以通过将@required
放入其文档块中来标记为“必需”:
/**
* @var string
* @required
*/
public $ someDatum ;
当 JSON 数据不包含此属性时,JsonMapper 将在激活$bExceptionOnMissingData
时抛出JsonMapper_Exception
:
$ jm = new JsonMapper ();
$ jm -> bExceptionOnMissingData = true ;
$ jm -> map (...);
选项$bRemoveUndefinedAttributes
会导致 JsonMapper 从最终对象中删除属性(如果它们不在 JSON 数据中):
$ jm = new JsonMapper ();
$ jm -> bRemoveUndefinedAttributes = true ;
$ jm -> map (...);
您可以通过将$bIgnoreVisibility
设置为 true 来允许映射到私有和受保护的属性和 setter 方法:
$ jm = new JsonMapper ();
$ jm -> bIgnoreVisibility = true ;
$ jm -> map (...);
当变量的类型是类并且 JSON 数据是简单类型(如string
时,JsonMapper 可以在配置时将此值传递给类的构造函数:
$ jm = new JsonMapper ();
$ jm -> bStrictObjectTypeChecking = false ;
$ jm -> map (...);
这可用于从日期字符串自动初始化 DateTime 对象。
不过,禁用这种严格的对象类型检查可能会导致问题:
@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:
$ 作曲家需要 netresearch/jsonmapper
替代方案
JsonMapper 根据 OSL 3.0 获得许可。
JsonMapper 遵循 PEAR 编码标准。
克里斯蒂安·韦斯克 (Christian Weiske),cweiske.de