|
1 | 1 | <?php namespace text\json; |
2 | 2 |
|
3 | | -use StdClass; |
| 3 | +use StdClass, Traversable; |
4 | 4 | use lang\{IllegalArgumentException, Value}; |
5 | 5 |
|
6 | 6 | /** |
@@ -81,52 +81,75 @@ public function close($token) { |
81 | 81 | * @return string |
82 | 82 | */ |
83 | 83 | public function representationOf($value) { |
84 | | - $t= gettype($value); |
85 | | - if ('string' === $t) { |
86 | | - return json_encode($value, $this->options); |
87 | | - } else if ('integer' === $t) { |
88 | | - return (string)$value; |
89 | | - } else if ('double' === $t) { |
| 84 | + $r= ''; |
| 85 | + foreach ($this->tokensOf($value) as $bytes) { |
| 86 | + $r.= $bytes; |
| 87 | + } |
| 88 | + return $r; |
| 89 | + } |
| 90 | + |
| 91 | + /** |
| 92 | + * Yields tokens for a given value |
| 93 | + * |
| 94 | + * @param var $value |
| 95 | + * @return iterable |
| 96 | + */ |
| 97 | + public function tokensOf($value) { |
| 98 | + if (is_string($value)) { |
| 99 | + yield json_encode($value, $this->options); |
| 100 | + } else if (is_int($value)) { |
| 101 | + yield (string)$value; |
| 102 | + } else if (is_float($value)) { |
90 | 103 | $cast= (string)$value; |
91 | | - return strpos($cast, '.') ? $cast : $cast.'.0'; |
92 | | - } else if ('array' === $t) { |
| 104 | + yield strpos($cast, '.') ? $cast : $cast.'.0'; |
| 105 | + } else if (is_array($value)) { |
93 | 106 | if (empty($value)) { |
94 | | - return '[]'; |
| 107 | + yield '[]'; |
95 | 108 | } else if (0 === key($value)) { |
96 | | - $r= $this->open('['); |
97 | | - $next= false; |
| 109 | + yield $this->open('['); |
| 110 | + $i= 0; |
98 | 111 | foreach ($value as $element) { |
99 | | - if ($next) { |
100 | | - $r.= $this->comma; |
101 | | - } else { |
102 | | - $next= true; |
103 | | - } |
104 | | - $r.= $this->representationOf($element); |
| 112 | + if ($i++) yield $this->comma; |
| 113 | + yield from $this->tokensOf($element); |
105 | 114 | } |
106 | | - return $r.$this->close(']'); |
107 | | - } else { map: |
108 | | - $r= $this->open('{'); |
109 | | - $next= false; |
110 | | - foreach ($value as $key => $mapped) { |
111 | | - if ($next) { |
112 | | - $r.= $this->comma; |
113 | | - } else { |
114 | | - $next= true; |
115 | | - } |
116 | | - $r.= $this->representationOf($key).$this->colon.$this->representationOf($mapped); |
| 115 | + yield $this->close(']'); |
| 116 | + } else { |
| 117 | + map: yield $this->open('{'); |
| 118 | + $i= 0; |
| 119 | + foreach ($value as $key => $element) { |
| 120 | + if ($i++) yield $this->comma; |
| 121 | + yield from $this->tokensOf((string)$key); |
| 122 | + yield $this->colon; |
| 123 | + yield from $this->tokensOf($element); |
117 | 124 | } |
118 | | - return $r.$this->close('}'); |
| 125 | + yield $this->close('}'); |
119 | 126 | } |
120 | 127 | } else if (null === $value) { |
121 | | - return 'null'; |
| 128 | + yield 'null'; |
122 | 129 | } else if (true === $value) { |
123 | | - return 'true'; |
| 130 | + yield 'true'; |
124 | 131 | } else if (false === $value) { |
125 | | - return 'false'; |
126 | | - } else if ($value instanceof StdClass) { |
127 | | - $value= (array)$value; |
128 | | - if (empty($value)) return '{}'; |
| 132 | + yield 'false'; |
| 133 | + } else if ($value instanceof JsonObject || $value instanceof StdClass) { |
129 | 134 | goto map; |
| 135 | + } else if ($value instanceof Traversable) { |
| 136 | + $i= 0; |
| 137 | + $map= null; |
| 138 | + foreach ($value as $key => $element) { |
| 139 | + if (0 === $i++) { |
| 140 | + $map= 0 !== $key; |
| 141 | + yield $this->open($map ? '{' : '['); |
| 142 | + } else { |
| 143 | + yield $this->comma; |
| 144 | + } |
| 145 | + |
| 146 | + if ($map) { |
| 147 | + yield from $this->tokensOf((string)$key); |
| 148 | + yield $this->colon; |
| 149 | + } |
| 150 | + yield from $this->tokensOf($element); |
| 151 | + } |
| 152 | + yield null === $map ? '[]' : $this->close($map ? '}' : ']'); |
130 | 153 | } else { |
131 | 154 | throw new IllegalArgumentException('Cannot represent instances of '.typeof($value)); |
132 | 155 | } |
|
0 commit comments