JSON is one of the most commonly used data serialization formats. It grew from its origins in JavaScript (JSON means JavaScript Object Notation) and has become the format of choice for many web APIs and configuration systems.
PHP comes with built-in JSON support. Historically, the functions were provided as a separate extension. The launch of PHP 8.0 in 2020 turned JSON into a permanently active extension that cannot be removed.
Read JSON data
To parse JSON data, use the json_decode()
function. The full signature is as follows:
json_decode(string $json, bool|null $associative=null, int $depth=512, int $flags=0) : mixed;
The simplest call is to pass a JSON string with no other arguments. We will work with it {"foo": "bar"}
which decodes to an instance of PHP’s generic stdClass
. Our new object is given ownership foo
with the value of bar
.
If you prefer to receive an associative array, you must pass true
to the $associative
parameter of json_decode()
. The above example would then decode to ["foo" => "bar"]
.
The $depth
parameter you can determine the maximum nest level to parsed to. You get null
if the JSON nests deeper than the set level, no attempt will be made to parse the data.
The $flags
parameter accepts a bit mask of optional flags that change the parsing behavior. These are detailed in the PHP manual and allow you to define how to handle specific data types.
Dealing with parsing errors
Standard, json_decode()
will be back null
when it passed an invalid JSON string. This poses a problem because one is isolated null
is a valid JSON string. You cannot know if it null
return value is due to the JSON with null
, or because the JSON was in the wrong format and could not be parsed.
PHP 7.3 finally solved this long-standing problem through the extension JSON_THROW_ON_ERROR
flag. Pass this constant to the $flags
parameter of json_decode()
to have PHP throw an exception when invalid JSON is encountered:
json_decode("['malformed json", true, 512, JSON_THROW_ON_ERROR);
Enabling this behavior is generally desirable, but it makes for a rather unwieldy invocation. You can use PHP 8’s mentioned arguments to simplify things a bit, as you don’t need to pass explicit values for the optional parameters:
json_decode(json: "['malformed json", flags: JSON_THROW_ON_ERROR);
The two examples shown above are equivalent to each other. The only difference is that the last syntax requires PHP 8.
Serialize data to JSON
You can serialize PHP values to JSON strings using the json_encode()
function. The signature is as follows:
json_encode(mixed $value, int $flags=0, int $depth=512) : string|false;
PHP accepts any value as $value
, except sources. Data types are automatically processed to ensure they have an appropriate mapping in the generated JSON. PHP objects and associative arrays become JSON objects containing all enumerable properties / key value pairs of the input value. PHP scalar types are mapped directly in JSON without transformation.
Like its decoding counterpart, json_encode()
accepts $flags
and $depth
parameters. Be careful with the order though – in a quirk of the PHP standard library the position of these two optional parameters is changed compared to json_decode()
.
Many more flags are supported when encoding data. Here are some to watch out for:
JSON_FORCE_OBJECT
Convert PHP numeric arrays to JSON objects instead of arrays. This covers the case where a variable contains an associative array that may be empty. When the array is empty ([]
), a JSON array would be created; if it is not empty (["foo" => "bar"]
), an object would be emitted instead. Enabling this flag ensures that an object is always used in the encoded JSON.JSON_PRETTY_PRINT
– PHP’s JSON output is normally miniaturized, which is ideal when sent over the network as part of an HTTP request. Setting this flag adds new line characters and auto indentation to the JSON string, making it more suitable for configuration files and other scenarios where people will read the output.JSON_PRESERVE_ZERO_FRACTION
– Forces PHP to use floats like0.0
exactly, instead of shaving off the fraction to write0
in the JSON (which can be incorrectly parsed as an integer).JSON_NUMERIC_CHECK
– Automatically converts numeric strings to numbers in the JSON output, instead of keeping them as strings. With this enabled, a PHP value"234.5"
is broadcast as234.5
in the JSON.JSON_PARTIAL_OUTPUT_ON_ERROR
– Try to continue writing even after an encoding error has occurred. PHP will try to replace invalid values to produce some output, even if it is incomplete.
You can find the full list of flags in the PHP documentation. The rest are usually specific options to customize the encoding used in certain scenarios.
Bring JSON to the domain layer of your application
Complex web backends most likely use PHP’s JSON functions in the context of sending HTTP responses. That probably means that you will be encoding domain layer class instances, such as BlogPost
.
Calling json_encode()
with an instance of a class results in a JSON string with a single object. PHP will use the public properties of the class and add them as key-value pairs in the JSON-encoded object.
class BlogPost { protected int $Id = 1; public string $Title = "Example"; } // produces '{"Title": "Example"}' $json = json_encode(new BlogPost());
PHP does not automatically access protected or private properties. This standard implementation is therefore insufficient for all classes except the simplest. Instead, your classes can do it JsonSerializable
couple. Allows you to control how instances are transformed to JSON.
JsonSerializable
defines a single method, jsonSerialize()
, which PHP will call when an instance needs to be serialized to JSON:
class BlogPost implements JsonSerializable { protected int $Id = 1; public string $Title = "Example"; public function jsonSerialize() { return [ "Id" => $this -> Id, "Title" => $this -> Title ]; } } // produces '{"Id": 1, "Title": "Example"}' $json = json_encode(new BlogPost());
Implement JsonSerializable
puts you in control of the serialization process. Your instances can choose what to display, including potentially protected properties, dynamically calculated values, and data returned by method calls.
You don’t even need to return an array. The jsonSerializable
method signature specifies a mixed
return type so that you can specify any value that PHP can serialize to JSON. You could return another object to have PHP serialize it recursively.
Source link