Pretty-printing JSON with custom indent

Berlin, Germany

Recently I was in need of pretty-printing JSON in PHP with custom indentation.

While PHP 5.4 has added the constants JSON_PRETTY_PRINT, JSON_UNESCAPED_SLASHES, and JSON_UNESCAPED_UNICODE which could be combined and passed in into json_encode() to configure encoding options, there’s unfortunately no built-in way to print JSON with an indent other than 4 spaces.

For example:

$data = [
    'name' => 'Andreas Möller',
    'emoji' => '🤓',
    'urls' => [
        'https://localheinz.com',
        'https://github.com/localheinz',
        'https://twitter.com/localheinz',
    ],
];

$json = json_encode(
    $data,
    JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE
);

will result in

{
    "name":"Andreas Möller",
    "emoji":"🤓",
    "urls":[
        "https://localheinz.com",
        "https://github.com/localheinz",
        "https://twitter.com/localheinz"
    ]
}

But what if - for some reason - I need to indent with 2 spaces, or with tabs? Or with 13 spaces?

I first turned to zendframework/zend-json. Unfortunately it doesn’t cover all of the cases I need it to cover, so I started to search. First thing I found was a blog post from 2008, by Dave Perrett. Unfortunately, I felt uncomfortable using it (I would have preferred to find a PHP package, with tests). So I continued to search. Next stop, Stack Overflow: I found a question from 2011. Of course, one answer recommended the blog post by Dave Perrett again. A dead end, it seemed. So I continued to search. Then I took a look at the source code of composer/composer and found Composer\Json\JsonFormatter. Guess what? Of course it is based on the blog post by Dave Perrett.

Well, then, off I go and take the code, grab some tests, add more tests, cut away the parts that I don’t need (back-porting JSON_UNESCAPED_SLASHES and JSON_UNESCAPED_UNICODE for PHP versions prior to 5,4), adjust it so it can process already pretty-printed JSON, allow to pass in an indent string, and publish it as localheinz/json-printer.

Now you can print JSON with 2 spaces, or tabs, or 13 spaces indentation, if you please:

use Localheinz\Json\Printer\Printer;

$indent = '  ';

$printer = new Printer();

$printer->print(
    $json,
    $indent
);

which will then result in

{
  "name":"Andreas Möller",
  "emoji":"🤓",
  "urls":[
    "https://localheinz.com",
    "https://github.com/localheinz",
    "https://twitter.com/localheinz"
  ]
}

Hope it helps!