parser($data, $cast, $delimiter); $data = \iterator_to_array($parser); if ($parser->getReturn() !== '') { throw new ParseException("Data left in buffer after parsing"); } return $data; } private function parser(string $data, callable $cast = null, string $delimiter = ','): \Generator { $data = \trim($data); if ($data[0] !== '{' || \substr($data, -1) !== '}') { throw new ParseException("Missing opening or closing brackets"); } $data = \ltrim(\substr($data, 1)); do { if ($data === '') { throw new ParseException("Missing closing bracket"); } if ($data[0] === '{') { // Array $parser = $this->parser($data, $cast, $delimiter); yield \iterator_to_array($parser); list($data, $end) = $this->trim($parser->getReturn(), 0); continue; } if ($data[0] === '"') { // Quoted value $position = 1; do { $position = \strpos($data, '"', $position); if ($position === false) { throw new ParseException("Could not find matching quote in quoted value"); } } while ($data[$position - 1] === '\\' && ++$position); // Check for escaped " $yield = \str_replace('\\"', '"', \substr($data, 1, $position - 1)); list($data, $end) = $this->trim($data, $position + 1); } else { // Unquoted value $position = 0; while (isset($data[$position]) && $data[$position] !== $delimiter && $data[$position] !== '}') { ++$position; } $yield = \trim(\substr($data, 0, $position)); list($data, $end) = $this->trim($data, $position); } if (\strcasecmp($yield, "NULL") === 0) { yield null; } elseif ($cast) { yield $cast($yield); } else { yield $yield; } } while ($end !== '}'); return $data; } private function trim(string $data, int $position): array { do { if (!isset($data[$position])) { throw new ParseException("Unexpected end of data"); } $end = $data[$position]; } while (\ltrim($end) === '' && isset($data[++$position])); $data = \ltrim(\substr($data, $position + 1)); return [$data, $end]; } }