4 * Quickie parser class that can happily read the subset of PHP we need
5 * for our localization arrays safely.
7 * Still an order of magnitude slower than eval().
9 class QuickArrayReader {
13 * @param $string string
15 function __construct( $string ) {
20 T_CONSTANT_ENCAPSED_STRING => true,
25 T_DOC_COMMENT => true,
27 $tokens = token_get_all( $string );
28 $count = count( $tokens );
29 for ( $i = 0; $i < $count; ) {
30 while ( isset( $skipTypes[$tokens[$i][0]] ) ) {
33 switch ( $tokens[$i][0] ) {
38 // '$messages' -> 'messages'
39 $varname = trim( substr( $tokens[$i][1], 1 ) );
42 while ( isset( $skipTypes[$tokens[++$i][0]] ) ) {
45 if ( $tokens[$i] === '[' ) {
46 while ( isset( $skipTypes[$tokens[++$i][0]] ) ) {
49 if ( isset( $scalarTypes[$tokens[$i][0]] ) ) {
50 $varindex = $this->parseScalar( $tokens[$i] );
52 throw $this->except( $tokens[$i], 'scalar index' );
54 while ( isset( $skipTypes[$tokens[++$i][0]] ) ) {
57 if ( $tokens[$i] !== ']' ) {
58 throw $this->except( $tokens[$i], ']' );
60 while ( isset( $skipTypes[$tokens[++$i][0]] ) ) {
64 if ( $tokens[$i] !== '=' ) {
65 throw $this->except( $tokens[$i], '=' );
67 while ( isset( $skipTypes[$tokens[++$i][0]] ) ) {
70 if ( isset( $scalarTypes[$tokens[$i][0]] ) ) {
71 $buildval = $this->parseScalar( $tokens[$i] );
72 } elseif ( $tokens[$i][0] === T_ARRAY ) {
73 while ( isset( $skipTypes[$tokens[++$i][0]] ) ) {
75 if ( $tokens[$i] !== '(' ) {
76 throw $this->except( $tokens[$i], '(' );
80 while ( isset( $skipTypes[$tokens[++$i][0]] ) ) {
83 if ( $tokens[$i] === ')' ) {
86 if ( isset( $scalarTypes[$tokens[$i][0]] ) ) {
87 $key = $this->parseScalar( $tokens[$i] );
89 while ( isset( $skipTypes[$tokens[++$i][0]] ) ) {
92 if ( $tokens[$i][0] !== T_DOUBLE_ARROW ) {
93 throw $this->except( $tokens[$i], '=>' );
95 while ( isset( $skipTypes[$tokens[++$i][0]] ) ) {
98 if ( isset( $scalarTypes[$tokens[$i][0]] ) ) {
99 $val = $this->parseScalar( $tokens[$i] );
101 wfSuppressWarnings();
102 $buildval[$key] = $val;
104 while ( isset( $skipTypes[$tokens[++$i][0]] ) ) {
107 if ( $tokens[$i] === ',' ) {
109 } elseif ( $tokens[$i] === ')' ) {
112 throw $this->except( $tokens[$i], ', or )' );
116 throw $this->except( $tokens[$i], 'scalar or array' );
118 if ( is_null( $varindex ) ) {
119 $this->vars[$varname] = $buildval;
121 wfSuppressWarnings();
122 $this->vars[$varname][$varindex] = $buildval;
125 while ( isset( $skipTypes[$tokens[++$i][0]] ) ) {
127 if ( $tokens[$i] !== ';' ) {
128 throw $this->except( $tokens[$i], ';' );
133 throw $this->except( $tokens[$i], 'open tag, whitespace, or variable.' );
140 * @param $expected string
143 private function except( $got, $expected ) {
144 if ( is_array( $got ) ) {
145 $got = token_name( $got[0] ) . " ('" . $got[1] . "')";
147 $got = "'" . $got . "'";
150 return new Exception( "Expected $expected, got $got" );
154 * Parse a scalar value in PHP
156 * @param $token string
158 * @return mixed Parsed value
160 function parseScalar( $token ) {
161 if ( is_array( $token ) ) {
166 if ( $str !== '' && $str[0] == '\'' ) {
167 // Single-quoted string
168 // @fixme trim() call is due to mystery bug where whitespace gets
169 // appended to the token; without it we ended up reading in the
170 // extra quote on the end!
171 return strtr( substr( trim( $str ), 1, -1 ),
172 [ '\\\'' => '\'', '\\\\' => '\\' ] );
175 wfSuppressWarnings();
176 if ( $str !== '' && $str[0] == '"' ) {
177 // Double-quoted string
178 // @fixme trim() call is due to mystery bug where whitespace gets
179 // appended to the token; without it we ended up reading in the
180 // extra quote on the end!
182 return stripcslashes( substr( trim( $str ), 1, -1 ) );
186 if ( substr( $str, 0, 4 ) === 'true' ) {
190 if ( substr( $str, 0, 5 ) === 'false' ) {
194 if ( substr( $str, 0, 4 ) === 'null' ) {
198 // Must be some kind of numeric value, so let PHP's weak typing
199 // be useful for a change
204 * @param $varname string
205 * @return null|string
207 function getVar( $varname ) {
208 if ( isset( $this->vars[$varname] ) ) {
209 return $this->vars[$varname];