apimatic/jsonmapper

将嵌套的 JSON 结构映射到 PHP 类

3.1.4 2024-06-11 11:48 UTC

README

https://img.shields.io/packagist/v/apimatic/jsonmapper.svg?style=flat https://img.shields.io/packagist/dm/apimatic/jsonmapper.svg?style=flat https://img.shields.io/packagist/l/apimatic/jsonmapper.svg?style=flat

从 JSON 网络服务获取数据,并将其转换为嵌套对象和数组 - 使用您自己的模型类。

从基础对象开始,它将 JSON 数据映射到类属性,将它们转换为正确的基本类型或对象。

它有点像 PHP 的 SoapClient 提供的本地 SOAP 参数映射,但用于 JSON。注意,它不依赖于任何模式,只依赖于您的类定义。

类型检测通过解析类属性的 @var 文档注释以及设置方法中的类型提示来实现。如果通过一些配置设置(如 opcache.save_comments=0)或任何其他类似配置丢弃了文档注释或一般注释,将抛出异常,阻止任何进一步的操作。

您不需要通过添加 JSON 特定代码来修改您的模型类;它通过解析已存在的文档注释自动工作。

关键词:反序列化,数据填充

内容

优缺点

优点

  • IDE 中的自动完成
  • 很容易向数据模型类添加便捷方法
  • 您的 JSON API 可能会更改,但您的模型可以保持不变 - 不会破坏使用模型类的应用程序。

缺点

  • 模型类需要手动编写

    由于 JsonMapper 不依赖于任何模式信息(例如来自 json-schema),模型类不能自动生成。

使用方法

基本用法

  1. 注册一个可以加载 PSR-0 兼容类的自动加载器。
  2. 创建一个 JsonMapper 对象实例
  3. 根据您的数据调用 mapmapArray 方法

映射一个普通对象

<?php
require 'autoload.php';
$mapper = new JsonMapper();
$contactObject = $mapper->map($jsonContact, new Contact());
?>

映射对象数组

<?php
require 'autoload.php';
$mapper = new JsonMapper();
$contactsArray = $mapper->mapArray(
    $jsonContacts, new ArrayObject(), 'Contact'
);
?>

示例

来自地址簿网络服务的 JSON

{
    'name':'Sheldon Cooper',
    'address': {
        'street': '2311 N. Los Robles Avenue',
        'city': 'Pasadena'
    }
}

您本地的 Contact

<?php
class Contact
{
    /**
     * Full name
     * @var string
     */
    public $name;

    /**
     * @var Address
     */
    public $address;
}
?>

您本地的 Address

<?php
class Address
{
    public $street;
    public $city;

    public function getGeoCoords()
    {
        //do something with the $street and $city
    }
}
?>

您的应用程序代码

<?php
$json = json_decode(file_get_contents('http://example.org/bigbang.json'));
$mapper = new JsonMapper();
$contact = $mapper->map($json, new Contact());

echo "Geo coordinates for " . $contact->name . ": "
    . var_export($contact->address->getGeoCoords(), true);
?>

让 JsonMapper 为您创建实例

映射一个普通对象(与 map 工作方式类似)

$mapper = new JsonMapper();
$contactObject = $mapper->mapClass($jsonContact, 'Contact');

映射对象数组(与 mapArray 工作方式类似)

$mapper = new JsonMapper();
$contactsArray = $mapper->mapClassArray($jsonContacts, 'Contact');

以任何类型组合映射值,例如 oneOf(string,int) 或 anyOf(string,Contact)

$mapper = new JsonMapper();
$contactObject = $mapper->mapFor($value, 'oneOf(string,Contact)');

属性类型文档

JsonMapper 使用多个来源来检测属性的正确类型

  1. 检查设置方法(set + ucwords($propertyname))。

    下划线使下一个字母大写,这意味着对于 JSON 属性 foo_bar_baz,使用 setFooBarBaz 的设置方法。

    1. 如果方法签名中具有类型提示,则使用此类型。

      public function setPerson(Contact $person) {...}
      
    2. 检查方法的文档注释以查找 @param $type 注释。

      /**
       * @param Contact $person Main contact for this application
       */
      public function setPerson($person) {...}
      
    3. 如果无法检测到类型,则将普通 JSON 值传递给设置方法。

  2. 类属性的 @var $type 文档注释

    /**
     * @var \my\application\model\Contact
     */
    public $person;
    

    请注意,属性必须是公共的才能直接使用。

    如果无法检测到类型,则属性将获取普通 JSON 值。

    如果找不到属性,JsonMapper会尝试以不区分大小写的方式查找属性。一个JSON属性isempty将被映射到PHP属性isEmpty

要映射JSON键到一个任意命名的类属性,您可以使用@maps注解

/**
 * @var \my\application\model\Person
 * @maps person_object
 */
public $person;

