philiprehberger/php-safe-json

Safe JSON parsing with exceptions, schema validation, and typed getters

Maintainers

Package info

github.com/philiprehberger/php-safe-json

pkg:composer/philiprehberger/php-safe-json

Fund package maintenance!

philiprehberger

Statistics

Installs: 38

Dependents: 0

Suggesters: 0

Stars: 1

Open Issues: 0

v1.2.0 2026-04-01 13:46 UTC

This package is auto-updated.

Last update: 2026-04-22 16:00:55 UTC


README

Tests Latest Version on Packagist Last updated

Safe JSON parsing with exceptions, schema validation, and typed getters.

Requirements

  • PHP 8.2+

Installation

composer require philiprehberger/php-safe-json

Usage

Decoding JSON

use PhilipRehberger\SafeJson\SafeJson;

$obj = SafeJson::decode('{"name":"Alice","age":30,"active":true}');

$obj->string('name');   // "Alice"
$obj->int('age');       // 30
$obj->bool('active');   // true

Dot Notation for Nested Access

$obj = SafeJson::decode('{"user":{"address":{"city":"Vienna"}}}');

$obj->string('user.address.city'); // "Vienna"
$obj->has('user.address.city');    // true
$obj->has('user.address.zip');     // false

Nested Objects

$obj = SafeJson::decode('{"user":{"name":"Alice"}}');

$user = $obj->object('user');
$user->string('name'); // "Alice"

Safe Decoding (No Exceptions)

$obj = SafeJson::tryDecode('{invalid}');
// Returns null instead of throwing

$obj = SafeJson::tryDecode('{"valid":true}');
// Returns JsonObject

Default Values

$obj = SafeJson::decode('{"name":"Alice"}');

$obj->get('name');              // "Alice"
$obj->get('missing', 'default'); // "default"
$obj->get('missing');           // throws JsonKeyException

Nullable Accessors

$obj = SafeJson::decode('{"name":"Alice","age":30}');

$obj->stringOrNull('name');    // "Alice"
$obj->stringOrNull('missing'); // null
$obj->intOrNull('name');       // null (wrong type)
$obj->intOrNull('age');        // 30

Merging Objects

$a = SafeJson::decode('{"name":"Alice","age":30}');
$b = SafeJson::decode('{"name":"Bob","email":"bob@example.com"}');

$merged = $a->merge($b);
$merged->string('name');  // "Bob" (overridden)
$merged->int('age');      // 30 (kept from $a)
$merged->string('email'); // "bob@example.com" (added from $b)

JSON Path Querying

$obj = SafeJson::decode('{"users":[{"name":"Alice","age":30},{"name":"Bob","age":25}]}');

$obj->query('$.users[*].name');       // ['Alice', 'Bob']
$obj->query('$.users[0].age');        // [30]
$obj->query('$..name');               // ['Alice', 'Bob'] (recursive descent)
$obj->query('$.users[0:1]');          // [['name' => 'Alice', 'age' => 30]]

Supported syntax: $ (root), .key (child), [0] (index), [*] (wildcard), ..key (recursive descent), [0:3] (slice), ['key'] (bracket notation).

JSON Diffing

$changes = SafeJson::diff(
    '{"name":"Alice","age":30}',
    '{"name":"Bob","age":30,"email":"bob@example.com"}'
);

// [
//   ['op' => 'replace', 'path' => 'name', 'value' => 'Bob', 'old' => 'Alice'],
//   ['op' => 'add', 'path' => 'email', 'value' => 'bob@example.com'],
// ]

Streaming Decode

// Memory-efficient decoding of large JSON arrays
foreach (SafeJson::decodeStream('/path/to/large-file.json') as $element) {
    // Each element is decoded one at a time
    // Only one element is held in memory
}

Encoding

$json = SafeJson::encode(['key' => 'value']);
// '{"key":"value"}'

$json = SafeJson::tryEncode($data);
// Returns null on failure instead of throwing

Serialization

$obj = SafeJson::decode('{"key":"value"}');

$obj->toArray(); // ['key' => 'value']
$obj->toJson();  // '{"key":"value"}'
json_encode($obj); // '{"key":"value"}' (JsonSerializable)
(string) $obj;     // '{"key":"value"}' (Stringable)

API

SafeJson

Method Description
decode(string $json): JsonObject Decode JSON string, throws JsonDecodeException on failure
tryDecode(string $json): ?JsonObject Decode JSON string, returns null on failure
encode(mixed $data, int $flags = 0): string Encode to JSON string, throws on failure
tryEncode(mixed $data, int $flags = 0): ?string Encode to JSON string, returns null on failure
diff(string $jsonA, string $jsonB): array Compare two JSON strings and return differences
decodeStream(string $filePath): Generator Stream-decode a JSON array file, yielding elements one at a time

JsonObject

Method Description
string(string $key): string Get string value by key
int(string $key): int Get integer value by key
float(string $key): float Get float value by key (accepts integers)
bool(string $key): bool Get boolean value by key
stringOrNull(string $key): ?string Get string value or null if missing/wrong type
intOrNull(string $key): ?int Get integer value or null if missing/wrong type
floatOrNull(string $key): ?float Get float value or null if missing/wrong type
boolOrNull(string $key): ?bool Get boolean value or null if missing/wrong type
array(string $key): array Get array value by key
object(string $key): JsonObject Get nested JsonObject by key
get(string $key, mixed $default = null): mixed Get value without type enforcement
has(string $key): bool Check if key exists
merge(self $other): self Merge with another JsonObject (other overrides on conflict)
query(string $path): array Query data using JSON Path expression
toArray(): array Return underlying array
toJson(int $flags = 0): string Return JSON string

All key-based methods support dot notation for nested access (e.g., user.address.city).

JsonPath

Method Description
query(array $data, string $path): array Query data using JSON Path expression

JsonDiff

Method Description
diff(mixed $a, mixed $b, string $path = ''): array Compare two values and return list of differences

StreamDecoder

Method Description
decodeStream(string $filePath): Generator Stream-decode a JSON array file element by element

Exceptions

Exception Thrown When
JsonDecodeException Invalid JSON input
JsonEncodeException Failed to encode data
JsonKeyException Missing key or type mismatch

Development

composer install
vendor/bin/phpunit
vendor/bin/pint --test
vendor/bin/phpstan analyse

Support

If you find this project useful:

Star the repo

🐛 Report issues

💡 Suggest features

❤️ Sponsor development

🌐 All Open Source Projects

💻 GitHub Profile

🔗 LinkedIn Profile

License

MIT