Skip to content

Instantly share code, notes, and snippets.

@jenschude
Created June 7, 2019 09:04
Show Gist options
  • Save jenschude/87895b4b71ac71609d59d0f0bcba14d3 to your computer and use it in GitHub Desktop.
Save jenschude/87895b4b71ac71609d59d0f0bcba14d3 to your computer and use it in GitHub Desktop.
JsonReader
<?php
require __DIR__ . '/../vendor/autoload.php';
use Doctrine\Common\Annotations\AnnotationRegistry;
use JMS\Serializer\Annotation as Serializer;
use JMS\Serializer\Annotation\Type;
use JMS\Serializer\SerializerBuilder;
use pcrov\JsonReader\JsonReader;
AnnotationRegistry::registerLoader('class_exists');
$json = <<<'JSON'
{
"type": "donut",
"name": "Cake",
"test": {
"type": "donut",
"name": "Cake"
},
"toppings": [
{ "id": 5002, "type": "Glazed" },
{ "id": 5006, "type": "Chocolate with Sprinkles" },
{ "id": 5004, "type": "Maple" }
]
}
JSON;
class Toppings {
/**
* @Type("int")
*/
private $id;
/**
* @Type("string")
*/
private $type;
/**
* @param mixed $id
*/
public function setId($id)
{
$this->id = $id;
}
/**
* @param mixed $type
*/
public function setType($type)
{
$this->type = $type;
}
}
class Donut {
/**
* @Type("string")
*/
private $type;
/**
* @Type("string")
*/
private $name;
/**
* @Type("Toppings")
*/
private $toppings;
/**
* @Type("Donut")
*/
private $test;
/**
* @param mixed $test
*/
public function setTest($test)
{
$this->test = $test;
}
public function setType($type)
{
$this->type = $type;
}
/**
* @param mixed $name
*/
public function setName($name)
{
$this->name = $name;
}
/**
* @param mixed $toppings
*/
public function setToppings($toppings)
{
$this->toppings = $toppings;
}
}
$reader = new JsonReader();
$reader->json($json);
$map = [
Donut::class => [
'properties' => [
'toppings' => Toppings::class,
'test' => Donut::class
]
]
];
$mapper = new ObjectMapper($map);
$start = microtime(true);
$result = $mapper->map($json, Donut::class);
var_dump((microtime(true) - $start) * 1000);
$start = microtime(true);
$result = json_decode($json);
var_dump((microtime(true) - $start) * 1000);
$serializer = SerializerBuilder::create()
->addMetadataDir(__DIR__)
->setCacheDir(__DIR__)
->build();
$start = microtime(true);
$object = $serializer->deserialize($json, Donut::class, 'json');
var_dump((microtime(true) - $start) * 1000);
var_dump($result);
class ObjectMapper {
private $typeMap;
/**
* ObjectMapper constructor.
* @param $typeMap
*/
public function __construct($typeMap)
{
$this->typeMap = $typeMap;
}
public function map($data, $type) {
$reader = new JsonReader();
$reader->json($data);
return $this->read($reader, $type);
}
private function read(JsonReader $reader, $type) {
$result = null;
while($reader->read()) {
switch ($reader->type()) {
case JsonReader::BOOL:
case JsonReader::NUMBER:
case JsonReader::STRING:
return $reader->value();
case JsonReader::OBJECT:
$result = new $type;
return $this->readProperties($reader, $type, $result);
case JsonReader::END_OBJECT:
return $result;
case JsonReader::ARRAY:
return $this->readItems($reader, $type);
break;
case JsonReader::END_ARRAY:
return $result;
}
}
}
private function readProperties(JsonReader $reader, $type, $result) {
while ($reader->read()) {
switch ($reader->type()) {
case JsonReader::BOOL:
case JsonReader::NUMBER:
case JsonReader::STRING:
$method = 'set' . ucfirst($reader->name());
$result->$method($reader->value());
break;
case JsonReader::OBJECT:
$name = $reader->name();
if (isset($this->typeMap[$type]['properties'][$name])) {
$propertyType = $this->typeMap[$type]['properties'][$name];
}
$method = 'set' . ucfirst($reader->name());
$object = new $propertyType;
$result->$method($this->readProperties($reader, $propertyType, $object));
break;
case JsonReader::END_OBJECT:
return $result;
case JsonReader::ARRAY:
$name = $reader->name();
if (isset($this->typeMap[$type]['properties'][$name])) {
$type = $this->typeMap[$type]['properties'][$name];
}
$method = 'set' . ucfirst($reader->name());
$items = $this->readItems($reader, $type);
$result->$method($items);
break;
case JsonReader::END_ARRAY:
break;
}
}
}
private function readItems(JsonReader $reader, $type) {
$result = [];
while ($reader->read()) {
switch ($reader->type()) {
case JsonReader::BOOL:
case JsonReader::NUMBER:
case JsonReader::STRING:
$result[] = $reader->value();
break;
case JsonReader::OBJECT:
$object = new $type;
$result[] = $this->readProperties($reader, $type, $object);
break;
case JsonReader::END_OBJECT:
break;
case JsonReader::ARRAY:
$result[] = $this->read($reader, $type);
break;
case JsonReader::END_ARRAY:
return $result;
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment