1 | <?php
|
---|
2 |
|
---|
3 | /*!
|
---|
4 | * ISC License
|
---|
5 | *
|
---|
6 | * Copyright (c) 2018-2021, Andrea Giammarchi, @WebReflection
|
---|
7 | *
|
---|
8 | * Permission to use, copy, modify, and/or distribute this software for any
|
---|
9 | * purpose with or without fee is hereby granted, provided that the above
|
---|
10 | * copyright notice and this permission notice appear in all copies.
|
---|
11 | *
|
---|
12 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
---|
13 | * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
---|
14 | * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
---|
15 | * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
---|
16 | * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
|
---|
17 | * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
---|
18 | * PERFORMANCE OF THIS SOFTWARE.
|
---|
19 | */
|
---|
20 |
|
---|
21 | class FlattedString {
|
---|
22 | public $value = '';
|
---|
23 | public function __construct($value) {
|
---|
24 | $this->value = $value;
|
---|
25 | }
|
---|
26 | }
|
---|
27 |
|
---|
28 | class Flatted {
|
---|
29 |
|
---|
30 | // public utilities
|
---|
31 | public static function parse($json, $assoc = false, $depth = 512, $options = 0) {
|
---|
32 | $input = array_map(
|
---|
33 | 'Flatted::asString',
|
---|
34 | array_map(
|
---|
35 | 'Flatted::wrap',
|
---|
36 | json_decode($json, $assoc, $depth, $options)
|
---|
37 | )
|
---|
38 | );
|
---|
39 | $value = &$input[0];
|
---|
40 | $set = array();
|
---|
41 | $set[] = &$value;
|
---|
42 | if (is_array($value))
|
---|
43 | return Flatted::loop(false, array_keys($value), $input, $set, $value);
|
---|
44 | if (is_object($value))
|
---|
45 | return Flatted::loop(true, Flatted::keys($value), $input, $set, $value);
|
---|
46 | return $value;
|
---|
47 | }
|
---|
48 |
|
---|
49 | public static function stringify($value, $options = 0, $depth = 512) {
|
---|
50 | $known = new stdClass;
|
---|
51 | $known->key = array();
|
---|
52 | $known->value = array();
|
---|
53 | $input = array();
|
---|
54 | $output = array();
|
---|
55 | $i = intval(Flatted::index($known, $input, $value));
|
---|
56 | while ($i < count($input)) {
|
---|
57 | $output[$i] = Flatted::transform($known, $input, $input[$i]);
|
---|
58 | $i++;
|
---|
59 | }
|
---|
60 | return json_encode($output, $options, $depth);
|
---|
61 | }
|
---|
62 |
|
---|
63 | // private helpers
|
---|
64 | private static function asString($value) {
|
---|
65 | return $value instanceof FlattedString ? $value->value : $value;
|
---|
66 | }
|
---|
67 |
|
---|
68 | private static function index(&$known, &$input, &$value) {
|
---|
69 | $input[] = &$value;
|
---|
70 | $index = strval(count($input) - 1);
|
---|
71 | $known->key[] = &$value;
|
---|
72 | $known->value[] = &$index;
|
---|
73 | return $index;
|
---|
74 | }
|
---|
75 |
|
---|
76 | private static function keys(&$value) {
|
---|
77 | $obj = new ReflectionObject($value);
|
---|
78 | $props = $obj->getProperties();
|
---|
79 | $keys = array();
|
---|
80 | foreach ($props as $prop)
|
---|
81 | $keys[] = $prop->getName();
|
---|
82 | return $keys;
|
---|
83 | }
|
---|
84 |
|
---|
85 | private static function loop($obj, $keys, &$input, &$set, &$output) {
|
---|
86 | foreach ($keys as $key) {
|
---|
87 | $value = $obj ? $output->$key : $output[$key];
|
---|
88 | if ($value instanceof FlattedString)
|
---|
89 | Flatted::ref($obj, $key, $input[$value->value], $input, $set, $output);
|
---|
90 | }
|
---|
91 | return $output;
|
---|
92 | }
|
---|
93 |
|
---|
94 | private static function relate(&$known, &$input, &$value) {
|
---|
95 | if (is_string($value) || is_array($value) || is_object($value)) {
|
---|
96 | $key = array_search($value, $known->key, true);
|
---|
97 | if ($key !== false)
|
---|
98 | return $known->value[$key];
|
---|
99 | return Flatted::index($known, $input, $value);
|
---|
100 | }
|
---|
101 | return $value;
|
---|
102 | }
|
---|
103 |
|
---|
104 | private static function ref($obj, &$key, &$value, &$input, &$set, &$output) {
|
---|
105 | if (is_array($value) && !in_array($value, $set, true)) {
|
---|
106 | $set[] = $value;
|
---|
107 | $value = Flatted::loop(false, array_keys($value), $input, $set, $value);
|
---|
108 | }
|
---|
109 | elseif (is_object($value) && !in_array($value, $set, true)) {
|
---|
110 | $set[] = $value;
|
---|
111 | $value = Flatted::loop(true, Flatted::keys($value), $input, $set, $value);
|
---|
112 | }
|
---|
113 | if ($obj) {
|
---|
114 | $output->$key = &$value;
|
---|
115 | }
|
---|
116 | else {
|
---|
117 | $output[$key] = &$value;
|
---|
118 | }
|
---|
119 | }
|
---|
120 |
|
---|
121 | private static function transform(&$known, &$input, &$value) {
|
---|
122 | if (is_array($value)) {
|
---|
123 | return array_map(
|
---|
124 | function ($value) use(&$known, &$input) {
|
---|
125 | return Flatted::relate($known, $input, $value);
|
---|
126 | },
|
---|
127 | $value
|
---|
128 | );
|
---|
129 | }
|
---|
130 | if (is_object($value)) {
|
---|
131 | $object = new stdClass;
|
---|
132 | $keys = Flatted::keys($value);
|
---|
133 | foreach ($keys as $key)
|
---|
134 | $object->$key = Flatted::relate($known, $input, $value->$key);
|
---|
135 | return $object;
|
---|
136 | }
|
---|
137 | return $value;
|
---|
138 | }
|
---|
139 |
|
---|
140 | private static function wrap($value) {
|
---|
141 | if (is_string($value)) {
|
---|
142 | return new FlattedString($value);
|
---|
143 | }
|
---|
144 | if (is_array($value)) {
|
---|
145 | return array_map('Flatted::wrap', $value);
|
---|
146 | }
|
---|
147 | if (is_object($value)) {
|
---|
148 | $keys = Flatted::keys($value);
|
---|
149 | foreach ($keys as $key) {
|
---|
150 | $value->$key = self::wrap($value->$key);
|
---|
151 | }
|
---|
152 | }
|
---|
153 | return $value;
|
---|
154 | }
|
---|
155 | }
|
---|
156 | ?> |
---|