true, T_DNUMBER => true, T_STRING => true, T_CONSTANT_ENCAPSED_STRING => true, ); $skipTypes = array( T_WHITESPACE => true, T_COMMENT => true, T_DOC_COMMENT => true, ); $tokens = token_get_all( $string ); $count = count( $tokens ); for ( $i = 0; $i < $count; ) { while ( isset( $skipTypes[$tokens[$i][0]] ) ) { $i++; } switch ( $tokens[$i][0] ) { case T_OPEN_TAG: $i++; continue; case T_VARIABLE: // '$messages' -> 'messages' $varname = trim( substr( $tokens[$i][1], 1 ) ); $varindex = null; while ( isset( $skipTypes[$tokens[++$i][0]] ) ); if ( $tokens[$i] === '[' ) { while ( isset( $skipTypes[$tokens[++$i][0]] ) ); if ( isset( $scalarTypes[$tokens[$i][0]] ) ) { $varindex = $this->parseScalar( $tokens[$i] ); } else { throw $this->except( $tokens[$i], 'scalar index' ); } while ( isset( $skipTypes[$tokens[++$i][0]] ) ); if ( $tokens[$i] !== ']' ) { throw $this->except( $tokens[$i], ']' ); } while ( isset( $skipTypes[$tokens[++$i][0]] ) ); } if ( $tokens[$i] !== '=' ) { throw $this->except( $tokens[$i], '=' ); } while ( isset( $skipTypes[$tokens[++$i][0]] ) ); if ( isset( $scalarTypes[$tokens[$i][0]] ) ) { $buildval = $this->parseScalar( $tokens[$i] ); } elseif ( $tokens[$i][0] === T_ARRAY ) { while ( isset( $skipTypes[$tokens[++$i][0]] ) ); if ( $tokens[$i] !== '(' ) { throw $this->except( $tokens[$i], '(' ); } $buildval = array(); do { while ( isset( $skipTypes[$tokens[++$i][0]] ) ); if ( $tokens[$i] === ')' ) { break; } if ( isset( $scalarTypes[$tokens[$i][0]] ) ) { $key = $this->parseScalar( $tokens[$i] ); } while ( isset( $skipTypes[$tokens[++$i][0]] ) ); if ( $tokens[$i][0] !== T_DOUBLE_ARROW ) { throw $this->except( $tokens[$i], '=>' ); } while ( isset( $skipTypes[$tokens[++$i][0]] ) ); if ( isset( $scalarTypes[$tokens[$i][0]] ) ) { $val = $this->parseScalar( $tokens[$i] ); } wfSuppressWarnings(); $buildval[$key] = $val; wfRestoreWarnings(); while ( isset( $skipTypes[$tokens[++$i][0]] ) ); if ( $tokens[$i] === ',' ) { continue; } elseif ( $tokens[$i] === ')' ) { break; } else { throw $this->except( $tokens[$i], ', or )' ); } } while ( true ); } else { throw $this->except( $tokens[$i], 'scalar or array' ); } if ( is_null( $varindex ) ) { $this->vars[$varname] = $buildval; } else { wfSuppressWarnings(); $this->vars[$varname][$varindex] = $buildval; wfRestoreWarnings(); } while ( isset( $skipTypes[$tokens[++$i][0]] ) ); if ( $tokens[$i] !== ';' ) { throw $this->except( $tokens[$i], ';' ); } $i++; break; default: throw $this->except( $tokens[$i], 'open tag, whitespace, or variable.' ); } } } /** * @param $got string * @param $expected string * @return Exception */ private function except( $got, $expected ) { if ( is_array( $got ) ) { $got = token_name( $got[0] ) . " ('" . $got[1] . "')"; } else { $got = "'" . $got . "'"; } return new Exception( "Expected $expected, got $got" ); } /** * Parse a scalar value in PHP * * @param $token string * * @return mixed Parsed value */ function parseScalar( $token ) { if ( is_array( $token ) ) { $str = $token[1]; } else { $str = $token; } if ( $str !== '' && $str[0] == '\'' ) { // Single-quoted string // @fixme trim() call is due to mystery bug where whitespace gets // appended to the token; without it we ended up reading in the // extra quote on the end! return strtr( substr( trim( $str ), 1, -1 ), array( '\\\'' => '\'', '\\\\' => '\\' ) ); } wfSuppressWarnings(); if ( $str !== '' && $str[0] == '"' ) { // Double-quoted string // @fixme trim() call is due to mystery bug where whitespace gets // appended to the token; without it we ended up reading in the // extra quote on the end! wfRestoreWarnings(); return stripcslashes( substr( trim( $str ), 1, -1 ) ); } wfRestoreWarnings(); if ( substr( $str, 0, 4 ) === 'true' ) { return true; } if ( substr( $str, 0, 5 ) === 'false' ) { return false; } if ( substr( $str, 0, 4 ) === 'null' ) { return null; } // Must be some kind of numeric value, so let PHP's weak typing // be useful for a change return $str; } /** * @param $varname string * @return null|string */ function getVar( $varname ) { if ( isset( $this->vars[$varname] ) ) { return $this->vars[$varname]; } else { return null; } } }