*/ final class CamelCaseKeys implements IteratorAggregate { /** @var array */ private array $source; /** * @param iterable $source */ public function __construct(iterable $source) { $this->source = $this->replace($source); } /** * @param iterable $source * @return array */ private function replace(iterable $source): array { $result = []; foreach ($source as $key => $value) { assert(is_string($key) || is_int($key)); if (is_iterable($value)) { $value = $this->replace($value); } if (! is_string($key)) { $result[$key] = $value; continue; } $camelCaseKey = $this->camelCaseKeys($key); if (isset($result[$camelCaseKey])) { continue; } $result[$camelCaseKey] = $value; } return $result; } private function camelCaseKeys(string $key): string { return lcfirst(str_replace([' ', '_', '-'], '', ucwords($key, ' _-'))); } public function getIterator(): Traversable { yield from $this->source; } }