From 84d815f4e006e02521759070bb89025dab80b219 Mon Sep 17 00:00:00 2001 From: Kevin Chabowski Date: Sat, 24 May 2014 01:39:33 +0200 Subject: Added scoping. ste:mktag generated tags now have an own scope. They even resemble closures, since they inherit their parent scope. A lot of work was done to keep this compatible with older programs. However: * Templates that relied on the non-scoping behavior of tags will probably fail. * Since $ste->vars is no longer an actual array, things like $ste->vars["foo"]["bar"] = "baz" are no longer possible! A single field access will still work: $ste->vars["foo"] = "bar" --- Scope.php | 187 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 187 insertions(+) create mode 100644 Scope.php (limited to 'Scope.php') diff --git a/Scope.php b/Scope.php new file mode 100644 index 0000000..53566ed --- /dev/null +++ b/Scope.php @@ -0,0 +1,187 @@ + 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; + } + + 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(); + } + + /* + * Function: get_var_reference + * Get a reference to a template variable using a variable name. + * This can be used, if your custom tag takes a variable name as a parameter. + * + * Parameters: + * $name - The variables name. + * $create_if_not_exist - Should the variable be created, if it does not exist? Otherwise NULL will be returned, if the variable does not exist. + * + * Throws: + * if the variable name can not be parsed (e.g. unbalanced brackets). + * + * Returns: + * A Reference to the variable. + */ + 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) ? array() : ""; + $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] = array(); + } else { + $ref[$field] = ""; + } + } + + $ref = &$ref[$field]; + } + + return $ref; + } + + /* + * Function: set_var_by_name + * Set a template variable by its name. + * This can be used, if your custom tag takes a variable name as a parameter. + * + * Parameters: + * $name - The variables name. + * $val - The new value. + * + * Throws: + * if the variable name can not be parsed (e.g. unbalanced brackets). + */ + public function set_var_by_name($name, $val) { + $ref = &$this->get_var_reference($name, true); + $ref = $val; + } + + public function set_local_var($name, $val) { + $ref = &$this->get_var_reference($name, true, true); + $ref = $val; + } + + /* + * Function: get_var_by_name + * Get a template variable by its name. + * This can be used, if your custom tag takes a variable name as a parameter. + * + * Parameters: + * $name - The variables name. + * + * Throws: + * if the variable name can not be parsed (e.g. unbalanced brackets). + * + * Returns: + * The variables value. + */ + public function get_var_by_name($name) { + $ref = $this->get_var_reference($name, false); + return $ref === NULL ? "" : $ref; + } + + 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); + return true; + } catch(VarNotInScope $e) { + return false; + } + } + public function offsetUnset($offset) { + unset($this->vars[$offset]); + } +} -- cgit v1.2.3-70-g09d2