public static function pprintJSON($obj, $indent = 0, $json_array = null, $buf = null)
    {
        if (!is_object($obj) && !is_array($obj))
            return self::writeJSON($obj, $buf);

        // Make sure objects are traversable, or otherwise convert it to array
        if (method_exists($obj, "jsonSerialize"))
        {
            $obj = $obj->jsonSerialize();
        }
        elseif (!WF::is_array_like($obj))
        {
            // Extract properties and mark as non-array
            $obj = get_object_vars($obj);
            $json_array = false;
        }

        if ($json_array === null)
            $array = WF::is_numeric_array($obj);
        else
            $array = (bool)$json_array;

        // Open a memory buffer when no buffer is provided
        $return_buf = false;
        if ($buf === null)
        {
            $buf = fopen("php://memory", "rw");
            $return_buf = true;
        }

        // Write opening bracket
        if (count($obj) > 0)
        {
            fwrite($buf, $array ? "[\n" : "{\n");

            // Write properties
            $indent += 4;
            $tot = count($obj);
            $cur = 0;
            foreach ($obj as $key => $sub)
            {
                // Keys need to be string, otherwise they will not be quoted
                if (is_numeric($key) && !$array)
                    $key = (string)$key;

                $ending = (++$cur < $tot ? ",\n" : "\n");
                fwrite($buf, str_repeat(' ', $indent));
                if (!$array)
                {
                    self::writeJSON($key, $buf);
                    fwrite($buf, ': ');
                } 

                if (WF::is_array_like($sub) || is_object($sub))
                    self::pprintJSON($sub, $indent, null, $buf);
                else
                    self::writeJSON($sub, $buf);

                fwrite($buf, $ending);
            }

            // Write closing bracket
            fwrite($buf, str_repeat(' ', $indent - 4) . ($array ? ']' : '}'));
        }
        else
            fwrite($buf, $array ? "[]" : "{}");

        if (!$return_buf)
            return;

        // Get buffer contents and return it
        rewind($buf);
        $json = stream_get_contents($buf);
        fclose($buf);
        return $json;
    }