Complex classes like AbstractJsonEncoder often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
While breaking up the class, it is a good idea to analyze how other classes use AbstractJsonEncoder, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
12 | abstract class AbstractJsonEncoder implements \Iterator |
||
13 | { |
||
14 | /** @var \Iterator[] Current value stack in encoding */ |
||
15 | private $stack; |
||
16 | |||
17 | /** @var bool[] True for every object in the stack, false for an array */ |
||
18 | private $stackType; |
||
19 | |||
20 | /** @var array Stack of values being encoded */ |
||
21 | private $valueStack; |
||
22 | |||
23 | /** @var bool Whether the next value is the first value in an array or an object */ |
||
24 | private $first; |
||
25 | |||
26 | /** @var int The JSON encoding options */ |
||
27 | private $options; |
||
28 | |||
29 | /** @var bool Whether next token should be preceded by new line or not */ |
||
30 | private $newLine; |
||
31 | |||
32 | /** @var string Indent to use for indenting JSON output */ |
||
33 | private $indent; |
||
34 | |||
35 | /** @var string[] Errors that occurred in encoding */ |
||
36 | private $errors; |
||
37 | |||
38 | /** @var int Number of the current line in output */ |
||
39 | private $line; |
||
40 | |||
41 | /** @var int Number of the current column in output */ |
||
42 | private $column; |
||
43 | |||
44 | /** @var mixed The initial value to encode as JSON */ |
||
45 | private $initialValue; |
||
46 | |||
47 | /** @var int|null The current step of the encoder */ |
||
48 | private $step; |
||
49 | |||
50 | /** |
||
51 | * AbstractJsonEncoder constructor. |
||
52 | * @param mixed $value The value to encode as JSON |
||
53 | */ |
||
54 | 117 | public function __construct($value) |
|
61 | |||
62 | /** |
||
63 | * Sets the JSON encoding options. |
||
64 | * @param int $options The JSON encoding options that are used by json_encode |
||
65 | * @return $this Returns self for call chaining |
||
66 | * @throws \RuntimeException If changing encoding options during encoding operation |
||
67 | */ |
||
68 | 75 | public function setOptions($options) |
|
77 | |||
78 | /** |
||
79 | * Sets the indent for the JSON output. |
||
80 | * @param string|int $indent A string to use as indent or the number of spaces |
||
81 | * @return $this Returns self for call chaining |
||
82 | * @throws \RuntimeException If changing indent during encoding operation |
||
83 | */ |
||
84 | 39 | public function setIndent($indent) |
|
93 | |||
94 | /** |
||
95 | * Returns the list of errors that occurred during the last encoding process. |
||
96 | * @return string[] List of errors that occurred during encoding |
||
97 | */ |
||
98 | 6 | public function getErrors() |
|
102 | |||
103 | /** |
||
104 | * Returns the current encoding value stack. |
||
105 | * @return array The current encoding value stack |
||
106 | */ |
||
107 | 3 | protected function getValueStack() |
|
111 | |||
112 | /** |
||
113 | * Initializes the iterator if it has not been initialized yet. |
||
114 | */ |
||
115 | 90 | private function initialize() |
|
121 | |||
122 | /** |
||
123 | * Returns the current number of step in the encoder. |
||
124 | * @return int|null The current step number as integer or null if the current state is not valid |
||
125 | */ |
||
126 | 6 | public function key() |
|
132 | |||
133 | /** |
||
134 | * Tells if the encoder has a valid current state. |
||
135 | * @return bool True if the iterator has a valid state, false if not |
||
136 | */ |
||
137 | 87 | public function valid() |
|
143 | |||
144 | /** |
||
145 | * Returns the current value or state from the encoder. |
||
146 | * @return mixed The current value or state from the encoder |
||
147 | */ |
||
148 | abstract public function current(); |
||
149 | |||
150 | /** |
||
151 | * Returns the JSON encoding to the beginning. |
||
152 | */ |
||
153 | 117 | public function rewind() |
|
171 | |||
172 | /** |
||
173 | * Iterates the next token or tokens to the output stream. |
||
174 | */ |
||
175 | 87 | public function next() |
|
193 | |||
194 | /** |
||
195 | * Handles the next value from the iterator to be encoded as JSON. |
||
196 | * @param \Iterator $iterator The iterator used to generate the next value |
||
197 | * @param bool $isObject True if the iterator is being handled as an object, false if not |
||
198 | */ |
||
199 | 57 | private function processStack(\Iterator $iterator, $isObject) |
|
212 | |||
213 | /** |
||
214 | * Handles the given value key into JSON. |
||
215 | * @param mixed $key The key to process |
||
216 | * @return bool True if the key is valid, false if not |
||
217 | */ |
||
218 | 33 | private function processKey($key) |
|
238 | |||
239 | /** |
||
240 | * Handles the given JSON value appropriately depending on it's type. |
||
241 | * @param mixed $value The value that should be encoded as JSON |
||
242 | */ |
||
243 | 117 | private function processValue($value) |
|
255 | |||
256 | /** |
||
257 | * Resolves the actual value of any given value that is about to be processed. |
||
258 | * @param mixed $value The value to resolve |
||
259 | * @return mixed The resolved value |
||
260 | */ |
||
261 | 117 | protected function resolveValue($value) |
|
275 | |||
276 | /** |
||
277 | * Adds an JSON encoding error to the list of errors. |
||
278 | * @param string $message The error message to add |
||
279 | * @throws EncodingException If the encoding should not continue due to the error |
||
280 | */ |
||
281 | 9 | private function addError($message) |
|
295 | |||
296 | /** |
||
297 | * Pushes the given iterable to the value stack. |
||
298 | * @param object|array $iterable The iterable value to push to the stack |
||
299 | */ |
||
300 | 66 | private function pushStack($iterable) |
|
315 | |||
316 | /** |
||
317 | * Creates a generator from the given iterable using a foreach loop. |
||
318 | * @param object|array $iterable The iterable value to iterate |
||
319 | * @return \Generator The generator using the given iterable |
||
320 | */ |
||
321 | 66 | private function getIterator($iterable) |
|
327 | |||
328 | /** |
||
329 | * Tells if the given iterable should be handled as a JSON object or not. |
||
330 | * @param object|array $iterable The iterable value to test |
||
331 | * @param \Iterator $iterator An Iterator created from the iterable value |
||
332 | * @return bool True if the given iterable should be treated as object, false if not |
||
333 | */ |
||
334 | 66 | private function isObject($iterable, \Iterator $iterator) |
|
346 | |||
347 | /** |
||
348 | * Tells if the given array is an associative array. |
||
349 | * @param array $array The array to test |
||
350 | * @return bool True if the array is associative, false if not |
||
351 | */ |
||
352 | 54 | private function isAssociative(array $array) |
|
368 | |||
369 | /** |
||
370 | * Removes the top element of the value stack. |
||
371 | */ |
||
372 | 63 | private function popStack() |
|
389 | |||
390 | /** |
||
391 | * Encodes the given value as JSON and passes it to output stream. |
||
392 | * @param mixed $value The value to output as JSON |
||
393 | * @param int $token The token type of the value |
||
394 | */ |
||
395 | 108 | private function outputJson($value, $token) |
|
406 | |||
407 | /** |
||
408 | * Returns the name of the JSON error constant. |
||
409 | * @param int $error The error code to find |
||
410 | * @return string The name for the error code |
||
411 | */ |
||
412 | 9 | private function getJsonErrorName($error) |
|
424 | |||
425 | /** |
||
426 | * Passes the given token to the output stream and ensures the next token is preceded by a newline. |
||
427 | * @param string $string The token to write to the output stream |
||
428 | * @param int $token The type of the token |
||
429 | */ |
||
430 | 66 | private function outputLine($string, $token) |
|
435 | |||
436 | /** |
||
437 | * Passes the given token to the output stream. |
||
438 | * @param string $string The token to write to the output stream |
||
439 | * @param int $token The type of the token |
||
440 | */ |
||
441 | 114 | private function output($string, $token) |
|
459 | |||
460 | /** |
||
461 | * Actually handles the writing of the given token to the output stream. |
||
462 | * @param string $string The given token to write |
||
463 | * @param int $token The type of the token |
||
464 | * @return void |
||
465 | */ |
||
466 | abstract protected function write($string, $token); |
||
467 | } |
||
468 |
This check looks for type mismatches where the missing type is
false
. This is usually indicative of an error condtion.Consider the follow example
This function either returns a new
DateTime
object or false, if there was an error. This is a typical pattern in PHP programming to show that an error has occurred without raising an exception. The calling code should check for this returnedfalse
before passing on the value to another function or method that may not be able to handle afalse
.