0) && ($more[0] !== '[')) { // TODO: better error message, not very non-programmer friendly... throw new RuntimeError("A variable name must be of format name('[' name ']')*."); } $remain = $field . $more; } return $fields; } /** * @param string $name * @param bool $localonly * @return mixed A reference to the resolved variable * @throws VarNotInScope */ private function &get_topvar_reference($name, $localonly) { if (array_key_exists($name, $this->vars)) { $ref = &$this->vars[$name]; return $ref; } if ((!$localonly) && ($this->parent !== null)) { $ref = &$this->parent->get_topvar_reference($name, $localonly); return $ref; } throw new VarNotInScope(); } /** * @param string $name * @param bool $create_if_not_exist * @param bool $localonly * @return mixed A reference to the resolved variable * @throws RuntimeError */ public function &get_var_reference($name, $create_if_not_exist, $localonly=false) { $nullref = null; $fields = self::parse_name($name); if (count($fields) == 0) { return $nullref; // TODO: or should we throw an exception here? } $first = $fields[0]; $ref = null; try { $ref = &$this->get_topvar_reference($first, $localonly); } catch (VarNotInScope $e) { if ($create_if_not_exist) { $this->vars[$first] = (count($fields) > 0) ? [] : ""; $ref = &$this->vars[$first]; } else { return $nullref; } } for ($i = 1; $i < count($fields); $i++) { $field = $fields[$i]; if (!is_array($ref)) { return $nullref; } if (!array_key_exists($field, $ref)) { if (!$create_if_not_exist) { return $nullref; } if ($i < count($fields) - 1) { $ref[$field] = []; } else { $ref[$field] = ""; } } $ref = &$ref[$field]; } return $ref; } /** * @param string $name * @param mixed $val * @throws RuntimeError */ public function set_var_by_name($name, $val) { $ref = &$this->get_var_reference($name, true); $ref = $val; } /** * @param string $name * @param mixed $val * @throws RuntimeError */ public function set_local_var($name, $val) { $ref = &$this->get_var_reference($name, true, true); $ref = $val; } /** * @param string $name * @return mixed Returns an empty string, if not found or unset * @throws RuntimeError */ public function get_var_by_name($name) { $ref = $this->get_var_reference($name, false); return $ref === null ? "" : $ref; } /** * @return self */ public function new_subscope() { $o = new self(); $o->parent = $this; return $o; } /* implementing ArrayAccess */ public function offsetSet($offset, $value) { $this->set_var_by_name($offset, $value); } public function offsetGet($offset) { return $this->get_var_by_name($offset); } public function offsetExists($offset) { try { $this->get_topvar_reference($offset, false); return true; } catch (VarNotInScope $e) { return false; } } public function offsetUnset($offset) { unset($this->vars[$offset]); } }