*/
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;
}
}