-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathJSONReference.php
108 lines (95 loc) · 3.64 KB
/
JSONReference.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
<?php
/**
* @author Steffen Maechtel <info@steffen-maechtel.de>
* @copyright 2015 Steffen Maechtel
* @license MIT
*/
class JSONReference {
/**
* @param mixed $data
* @return \stdClass {root: ..., objects: ...}
*/
public static function encode($data) {
$objects = new \stdClass();
$root = self::extractObjectsAndReplaceWithHashRecursive($data, $objects);
return (object) array('root' => $root, 'objects' => $objects);
}
/**
* @param \stdClass $data
* @return mixed
* @throws \InvalidArgumentException
*/
public static function decode($data) {
if (($data instanceof \stdClass) === false) {
throw new \InvalidArgumentException('Parameter data is not an instance of stdClass');
}
if (property_exists($data, 'root') === false) {
throw new \InvalidArgumentException('Parameter data has no property root');
}
if (property_exists($data, 'objects') === false) {
throw new \InvalidArgumentException('Parameter data has no property objects');
}
if (is_array($data->objects) && count($data->objects) > 0) {
throw new \InvalidArgumentException('Parameter data->objects has items, but is not an instance of stdClass');
}
return self::replaceHashWithObjectsRecursive($data->root, clone $data->objects);
}
/**
* @param mixed $data
* @param \stdClass $objects
* @param array $reached
* @return string
*/
protected static function extractObjectsAndReplaceWithHashRecursive($data, $objects, & $reached = array()) {
switch (true) {
case is_array($data):
foreach ($data as $key => $value) {
$data[$key] = self::extractObjectsAndReplaceWithHashRecursive($value, $objects, $reached);
}
return $data;
case is_object($data):
$hash = '@' . spl_object_hash($data);
if (in_array($hash, $reached) === false) {
$reached[] = $hash;
$object = new stdClass();
foreach ($data as $property => $value) {
$object->$property = self::extractObjectsAndReplaceWithHashRecursive($value, $objects, $reached);
}
$objects->$hash = $object;
}
return $hash;
default:
return $data;
}
}
/**
*
* @param mixed $data
* @param \stdClass $objects
* @param array $reached
* @return mixed
* @throws \Exception
*/
protected static function replaceHashWithObjectsRecursive($data, $objects, & $reached = array()) {
switch (true) {
case is_array($data):
foreach ($data as $key => $value) {
$data[$key] = self::replaceHashWithObjectsRecursive($value, $objects, $reached);
}
return $data;
case is_string($data) === true && $data[0] === '@':
if (property_exists($objects, $data) === false) {
throw new \Exception('Object with hash "' . $data . '" does not exists in objects');
}
if (in_array($data, $reached) === false) {
$reached[] = $data;
foreach ($objects->$data as $property => $value) {
$objects->$data->$property = self::replaceHashWithObjectsRecursive($value, $objects, $reached);
}
}
return $objects->$data;
default:
return $data;
}
}
}