flow/jsonpath
PHP JSONPath implementation for querying and extracting data with XPath-like expressions. Object-oriented, tokenized/cached parser (no eval) and works with arrays, objects, and ArrayAccess. Note: this repo is unmaintained; see SoftCreatR/JSONPath.
Installation:
composer require flow/jsonpath
(Note: The package is archived; use SoftCreatR/JSONPath for active maintenance.)
Basic Usage:
use Flow\JSONPath\JSONPath;
$data = ['store' => ['books' => [
['title' => 'Book 1', 'price' => 10],
['title' => 'Book 2', 'price' => 20]
]]];
$jsonPath = new JSONPath($data);
$results = $jsonPath->find('$.store.books[*].title');
// Returns: ['Book 1', 'Book 2']
First Use Case:
$response = json_decode($apiResponse);
$titles = (new JSONPath($response))->find('$.data.books[*].title');
Chaining Queries:
Use find() to chain multiple JSONPath queries:
$books = $jsonPath->find('$.store.books');
$expensiveBooks = $jsonPath->find('$..[?(@.price > 15)]');
Recursive Descent (..):
Traverse deeply nested structures:
$allAuthors = $jsonPath->find('$..author'); // Finds all authors recursively
Array Slicing: Extract subarrays using slice notation:
$firstTwoBooks = $jsonPath->find('$..books[0:2]'); // First two books
$everyThirdBook = $jsonPath->find('$..books[::3]'); // Every third book
Filtering with Predicates: Filter results dynamically:
$cheapBooks = $jsonPath->find('$..books[?(@.price < 10)]');
Magic Method Access (Caution):
Enable __get() support for objects (use sparingly):
$jsonPath = new JSONPath($object, JSONPath::ALLOW_MAGIC);
API Response Processing:
Parse Laravel API responses (e.g., from Http::get() or axios):
$response = Http::get('api/books')->json();
$titles = (new JSONPath($response))->find('$.data[*].title');
Configuration Extraction:
Extract values from nested config arrays (e.g., config('services.api')):
$config = config('services');
$apiKeys = (new JSONPath($config))->find('$..api[*].key');
Form Data Validation:
Validate nested form data (e.g., from request()->all()):
$data = request()->all();
$validBooks = (new JSONPath($data))->find('$..books[?(@.price > 0)]');
Laravel Service Provider: Bind the package globally for reuse:
// app/Providers/AppServiceProvider.php
public function register()
{
$this->app->singleton('jsonpath', function () {
return new \Flow\JSONPath\JSONPath;
});
}
Usage:
$results = app('jsonpath')->find($data, '$.path');
Eloquent Relationships: Query nested Eloquent relationships:
$user = User::with('posts.comments')->find(1);
$comments = (new JSONPath($user))->find('$..comments[*].body');
Testing: Use in PHPUnit tests to assert nested data:
$this->assertEquals(['Book 1', 'Book 2'], (new JSONPath($data))->find('$.store.books[*].title'));
Archived Package:
Magic Method Quirks:
ALLOW_MAGIC can lead to unpredictable behavior (e.g., wildcard queries ignore private properties).__get() implementation.Slice Notation Breaking Change:
0.5.0 fixed slice notation (e.g., [0:2:5]). Older code may break if relying on the buggy implementation.No Multiple String Indices:
$[name,year] or $["name","year"]. Use dot notation ($.name.year) instead.Script Expressions:
eval() support. Use only supported operators (==, !=, <, >) in predicates.Tokenization Errors:
$lexer = new \Flow\JSONPath\Lexer('$.store..price');
$tokens = $lexer->getTokens();
dd($tokens); // Debug token stream
Path Not Found:
exists():
if ((new JSONPath($data))->exists('$.store.books')) {
// Path exists
}
Performance:
$data object is immutable or cloned per query to avoid side effects.Laravel Collections Integration: Convert results to Laravel Collections for chaining:
$results = collect((new JSONPath($data))->find('$.path'));
$filtered = $results->filter(fn($item) => $item > 10);
Custom Data Structures:
Works with ArrayAccess objects (e.g., Laravel’s Arrayable):
$arrayable = new class implements ArrayAccess { ... };
$results = (new JSONPath($arrayable))->find('$.key');
Performance Optimization:
$jsonPath = new JSONPath($data);
$cachedQuery = $jsonPath->compile('$.store.books[*].title');
$results = $cachedQuery->evaluate($data);
Error Handling:
try {
$results = (new JSONPath($data))->find('$.invalid.path');
} catch (\Flow\JSONPath\Exception\RuntimeException $e) {
Log::error($e->getMessage());
}
Alternative for Advanced Use Cases:
How can I help you explore Laravel packages today?