*/ class Styles implements Countable, ArrayAccess, Stringable { /** @var array */ protected $styles = []; /** @var bool */ protected $sorted = true; /** * @param null|array|Traversable|null $classes */ public function __construct(null|array|Traversable $classes = null) { if (!$classes) { return; } foreach ($classes as $name => $value) { $this[$name] = $value; } } public function parse(string $css_string): void { foreach (explode(';', $css_string) as $rule) { $rule = explode(':', trim($rule)); if (count($rule) == 2) { $this[$rule[0]] = $rule[1]; } } } public function count(): int { return count($this->styles); } public function offsetExists(mixed $offset): bool { return @isset($this->styles[$offset]); } public function offsetGet(mixed $offset): mixed { return @$this->styles[$offset]; } public function offsetSet(mixed $offset, mixed $value): void { if (!$value) { unset($this->styles[$offset]); } else { if (!static::validate($offset, $value)) { return; } if (!isset($this->styles[$offset])) { $this->sorted = false; } $this->styles[$offset] = trim($value); } } public function offsetUnset(mixed $offset): void { unset($this->styles[$offset]); } /** * @return array */ public function getArray(): array { if (!$this->sorted) { ksort($this->styles); $this->sorted = true; } return $this->styles; } public function __toString(): string { $styles = []; foreach ($this->getArray() as $key => $value) { $styles[] = $key . ':' . $value; } return implode(';', $styles); } protected static function validate(null|string $property, string $value): bool { if (!$property) { return false; } elseif (!preg_match('/[a-z]/', $property)) { return false; } if (str_contains($value, ';')) { return false; } elseif (str_contains($value, ':')) { return false; } return true; } }