private static function getAttributes($block) { $result = array(); $state = State::START; for ($i = 0, $len = strlen($block); $i < $len; $i++) { $c = $block[$i]; switch ($state) { case State::START: $state = Lexer::isAttributesListStart($c) ? State::ATTRNAME : State::ERROR; $attrName = ''; $attrVal = null; break; case State::ATTRNAME: if (Lexer::isSpace($c)) { continue; } $p = self::getName($block, $len, $i); if ($p == -1) { $state = State::ERROR; } else { $attrName = substr($block, $i, $p); $i += $p - 1; $state = State::ATTRSEPARATOR; } break; case State::ATTRSEPARATOR: if (Lexer::isSpace($c)) { continue; } if (Lexer::isAttributeValueSeparator($c)) { $state = State::ATTRVALUE; } break; case State::ATTRVALUE: if (Lexer::isSpace($c)) { continue; } if (Lexer::isPairingSymbol($c)) { $p = self::getBraketsBlock($block, $len, $i, $c); if ($p == -1) { $state = State::ERROR; } else { $val = substr($block, $i, $p); $attrVal = $val[0] == "'" ? substr($val, 1, -1) : json_decode($val); $i += $p - 1; $state = State::ATTRDONE; } } else { // Dirty but effective way $attrVal = strtok(substr($block, $i), ' ,)'); $i += strlen($attrVal) - 1; $state = State::ATTRDONE; } break; case State::ATTRDONE: if (!empty($attrName)) { $result[$attrName] = $attrVal; } $attrName = ''; $attrVal = null; if (Lexer::isComma($c)) { $state = State::ATTRNAME; } if (Lexer::isAttributesListEnd($c)) { return $result; } break; case State::ERROR: default: throw new RuntimeException("Wrong state: {$state}"); } } return $result; }