Last active
October 30, 2020 10:20
-
-
Save attitude/1953e9df155ef709b79f9af32fcb2c03 to your computer and use it in GitHub Desktop.
A JSON encoder class to encode and process large data sets
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace LargeJson; | |
class JSONEncoder { | |
protected static $whiteSpace = ' '; | |
protected static $indentation = 2; | |
protected static $inline = false; | |
/** | |
* Globally set to use tabs | |
* | |
* Call with `false` to switch to spaces back. | |
* | |
*/ | |
public static function tabs(bool $useTabs = true) { | |
static::$whiteSpace = $useTabs ? "\t" : ' '; | |
} | |
/** | |
* Globally set how much to indent for pretty print | |
* | |
* Use `0` to disable pretty print. | |
* | |
*/ | |
public static function indent(int $indentation) { | |
assert($indentation >= 0, 'indentation is non-negative failed'); | |
static::$indentation = $indentation; | |
} | |
protected static function paddingByLevel(int $level) { | |
if (static::$inline) { | |
return ''; | |
} | |
return str_repeat(static::$whiteSpace, $level * static::$indentation); | |
} | |
protected static function newLine() { | |
return static::$indentation > 0 && !static::$inline ? "\n" : ''; | |
} | |
protected static function allScallar(array $array) { | |
foreach ($array as &$value) { | |
if (is_array($value) || is_object($value)) { | |
return false; | |
} | |
} | |
return true; | |
} | |
/** | |
* Encode data to JSON with callback | |
* | |
* Use callback function to further process part of the encoded JSON string. | |
* Callback is expected to have 1 string attribute. | |
*/ | |
public static function encode($data, callable $append, int $level = 0) { | |
if (!is_array($data) && !is_object($data)) { | |
$append(json_encode($data)); | |
} | |
$padding = static::paddingByLevel($level); | |
$innerPadding = static::paddingByLevel($level + 1); | |
$newLine = static::newLine(); | |
if ($level === 200) { | |
$append(str_replace($newLine, "${$newLine}${padding} ", json_encode($data, JSON_PRETTY_PRINT))); | |
} | |
$isObject = is_object($data); | |
$keys = array_keys((array) $data); | |
$hasKeys = $isObject || is_string($keys[0]); | |
$append(($hasKeys ? "{" : "[").$newLine); | |
foreach ($keys as $index => $key) { | |
$append($hasKeys | |
? "${innerPadding}\"${key}\":".($newLine ? ' ' : '') | |
: "${innerPadding}" | |
); | |
if ($isObject) { | |
$value =& $data->{$key}; | |
} else { | |
$value =& $data[$key]; | |
} | |
if (is_array($value) || is_object($value)) { | |
if (is_array($value) && static::allScallar($value)) { | |
static::$inline = true; | |
static::encode($value, $append, 0); | |
static::$inline = false; | |
} else { | |
static::encode($value, $append, $level + 1); | |
} | |
} else { | |
$append(json_encode($value)); | |
} | |
if ($index <= count($keys) - 2) { | |
$append(",".(static::$inline ? ' ' : '')); | |
} | |
$append($newLine); | |
} | |
$append($hasKeys ? "${padding}}" : "${padding}]"); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment