Принимает данные, полученные из веб-службы JSON, и преобразует их во вложенные объекты и массивы, используя ваши собственные классы модели.
Начиная с базового объекта, он сопоставляет данные JSON со свойствами класса, преобразуя их в правильные простые типы или объекты.
Это немного похоже на встроенное сопоставление параметров SOAP, которое предоставляет PHP SoapClient
, но для JSON. Он не опирается ни на какую схему, а только на определения классов PHP.
Обнаружение типов работает путем анализа объявлений типов и аннотаций @var
docblock свойств класса, а также подсказок типов в методах установки.
Вам не нужно изменять классы моделей, добавляя специальный код JSON; он работает автоматически, анализируя уже существующие докблоки.
Эта библиотека не имеет зависимостей.
Ключевые слова: десериализация, гидратация.
Содержание
map()
Классы моделей необходимо писать вручную.
Поскольку JsonMapper не полагается на какую-либо информацию о схеме (например, из json-схемы), классы модели не могут генерироваться автоматически.
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
.
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
.
Если в сигнатуре метода есть подсказка типа, то используется его тип:
публичная функция setPerson(Contact $person) {...}
Документационный блок метода проверяется на наличие аннотаций @param $type
:
/** * @param Контактное лицо $person Основное контактное лицо для этого приложения */ публичная функция setPerson($person) {...}
Если тип не обнаружен, методу установки передается простое значение JSON.
Типы свойств класса (начиная с PHP 7.4):
общедоступный контакт $person;
Типы продвижения свойств конструктора (начиная с PHP 8.0):
публичная функция __construct(protected Contact $person) {}
@var $type
аннотация docblock свойств класса:
/** * @var myapplicationmodelContact */ публичный $человек;
Недвижимость должна быть общедоступной, чтобы ее можно было использовать напрямую. Вы также можете использовать $bIgnoreVisibility для использования защищенных и частных свойств.
Если тип не обнаружен, свойство получает набор простых значений JSON.
Если свойство не может быть найдено, JsonMapper пытается найти его без учета регистра. Свойство JSON isempty
затем будет сопоставлено со свойством PHP isEmpty
.
Примечание
Для работы типа необходимо предоставить полное пространство имен. Относительные имена классов оцениваются в контексте текущего пространства имен классов, НЕ учитывая какой-либо импорт, который может присутствовать.
PHP не обеспечивает импорт через Reflection; текст комментария содержит только буквальный текст типа. По соображениям производительности 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
— будет иметь null
, если значение в JSON равно null
, в противном случае оно будет целым числом.Contact|null
или ?Contact
— будет иметь null
, если значение в JSON равно null
, в противном случае это будет объект типа Contact
Объекты ArrayObject и расширяющие классы рассматриваются как массивы.
Переменные без типа или со mixed
типом получат значение JSON, установленное напрямую, без какого-либо преобразования.
Дополнительную информацию смотрите в документации по типам phpdoc.
Примечание
Эта функция отключена по умолчанию по соображениям безопасности, начиная с версии 5. Подробности см. в разделе $bStrictObjectTypeChecking.
Если объект должен быть создан, но JSON содержит только простой тип (например, строка, число с плавающей запятой, логическое значение), это значение передается конструктору классов. Пример:
PHP-код:
public DateTime $ date ;
JSON:
{ "date" : "2014-05-15" }
Это приведет к вызову new DateTime('2014-05-15')
.
Когда переменные определяются как объекты абстрактных классов или интерфейсов, JsonMapper обычно пытается создать их экземпляры напрямую и приводит к сбою.
Используя свойство $classMap
JsonMapper, вы можете указать, какие классы будут создаваться вместо этого:
$ 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 (...);
JsonMapper выдает исключение, когда свойство JSON имеет значение null
, если только свойство класса PHP не имеет типа, допускающего значение NULL, например Contact|null
или ?Contact
.
Если ваш API содержит много полей, которые могут иметь значение null
, и вы не хотите, чтобы все определения типов были обнуляемыми, установите:
$ jm -> bStrictNullTypes = false ;
Начиная с версии 5.0.0, значения null
в массивах приводят к JsonMapper_Exception
, если только тип не допускает значения NULL — например, array[?string]
или array[string|null]
.
Чтобы вернуть предыдущее поведение (допуская значения NULL, даже если они не объявлены так), установите:
$ jm -> bStrictNullTypesInArrays = false ;
Метод setLogger()
JsonMapper поддерживает все экземпляры регистраторов, совместимые с 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 обрабатывать установщик за вас, вы можете вернуть строку из $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 выдаст исключение JsonMapper_Exception
при активации $bExceptionOnMissingData
:
$ 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 из строк даты.
Однако отключение этой строгой проверки типа объекта может привести к проблемам:
@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 (...);
Через Composer от Packagist:
$ композитор требует netresearch/jsonmapper
Альтернативы
JsonMapper распространяется под лицензией OSL 3.0.
JsonMapper соответствует стандартам кодирования PEAR.
Кристиан Вайске, cweiske.de