private function encapsVar() {
    static $offset_types = [T_STRING, T_NUM_STRING, T_VARIABLE];
    $node = new StringVariableNode();
    if ($this->tryMatch(T_DOLLAR_OPEN_CURLY_BRACES, $node)) {
      if ($this->tryMatch(T_STRING_VARNAME, $node)) {
        if ($this->tryMatch('[', $node)) {
          $node->addChild($this->expr());
          $this->mustMatch(']', $node);
        }
      }
      else {
        $node->addChild($this->expr());
      }
      $this->mustMatch('}', $node);
      return $node;
    }
    elseif ($this->tryMatch(T_CURLY_OPEN, $node)) {
      $node->addChild($this->variable());
      $this->mustMatch('}', $node);
      return $node;
    }
    elseif ($this->mustMatch(T_VARIABLE, $node)) {
      if ($this->tryMatch('[', $node)) {
        if (!in_array($this->currentType, $offset_types)) {
          throw new ParserException(
            $this->filename,
            $this->iterator->getLineNumber(),
            $this->iterator->getColumnNumber(),
            'expected encaps_var_offset (T_STRING or T_NUM_STRING or T_VARIABLE)');
        }
        $node->addChild($this->tryMatchToken($offset_types));
        $this->mustMatch(']', $node);
      }
      elseif ($this->tryMatch(T_OBJECT_OPERATOR, $node)) {
        $this->mustMatch(T_STRING, $node);
      }
      return $node;
    }
    throw new ParserException(
      $this->filename,
      $this->iterator->getLineNumber(),
      $this->iterator->getColumnNumber(),
      'expected encaps variable');
  }