$values */ public function __construct(private array $values) {} public function getSeparator(): string { return ':'; } public function scopeTo(string ...$prefix): Config { return new ScopedConfig($this, $prefix); } public function hasValues(string|array $names): bool { if(is_string($names)) return array_key_exists($names, $this->values); foreach($names as $name) if(!array_key_exists($name, $this->values)) return false; return true; } public function getAllValueInfos(int $range = 0, int $offset = 0): array { if($range === 0) return array_values($this->values); if($range < 0) throw new InvalidArgumentException('$range must be a positive integer'); if($offset < 0) throw new InvalidArgumentException('$offset must be greater than zero if a range is specified'); return array_slice($this->values, $offset, $range); } public function getValueInfos(string|array $names): array { if(is_string($names)) return array_key_exists($names, $this->values) ? [$this->values[$names]] : []; $infos = []; foreach($names as $name) if(array_key_exists($name, $this->values)) $infos[] = $this->values[$name]; return $infos; } /** * Creates an instance of FsConfig from an array of lines. * * @param string[] $lines Config lines. * @return FsConfig */ public static function fromLines(array $lines): self { $values = []; foreach($lines as $line) { $line = trim($line); if($line === '' || $line[0] === '#' || $line[0] === ';') continue; $info = new FsConfigValueInfo(...explode(' ', $line, 2)); $values[$info->getName()] = $info; } return new FsConfig($values); } /** * Creates an instance of FsConfig from a string. * * @param string $lines Config lines. * @param non-empty-string $newLine Line separator character. * @return FsConfig */ public static function fromString(string $lines, string $newLine = "\n"): self { return self::fromLines(explode($newLine, $lines)); } /** * Creates an instance of FsConfig from a file. * * @param string $path Config file path. * @throws InvalidArgumentException If $path does not exist or could not be opened. * @return FsConfig */ public static function fromFile(string $path): self { if(!is_file($path)) throw new InvalidArgumentException('$path does not exist'); $handle = fopen($path, 'rb'); if($handle === false) throw new RuntimeException('could not open a file handle from $path'); try { return self::fromStream($handle); } finally { fclose($handle); } } /** * Creates an instance of FsConfig from a readable stream. * * @param resource $stream Config file stream. * @throws InvalidArgumentException If $stream is not a . * @return FsConfig */ public static function fromStream(mixed $stream): self { if(!is_resource($stream)) throw new InvalidArgumentException('$stream must be a resource'); $values = []; while(($line = fgets($stream)) !== false) { $line = trim($line); if($line === '' || $line[0] === '#' || $line[0] === ';') continue; $info = new FsConfigValueInfo(...explode(' ', $line, 2)); $values[$info->getName()] = $info; } return new FsConfig($values); } }