支持的类型名称

  • 简单类型
    • string
    • boolboolean
    • intinteger
    • float
    • array
    • object
  • 类名称,包括和不包括命名空间
  • 简单类型和类名称的数组
    • int[]
    • Contact[]
  • 简单类型和类名称的ArrayObjects
    • ContactList[Contact]
    • NumberList[int]
  • 可空类型
    • int|null - 如果JSON中的值是null,则为null,否则为整数

ArrayObjects和扩展类被视为数组。

没有类型或类型为mixed的变量将直接设置JSON值,而不进行任何转换。

有关更多信息,请参阅phpdoc的类型文档

简单类型映射

当需要创建对象但JSON只包含简单类型(例如字符串、浮点数、布尔值)时,此值将被传递到类的构造函数中。示例

PHP代码

/**
 * @var DateTime
 */
public $date;

JSON

{"date":"2014-05-15"}

这将导致调用new DateTime('2014-05-15')

自定义属性初始化

您可以使用@factory注解来指定一个自定义方法,该方法将用于获取分配给属性的值。

/**
 * @factory MyUtilityClass::createDate
 */
public $date;

在此,MyUtilityClass中的createDate方法使用date属性的原始值和工厂方法返回的值调用。

当使用is_callable测试时,工厂方法应该返回true,否则将抛出异常。

工厂注解可以与其他注解(如@var)一起使用;然而,只有工厂方法创建的值将被使用,而其他属性的类型提示和初始化方法将被忽略。

日志记录

JsonMapper的setLogger()方法支持所有PSR-3兼容的日志记录实例。

被记录的事件

  • JSON数据包含一个键,但类没有为该键定义属性或setter方法。
  • 由于它们是受保护的或私有的,因此既不能从外部设置setter,也不能设置属性

处理无效或缺失数据

在开发过程中,API经常更改。为了通知此类更改,JsonMapper可能会在数据缺失或尚未知的情况下抛出异常。

未知属性

当JsonMapper看到JSON数据中的属性未在PHP类中定义时,您可以通过设置$bExceptionOnUndefinedProperty来让它抛出异常

$jm = new JsonMapper();
$jm->bExceptionOnUndefinedProperty = true;
$jm->map(...);

要自己处理未知属性,您可以在类上设置一个方法作为收集方法

$jm = new JsonMapper();
$mapper->sAdditionalPropertiesCollectionMethod = 'addAdditionalProperty';
$jm->map(...);

在此,将使用namevalue参数调用addAdditionalProperty()方法。

缺失属性

您可以在PHP类的属性的docblock中放置@required来标记属性为“必需”

/**
 * @var string
 * @required
 */
public $someDatum;

当JSON数据不包含此属性时,如果激活了$bExceptionOnMissingData,JsonMapper将抛出异常

$jm = new JsonMapper();
$jm->bExceptionOnMissingData = true;
$jm->map(...);

将数组传递给 map()

您可能希望将您通过调用得到的数组数据传递给map()

json_decode($jsonString, true)

默认情况下,由于map()需要对象作为第一个参数,JsonMapper将抛出异常。您可以通过设置$bEnforceMapTypefalse来绕过这一点

$jm = new JsonMapper();
$jm->bEnforceMapType = false;
$jm->map(...);

处理多态响应

JsonMapper允许您根据区分字段将JSON对象映射到派生类。区分字段的值用于决定此JSON对象应映射到哪个类。

您本地的Person

<?php
/**
 * @discriminator type
 * @discriminatorType person
 */
class Person
{
    public $name;
    public $age;
    public $type;
}

您本地的Employee

<?php
/**
 * @discriminator type
 * @discriminatorType employee
 */
class Employee extends Person
{
    public $employeeId;
}

您的应用程序代码

$mapper = new JsonMapper();
$mapper->arChildClasses['Person'] = ['Employee'];
$mapper->arChildClasses['Employee'] = [];
$person = $mapper->mapClass($json, 'Person');

现在,如果JSON中type键的值是"person",则返回Person类的实例。然而,如果type"employee",则返回Employee类的实例。

在使用区分符之前,类必须在 arChildClasses 中注册。

注意,在对象层次结构中只能有一个区分符字段。

如果多态类作为字段或数组嵌入,则多态响应也可以工作。

要映射类数组,请使用 mapArrayClass,它将通过检查 discriminatorType 值来创建正确的类型对象。

安装

支持的 PHP 版本

  • PHP 5.6
  • PHP 7.0
  • PHP 7.1
  • PHP 7.2
  • PHP 7.4
  • PHP 8.0
  • PHP 8.1
  • PHP 8.2

安装软件包

来源:Packagist

$ composer require apimatic/jsonmapper

相关软件

关于 JsonMapper

许可证

JsonMapper 采用 OSL 3.0 许可。

编码风格

JsonMapper 遵循 PEAR 编码标准

作者

Christian WeiskeNetresearch GmbH & Co KG