hitrain/jsonmapper

将嵌套JSON结构映射到PHP类

v1.3.0 2017-08-14 07:26 UTC

README

https://api.travis-ci.org/cweiske/jsonmapper.png

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

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

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

类型检测通过解析类属性的@var docblock注释以及setter方法中的类型提示来完成。

您不需要通过添加JSON特定代码来修改模型类;它通过解析现有的docblocks自动工作。

关键词:反序列化,活化

内容

利与弊

优点

  • 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, array(), 'Contact'
);
?>

除了array()之外,您还可以使用ArrayObject及其派生类。

示例

来自地址簿网络服务的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 $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使用多个来源来检测属性的正确类型

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

    下划线"_"和连字符"-"将下一个字母转换为大写。属性foo_bar-baz将导致setter方法setFooBarBaz

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

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

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

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

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

    属性必须是公共的才能直接使用。受保护和私有的属性不能设置;您必须为它们提供setter方法。

    如果无法检测到类型,则将属性设置为纯JSON值。

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

支持的类型名称

  • 简单类型
    • 字符串
    • boolboolean
    • intinteger
    • doublefloat
    • 数组
    • 对象
  • 类名,带和不带命名空间
    • Contact - 如果 JSON 值为 null,则将抛出异常
  • 简单类型和类名的数组
    • int[]
    • Contact[]
  • 多维数组
    • int[][]
    • TreeDeePixel[][][]
  • 简单类型和类名的 ArrayObjects
    • ContactList[Contact]
    • NumberList[int]
  • 可空类型
    • int|null - 如果 JSON 中的值为 null,则将是 null,否则将是一个整数
    • Contact|null - 如果 JSON 中的值为 null,则将是 null,否则将是一个 Contact 类型的对象

ArrayObjects 和扩展类被视为数组。

没有类型或类型为 mixed 的变量将直接设置 JSON 值,无需任何转换。

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

不同的属性名

当需要将 JSON 中的不同属性名映射到本地类时

您的本地Contact

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

    /**
     * define mapping rule with assoc array
     * @return array
     */
    public function mappingRule()
    {
       return [
           'jsonName' => 'name',
           ];
   }
}
?>

PHP 代码

$jm = new JsonMapper();
$jm->bUseMappingRule = true;
$contact->map($json, new Contact());

获取嵌套属性

获取嵌套属性到根对象属性

您的本地Contact

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

    /**
     * define mapping rule with assoc array
     * @return array
     */
    public function mappingRule()
    {
       return [
           'jsonObject.nestedJsonObject.jsonName' => 'name',
           ];
   }
}
?>

PHP 代码

$jm = new JsonMapper();
$jm->bUseMappingRule = true;
$contact->map($json, new Contact());

简单类型映射

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

PHP 代码

/**
 * @var DateTime
 */
public $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 时。

可空

JsonMapper 在 JSON 属性为 null 时抛出异常,除非 PHP 类属性具有可空类型 - 例如 Contact|null

如果您的 API 包含许多可能为 null 的字段,并且您不希望将所有类型定义都设置为可空,请设置

$jm->bStrictNullTypes = 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(...);

缺失属性

您可以通过在它们的 docblock 中放置 @required 来将 PHP 类中的属性标记为 "必需的"

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

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

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

私有属性和函数

您可以通过将 $bIgnoreVisibility 设置为 true 允许映射到私有和受保护的属性以及设置方法

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

简单类型而非对象

当变量的类型是类且 JSON 数据是简单类型(如 string)时,JsonMapper 将此值传递给类的构造函数。

如果您不希望这样做,请将 $bStrictObjectTypeChecking 设置为 true

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

在这种情况下将抛出异常。

map()传递数组

您可能希望将调用获取的数组数据传递到 map()

json_decode($jsonString, true)

默认情况下,JsonMapper会抛出异常,因为map()需要一个对象作为第一个参数。您可以通过将$bEnforceMapType设置为false来绕过这个问题。

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

安装

通过Composer

来自Packagist

$ composer require netresearch/jsonmapper

通过PEAR

注意:

从版本1.0.0开始,JsonMapper迁移到了PEAR频道https://zustellzentrum.cweiske.de/

来自我们的PEAR频道

$ pear channel-discover zustellzentrum.cweiske.de
$ pear install zz/jsonmapper

相关软件

关于JsonMapper

许可

JsonMapper遵循OSL 3.0许可证。

编码风格

JsonMapper遵循PEAR编码标准

作者

Christian Weiskecweiske.de