Implement the Listener interface
master\JsonStreamingParser\Listener interface. The parser will trigger events on this listener as it encounters different parts of the JSON structure (e.g., start of object, key, value, etc.).repository·master·Indexed 20 days ago
https://github.com/salsify/jsonstreamingparserA streaming JSON parser for PHP designed to process very large JSON documents efficiently by avoiding loading the entire document into memory. It utilizes a listener pattern similar to a SAX parser, requiring the implementation of the \JsonStreamingParser\Listener interface. The library includes specialized listeners such as CorruptedJsonListener for repairing truncated documents, GeoJsonListener for processing GeoJSON features, RegexListener for path-based extraction, and SimpleObjectQueueListener for flat arrays of objects.
\JsonStreamingParser\Listener interface. The parser will trigger events on this listener as it encounters different parts of the JSON structure (e.g., start of object, key, value, etc.).To add the streaming JSON parser to your PHP project, use Composer to require the package.
composer require salsify/json-streaming-parserThe JsonStreamingParser works by using a listener pattern similar to a SAX parser for XML. To use it, you must implement the \JsonStreamingParser\Listener interface. This interface allows your custom listener to receive events from the parser as it processes the JSON stream, enabling you to handle large documents without loading them entirely into memory.
Once your listener is implemented, pass the file stream and your listener instance to the \JsonStreamingParser\Parser class and call the parse() method.
$stream = fopen('doc.json', 'r');
$listener = new YourListener(); // YourListener must implement \JsonStreamingParser\Listener
try {
$parser = new \JsonStreamingParser\Parser($stream, $listener);
$parser->parse();
fclose($stream);
} catch (Exception $e) {
fclose($stream);
throw $e;
}The CorruptedJsonListener is a specialized implementation of ListenerInterface designed to construct an in-memory representation of a JSON document. It is particularly useful for repairing "cut" JSON documents—files that end unexpectedly before the structure is complete. By using this listener, you can capture the partially parsed data and then call forceEndDocument() to close all open objects and arrays, effectively reconstructing a valid JSON structure from the truncated input.
// Conceptual usage pattern
$listener = new \JsonStreamingParser\Listener\CorruptedJsonListener();
$parser = new \JsonStreamingParser\Parser($listener);
// If the stream ends prematurely, you can attempt to repair it:
$listener->forceEndDocument();
$repairedJson = $listener->getJson();The RegexListener allows you to extract specific elements from a JSON stream by matching their path against regular expressions. This is useful for processing large JSON files where you only need a subset of the data.
Paths are constructed using forward slashes (/).
/name matches a name attribute at the root./1/name matches the name attribute of the second element (index 1) in an array./\d* matches any element within an array.You can use regex capture groups to pass the specific path segment to your callback. For example, (/\d*) will pass the array index as the second argument to your closure.
To improve performance when you only need a specific piece of data, you can call $parser->stop() inside your callback to halt the parsing process immediately.
// Basic usage: selecting specific paths
$listener = new RegexListener([
"/1/name" => function ($data) {
echo "/1/name=" . $data . PHP_EOL;
}
]);
$parser = new Parser(fopen($filename, 'rb'), $listener);
$parser->parse();
// Using capture groups to get the path segment
$listener = new RegexListener([
"(/\d*)" => function ($data, $path) {
echo $path . "=" . $data['name'] . PHP_EOL;
}
]);
$parser = new Parser(fopen($filename, 'rb'), $listener);
$parser->parse();
// Stopping the parser once data is found
$listener = new RegexListener();
$parser = new Parser(fopen($filename, 'rb'), $listener);
$listener->setMatch([
"/total_rows" => function ($data) use ($parser) {
echo "/total_rows=" . $data . PHP_EOL;
$parser->stop();
}
]);
$parser->parse();JsonStreamingParser\Exception\ParsingException. This exception provides the exact location of the error within the document using the line and character position. You can catch this exception to identify where the JSON structure failed.The SimpleObjectQueueListener is a specialized listener designed to parse simple JSON files containing a flat array of objects (e.g., [{"id":"1", "name":"foo"}, {"id":"2", "name":"bar"}]). It is ideal for high-volume data imports or database seeding where memory efficiency is critical.
Limitations:
To use it, instantiate the listener with a callback function that will be executed every time an object in the array is fully parsed.
use JsonStreamingParser\Listener
SimpleObjectQueueListener;
// Define a callback to handle each parsed object
$callback = function ($object) {
// Process the object (e.g., save to database)
echo "Parsed object: " . print_r($object, true) . "\n";
};
// Initialize the listener.
// Use TYPE_ARRAY to receive associative arrays, or TYPE_OBJECT to receive stdClass objects.
$listener = new SimpleObjectQueueListener($callback, SimpleObjectQueueListener::TYPE_ARRAY);
// The $listener would then be passed to the Parser instanceThe GeoJsonListener is a specialized implementation of ListenerInterface designed to handle GeoJSON data efficiently. Instead of building a massive in-memory FeatureCollection, it constructs an in-memory representation only at the second level of the JSON hierarchy. This allows you to process individual Feature objects one at a time, significantly reducing memory usage when parsing large GeoJSON files.
To use it, pass a callable to the constructor. This callback will be triggered every time a single feature (or a second-level object) is fully parsed. The callback receives the parsed object as its argument.
use JsonStreamingParserormatormat; // Assuming parser usage
use JsonStreamingParserormatormat;
use JsonStreamingParser\Listener\GeoJsonListener;
// The callback is executed for every second-level object parsed
$callback = function ($feature) {
// Process a single GeoJSON Feature here
echo "Parsed feature: " . json_encode($feature) . PHP_EOL;
};
$listener = new GeoJsonListener($callback);
// Pass the listener to your parser instance to begin streaming
// $parser->parse($stream, $listener);The InMemoryListener is a basic implementation of a listener that constructs a complete in-memory representation of a JSON document. While streaming parsers are typically used to avoid loading entire documents into memory, this class is useful as a reference implementation or as a starting point for building custom listeners.
After the parser has finished, you can retrieve the fully parsed JSON structure using the getJson() method.
// Example usage pattern (conceptual)
$listener = new \JsonStreamingParser\Listener\InMemoryListener();
$parser = new \JsonStreamingParser\Parser($listener);
$parser->parse($jsonString);
$json = $listener->getJson();The RegexListener uses a mapping of regular expression strings to callables to determine which parts of the JSON stream to act upon.
setMatch(array $dataMatch)Sets or updates the matching criteria.
Parameters:
$dataMatch: An associative array where the key is a regular expression string representing the JSON path, and the value is a callable (e.g., an anonymous function) that receives the extracted data.Callback Signature:
function ($value, $pathSegment = [])
$value: The data found at the matched path.$pathSegment: (Optional) If the regex contains a capture group, this argument contains the captured string/array.$listener = new RegexListener();
$listener->setMatch([
"/user/id" => function($id) { /* ... */ },
"/items/\d+/price" => function($price) { /* ... */ }
]);When instantiating SimpleObjectQueueListener, you can specify the data type that the callback receives using the $returnType parameter. This determines whether the parsed object is passed to your callback as an associative array or a stdClass object.
Available constants:
SimpleObjectQueueListener::TYPE_ARRAY: Provides an associative array to the callback.SimpleObjectQueueListener::TYPE_OBJECT: Provides an object (stdClass) to the callback.// To receive associative arrays:
$listener = new SimpleObjectQueueListener($callback, SimpleObjectQueueListener::TYPE_ARRAY);
// To receive objects:
$listener = new SimpleObjectQueueListener($callback, SimpleObjectQueueListener::TYPE_OBJECT);To use the streaming parser, instantiate the JsonStreamingParser\Parser class. You must provide a PHP stream resource and an implementation of ListenerInterface which will receive events as the JSON is parsed.
Optional parameters allow you to configure the line ending, whether to emit whitespace events, and the buffer size for reading from the stream.
use JsonStreamingParser\Parser;
use Your\Custom\ListenerImplementation;
$stream = fopen('data.json', 'r');
$listener = new ListenerImplementation();
$parser = new Parser(
$stream, // resource
$listener, // ListenerInterface
"\n", // string (optional, default: "\n")
false, // bool (optional, default: false, emitWhitespace)
8192 // int (optional, default: 8192, bufferSize)
);