Skip to content

Instantly share code, notes, and snippets.

@attitude
Last active October 30, 2020 10:20
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save attitude/1953e9df155ef709b79f9af32fcb2c03 to your computer and use it in GitHub Desktop.
Save attitude/1953e9df155ef709b79f9af32fcb2c03 to your computer and use it in GitHub Desktop.
A JSON encoder class to encode and process large data sets
<?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