Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.
Common duplication problems, and corresponding solutions are:
Complex classes like Parser often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
While breaking up the class, it is a good idea to analyze how other classes use Parser, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
31 | class Parser |
||
32 | { |
||
33 | /** Constants */ |
||
34 | // Sheet title in unquoted form |
||
35 | // Invalid sheet title characters cannot occur in the sheet title: |
||
36 | // *:/\?[] |
||
|
|||
37 | // Moreover, there are valid sheet title characters that cannot occur in unquoted form (there may be more?) |
||
38 | // +-% '^&<>=,;#()"{} |
||
39 | const REGEX_SHEET_TITLE_UNQUOTED = '[^\*\:\/\\\\\?\[\]\+\-\% \\\'\^\&\<\>\=\,\;\#\(\)\"\{\}]+'; |
||
40 | |||
41 | // Sheet title in quoted form (without surrounding quotes) |
||
42 | // Invalid sheet title characters cannot occur in the sheet title: |
||
43 | // *:/\?[] (usual invalid sheet title characters) |
||
44 | // Single quote is represented as a pair '' |
||
45 | const REGEX_SHEET_TITLE_QUOTED = '(([^\*\:\/\\\\\?\[\]\\\'])+|(\\\'\\\')+)+'; |
||
46 | |||
47 | /** |
||
48 | * The index of the character we are currently looking at. |
||
49 | * |
||
50 | * @var int |
||
51 | */ |
||
52 | public $currentCharacter; |
||
53 | |||
54 | /** |
||
55 | * The token we are working on. |
||
56 | * |
||
57 | * @var string |
||
58 | */ |
||
59 | public $currentToken; |
||
60 | |||
61 | /** |
||
62 | * The formula to parse. |
||
63 | * |
||
64 | * @var string |
||
65 | */ |
||
66 | private $formula; |
||
67 | |||
68 | /** |
||
69 | * The character ahead of the current char. |
||
70 | * |
||
71 | * @var string |
||
72 | */ |
||
73 | public $lookAhead; |
||
74 | |||
75 | /** |
||
76 | * The parse tree to be generated. |
||
77 | * |
||
78 | * @var string |
||
79 | */ |
||
80 | private $parseTree; |
||
81 | |||
82 | /** |
||
83 | * Array of external sheets. |
||
84 | * |
||
85 | * @var array |
||
86 | */ |
||
87 | private $externalSheets; |
||
88 | |||
89 | /** |
||
90 | * Array of sheet references in the form of REF structures. |
||
91 | * |
||
92 | * @var array |
||
93 | */ |
||
94 | public $references; |
||
95 | |||
96 | /** |
||
97 | * The Excel ptg indices. |
||
98 | * |
||
99 | * @var array |
||
100 | */ |
||
101 | private $ptg = [ |
||
102 | 'ptgExp' => 0x01, |
||
103 | 'ptgTbl' => 0x02, |
||
104 | 'ptgAdd' => 0x03, |
||
105 | 'ptgSub' => 0x04, |
||
106 | 'ptgMul' => 0x05, |
||
107 | 'ptgDiv' => 0x06, |
||
108 | 'ptgPower' => 0x07, |
||
109 | 'ptgConcat' => 0x08, |
||
110 | 'ptgLT' => 0x09, |
||
111 | 'ptgLE' => 0x0A, |
||
112 | 'ptgEQ' => 0x0B, |
||
113 | 'ptgGE' => 0x0C, |
||
114 | 'ptgGT' => 0x0D, |
||
115 | 'ptgNE' => 0x0E, |
||
116 | 'ptgIsect' => 0x0F, |
||
117 | 'ptgUnion' => 0x10, |
||
118 | 'ptgRange' => 0x11, |
||
119 | 'ptgUplus' => 0x12, |
||
120 | 'ptgUminus' => 0x13, |
||
121 | 'ptgPercent' => 0x14, |
||
122 | 'ptgParen' => 0x15, |
||
123 | 'ptgMissArg' => 0x16, |
||
124 | 'ptgStr' => 0x17, |
||
125 | 'ptgAttr' => 0x19, |
||
126 | 'ptgSheet' => 0x1A, |
||
127 | 'ptgEndSheet' => 0x1B, |
||
128 | 'ptgErr' => 0x1C, |
||
129 | 'ptgBool' => 0x1D, |
||
130 | 'ptgInt' => 0x1E, |
||
131 | 'ptgNum' => 0x1F, |
||
132 | 'ptgArray' => 0x20, |
||
133 | 'ptgFunc' => 0x21, |
||
134 | 'ptgFuncVar' => 0x22, |
||
135 | 'ptgName' => 0x23, |
||
136 | 'ptgRef' => 0x24, |
||
137 | 'ptgArea' => 0x25, |
||
138 | 'ptgMemArea' => 0x26, |
||
139 | 'ptgMemErr' => 0x27, |
||
140 | 'ptgMemNoMem' => 0x28, |
||
141 | 'ptgMemFunc' => 0x29, |
||
142 | 'ptgRefErr' => 0x2A, |
||
143 | 'ptgAreaErr' => 0x2B, |
||
144 | 'ptgRefN' => 0x2C, |
||
145 | 'ptgAreaN' => 0x2D, |
||
146 | 'ptgMemAreaN' => 0x2E, |
||
147 | 'ptgMemNoMemN' => 0x2F, |
||
148 | 'ptgNameX' => 0x39, |
||
149 | 'ptgRef3d' => 0x3A, |
||
150 | 'ptgArea3d' => 0x3B, |
||
151 | 'ptgRefErr3d' => 0x3C, |
||
152 | 'ptgAreaErr3d' => 0x3D, |
||
153 | 'ptgArrayV' => 0x40, |
||
154 | 'ptgFuncV' => 0x41, |
||
155 | 'ptgFuncVarV' => 0x42, |
||
156 | 'ptgNameV' => 0x43, |
||
157 | 'ptgRefV' => 0x44, |
||
158 | 'ptgAreaV' => 0x45, |
||
159 | 'ptgMemAreaV' => 0x46, |
||
160 | 'ptgMemErrV' => 0x47, |
||
161 | 'ptgMemNoMemV' => 0x48, |
||
162 | 'ptgMemFuncV' => 0x49, |
||
163 | 'ptgRefErrV' => 0x4A, |
||
164 | 'ptgAreaErrV' => 0x4B, |
||
165 | 'ptgRefNV' => 0x4C, |
||
166 | 'ptgAreaNV' => 0x4D, |
||
167 | 'ptgMemAreaNV' => 0x4E, |
||
168 | 'ptgMemNoMemNV' => 0x4F, |
||
169 | 'ptgFuncCEV' => 0x58, |
||
170 | 'ptgNameXV' => 0x59, |
||
171 | 'ptgRef3dV' => 0x5A, |
||
172 | 'ptgArea3dV' => 0x5B, |
||
173 | 'ptgRefErr3dV' => 0x5C, |
||
174 | 'ptgAreaErr3dV' => 0x5D, |
||
175 | 'ptgArrayA' => 0x60, |
||
176 | 'ptgFuncA' => 0x61, |
||
177 | 'ptgFuncVarA' => 0x62, |
||
178 | 'ptgNameA' => 0x63, |
||
179 | 'ptgRefA' => 0x64, |
||
180 | 'ptgAreaA' => 0x65, |
||
181 | 'ptgMemAreaA' => 0x66, |
||
182 | 'ptgMemErrA' => 0x67, |
||
183 | 'ptgMemNoMemA' => 0x68, |
||
184 | 'ptgMemFuncA' => 0x69, |
||
185 | 'ptgRefErrA' => 0x6A, |
||
186 | 'ptgAreaErrA' => 0x6B, |
||
187 | 'ptgRefNA' => 0x6C, |
||
188 | 'ptgAreaNA' => 0x6D, |
||
189 | 'ptgMemAreaNA' => 0x6E, |
||
190 | 'ptgMemNoMemNA' => 0x6F, |
||
191 | 'ptgFuncCEA' => 0x78, |
||
192 | 'ptgNameXA' => 0x79, |
||
193 | 'ptgRef3dA' => 0x7A, |
||
194 | 'ptgArea3dA' => 0x7B, |
||
195 | 'ptgRefErr3dA' => 0x7C, |
||
196 | 'ptgAreaErr3dA' => 0x7D, |
||
197 | ]; |
||
198 | |||
199 | /** |
||
200 | * Thanks to Michael Meeks and Gnumeric for the initial arg values. |
||
201 | * |
||
202 | * The following hash was generated by "function_locale.pl" in the distro. |
||
203 | * Refer to function_locale.pl for non-English function names. |
||
204 | * |
||
205 | * The array elements are as follow: |
||
206 | * ptg: The Excel function ptg code. |
||
207 | * args: The number of arguments that the function takes: |
||
208 | * >=0 is a fixed number of arguments. |
||
209 | * -1 is a variable number of arguments. |
||
210 | * class: The reference, value or array class of the function args. |
||
211 | * vol: The function is volatile. |
||
212 | * |
||
213 | * @var array |
||
214 | */ |
||
215 | private $functions = [ |
||
216 | // function ptg args class vol |
||
217 | 'COUNT' => [0, -1, 0, 0], |
||
218 | 'IF' => [1, -1, 1, 0], |
||
219 | 'ISNA' => [2, 1, 1, 0], |
||
220 | 'ISERROR' => [3, 1, 1, 0], |
||
221 | 'SUM' => [4, -1, 0, 0], |
||
222 | 'AVERAGE' => [5, -1, 0, 0], |
||
223 | 'MIN' => [6, -1, 0, 0], |
||
224 | 'MAX' => [7, -1, 0, 0], |
||
225 | 'ROW' => [8, -1, 0, 0], |
||
226 | 'COLUMN' => [9, -1, 0, 0], |
||
227 | 'NA' => [10, 0, 0, 0], |
||
228 | 'NPV' => [11, -1, 1, 0], |
||
229 | 'STDEV' => [12, -1, 0, 0], |
||
230 | 'DOLLAR' => [13, -1, 1, 0], |
||
231 | 'FIXED' => [14, -1, 1, 0], |
||
232 | 'SIN' => [15, 1, 1, 0], |
||
233 | 'COS' => [16, 1, 1, 0], |
||
234 | 'TAN' => [17, 1, 1, 0], |
||
235 | 'ATAN' => [18, 1, 1, 0], |
||
236 | 'PI' => [19, 0, 1, 0], |
||
237 | 'SQRT' => [20, 1, 1, 0], |
||
238 | 'EXP' => [21, 1, 1, 0], |
||
239 | 'LN' => [22, 1, 1, 0], |
||
240 | 'LOG10' => [23, 1, 1, 0], |
||
241 | 'ABS' => [24, 1, 1, 0], |
||
242 | 'INT' => [25, 1, 1, 0], |
||
243 | 'SIGN' => [26, 1, 1, 0], |
||
244 | 'ROUND' => [27, 2, 1, 0], |
||
245 | 'LOOKUP' => [28, -1, 0, 0], |
||
246 | 'INDEX' => [29, -1, 0, 1], |
||
247 | 'REPT' => [30, 2, 1, 0], |
||
248 | 'MID' => [31, 3, 1, 0], |
||
249 | 'LEN' => [32, 1, 1, 0], |
||
250 | 'VALUE' => [33, 1, 1, 0], |
||
251 | 'TRUE' => [34, 0, 1, 0], |
||
252 | 'FALSE' => [35, 0, 1, 0], |
||
253 | 'AND' => [36, -1, 0, 0], |
||
254 | 'OR' => [37, -1, 0, 0], |
||
255 | 'NOT' => [38, 1, 1, 0], |
||
256 | 'MOD' => [39, 2, 1, 0], |
||
257 | 'DCOUNT' => [40, 3, 0, 0], |
||
258 | 'DSUM' => [41, 3, 0, 0], |
||
259 | 'DAVERAGE' => [42, 3, 0, 0], |
||
260 | 'DMIN' => [43, 3, 0, 0], |
||
261 | 'DMAX' => [44, 3, 0, 0], |
||
262 | 'DSTDEV' => [45, 3, 0, 0], |
||
263 | 'VAR' => [46, -1, 0, 0], |
||
264 | 'DVAR' => [47, 3, 0, 0], |
||
265 | 'TEXT' => [48, 2, 1, 0], |
||
266 | 'LINEST' => [49, -1, 0, 0], |
||
267 | 'TREND' => [50, -1, 0, 0], |
||
268 | 'LOGEST' => [51, -1, 0, 0], |
||
269 | 'GROWTH' => [52, -1, 0, 0], |
||
270 | 'PV' => [56, -1, 1, 0], |
||
271 | 'FV' => [57, -1, 1, 0], |
||
272 | 'NPER' => [58, -1, 1, 0], |
||
273 | 'PMT' => [59, -1, 1, 0], |
||
274 | 'RATE' => [60, -1, 1, 0], |
||
275 | 'MIRR' => [61, 3, 0, 0], |
||
276 | 'IRR' => [62, -1, 0, 0], |
||
277 | 'RAND' => [63, 0, 1, 1], |
||
278 | 'MATCH' => [64, -1, 0, 0], |
||
279 | 'DATE' => [65, 3, 1, 0], |
||
280 | 'TIME' => [66, 3, 1, 0], |
||
281 | 'DAY' => [67, 1, 1, 0], |
||
282 | 'MONTH' => [68, 1, 1, 0], |
||
283 | 'YEAR' => [69, 1, 1, 0], |
||
284 | 'WEEKDAY' => [70, -1, 1, 0], |
||
285 | 'HOUR' => [71, 1, 1, 0], |
||
286 | 'MINUTE' => [72, 1, 1, 0], |
||
287 | 'SECOND' => [73, 1, 1, 0], |
||
288 | 'NOW' => [74, 0, 1, 1], |
||
289 | 'AREAS' => [75, 1, 0, 1], |
||
290 | 'ROWS' => [76, 1, 0, 1], |
||
291 | 'COLUMNS' => [77, 1, 0, 1], |
||
292 | 'OFFSET' => [78, -1, 0, 1], |
||
293 | 'SEARCH' => [82, -1, 1, 0], |
||
294 | 'TRANSPOSE' => [83, 1, 1, 0], |
||
295 | 'TYPE' => [86, 1, 1, 0], |
||
296 | 'ATAN2' => [97, 2, 1, 0], |
||
297 | 'ASIN' => [98, 1, 1, 0], |
||
298 | 'ACOS' => [99, 1, 1, 0], |
||
299 | 'CHOOSE' => [100, -1, 1, 0], |
||
300 | 'HLOOKUP' => [101, -1, 0, 0], |
||
301 | 'VLOOKUP' => [102, -1, 0, 0], |
||
302 | 'ISREF' => [105, 1, 0, 0], |
||
303 | 'LOG' => [109, -1, 1, 0], |
||
304 | 'CHAR' => [111, 1, 1, 0], |
||
305 | 'LOWER' => [112, 1, 1, 0], |
||
306 | 'UPPER' => [113, 1, 1, 0], |
||
307 | 'PROPER' => [114, 1, 1, 0], |
||
308 | 'LEFT' => [115, -1, 1, 0], |
||
309 | 'RIGHT' => [116, -1, 1, 0], |
||
310 | 'EXACT' => [117, 2, 1, 0], |
||
311 | 'TRIM' => [118, 1, 1, 0], |
||
312 | 'REPLACE' => [119, 4, 1, 0], |
||
313 | 'SUBSTITUTE' => [120, -1, 1, 0], |
||
314 | 'CODE' => [121, 1, 1, 0], |
||
315 | 'FIND' => [124, -1, 1, 0], |
||
316 | 'CELL' => [125, -1, 0, 1], |
||
317 | 'ISERR' => [126, 1, 1, 0], |
||
318 | 'ISTEXT' => [127, 1, 1, 0], |
||
319 | 'ISNUMBER' => [128, 1, 1, 0], |
||
320 | 'ISBLANK' => [129, 1, 1, 0], |
||
321 | 'T' => [130, 1, 0, 0], |
||
322 | 'N' => [131, 1, 0, 0], |
||
323 | 'DATEVALUE' => [140, 1, 1, 0], |
||
324 | 'TIMEVALUE' => [141, 1, 1, 0], |
||
325 | 'SLN' => [142, 3, 1, 0], |
||
326 | 'SYD' => [143, 4, 1, 0], |
||
327 | 'DDB' => [144, -1, 1, 0], |
||
328 | 'INDIRECT' => [148, -1, 1, 1], |
||
329 | 'CALL' => [150, -1, 1, 0], |
||
330 | 'CLEAN' => [162, 1, 1, 0], |
||
331 | 'MDETERM' => [163, 1, 2, 0], |
||
332 | 'MINVERSE' => [164, 1, 2, 0], |
||
333 | 'MMULT' => [165, 2, 2, 0], |
||
334 | 'IPMT' => [167, -1, 1, 0], |
||
335 | 'PPMT' => [168, -1, 1, 0], |
||
336 | 'COUNTA' => [169, -1, 0, 0], |
||
337 | 'PRODUCT' => [183, -1, 0, 0], |
||
338 | 'FACT' => [184, 1, 1, 0], |
||
339 | 'DPRODUCT' => [189, 3, 0, 0], |
||
340 | 'ISNONTEXT' => [190, 1, 1, 0], |
||
341 | 'STDEVP' => [193, -1, 0, 0], |
||
342 | 'VARP' => [194, -1, 0, 0], |
||
343 | 'DSTDEVP' => [195, 3, 0, 0], |
||
344 | 'DVARP' => [196, 3, 0, 0], |
||
345 | 'TRUNC' => [197, -1, 1, 0], |
||
346 | 'ISLOGICAL' => [198, 1, 1, 0], |
||
347 | 'DCOUNTA' => [199, 3, 0, 0], |
||
348 | 'USDOLLAR' => [204, -1, 1, 0], |
||
349 | 'FINDB' => [205, -1, 1, 0], |
||
350 | 'SEARCHB' => [206, -1, 1, 0], |
||
351 | 'REPLACEB' => [207, 4, 1, 0], |
||
352 | 'LEFTB' => [208, -1, 1, 0], |
||
353 | 'RIGHTB' => [209, -1, 1, 0], |
||
354 | 'MIDB' => [210, 3, 1, 0], |
||
355 | 'LENB' => [211, 1, 1, 0], |
||
356 | 'ROUNDUP' => [212, 2, 1, 0], |
||
357 | 'ROUNDDOWN' => [213, 2, 1, 0], |
||
358 | 'ASC' => [214, 1, 1, 0], |
||
359 | 'DBCS' => [215, 1, 1, 0], |
||
360 | 'RANK' => [216, -1, 0, 0], |
||
361 | 'ADDRESS' => [219, -1, 1, 0], |
||
362 | 'DAYS360' => [220, -1, 1, 0], |
||
363 | 'TODAY' => [221, 0, 1, 1], |
||
364 | 'VDB' => [222, -1, 1, 0], |
||
365 | 'MEDIAN' => [227, -1, 0, 0], |
||
366 | 'SUMPRODUCT' => [228, -1, 2, 0], |
||
367 | 'SINH' => [229, 1, 1, 0], |
||
368 | 'COSH' => [230, 1, 1, 0], |
||
369 | 'TANH' => [231, 1, 1, 0], |
||
370 | 'ASINH' => [232, 1, 1, 0], |
||
371 | 'ACOSH' => [233, 1, 1, 0], |
||
372 | 'ATANH' => [234, 1, 1, 0], |
||
373 | 'DGET' => [235, 3, 0, 0], |
||
374 | 'INFO' => [244, 1, 1, 1], |
||
375 | 'DB' => [247, -1, 1, 0], |
||
376 | 'FREQUENCY' => [252, 2, 0, 0], |
||
377 | 'ERROR.TYPE' => [261, 1, 1, 0], |
||
378 | 'REGISTER.ID' => [267, -1, 1, 0], |
||
379 | 'AVEDEV' => [269, -1, 0, 0], |
||
380 | 'BETADIST' => [270, -1, 1, 0], |
||
381 | 'GAMMALN' => [271, 1, 1, 0], |
||
382 | 'BETAINV' => [272, -1, 1, 0], |
||
383 | 'BINOMDIST' => [273, 4, 1, 0], |
||
384 | 'CHIDIST' => [274, 2, 1, 0], |
||
385 | 'CHIINV' => [275, 2, 1, 0], |
||
386 | 'COMBIN' => [276, 2, 1, 0], |
||
387 | 'CONFIDENCE' => [277, 3, 1, 0], |
||
388 | 'CRITBINOM' => [278, 3, 1, 0], |
||
389 | 'EVEN' => [279, 1, 1, 0], |
||
390 | 'EXPONDIST' => [280, 3, 1, 0], |
||
391 | 'FDIST' => [281, 3, 1, 0], |
||
392 | 'FINV' => [282, 3, 1, 0], |
||
393 | 'FISHER' => [283, 1, 1, 0], |
||
394 | 'FISHERINV' => [284, 1, 1, 0], |
||
395 | 'FLOOR' => [285, 2, 1, 0], |
||
396 | 'GAMMADIST' => [286, 4, 1, 0], |
||
397 | 'GAMMAINV' => [287, 3, 1, 0], |
||
398 | 'CEILING' => [288, 2, 1, 0], |
||
399 | 'HYPGEOMDIST' => [289, 4, 1, 0], |
||
400 | 'LOGNORMDIST' => [290, 3, 1, 0], |
||
401 | 'LOGINV' => [291, 3, 1, 0], |
||
402 | 'NEGBINOMDIST' => [292, 3, 1, 0], |
||
403 | 'NORMDIST' => [293, 4, 1, 0], |
||
404 | 'NORMSDIST' => [294, 1, 1, 0], |
||
405 | 'NORMINV' => [295, 3, 1, 0], |
||
406 | 'NORMSINV' => [296, 1, 1, 0], |
||
407 | 'STANDARDIZE' => [297, 3, 1, 0], |
||
408 | 'ODD' => [298, 1, 1, 0], |
||
409 | 'PERMUT' => [299, 2, 1, 0], |
||
410 | 'POISSON' => [300, 3, 1, 0], |
||
411 | 'TDIST' => [301, 3, 1, 0], |
||
412 | 'WEIBULL' => [302, 4, 1, 0], |
||
413 | 'SUMXMY2' => [303, 2, 2, 0], |
||
414 | 'SUMX2MY2' => [304, 2, 2, 0], |
||
415 | 'SUMX2PY2' => [305, 2, 2, 0], |
||
416 | 'CHITEST' => [306, 2, 2, 0], |
||
417 | 'CORREL' => [307, 2, 2, 0], |
||
418 | 'COVAR' => [308, 2, 2, 0], |
||
419 | 'FORECAST' => [309, 3, 2, 0], |
||
420 | 'FTEST' => [310, 2, 2, 0], |
||
421 | 'INTERCEPT' => [311, 2, 2, 0], |
||
422 | 'PEARSON' => [312, 2, 2, 0], |
||
423 | 'RSQ' => [313, 2, 2, 0], |
||
424 | 'STEYX' => [314, 2, 2, 0], |
||
425 | 'SLOPE' => [315, 2, 2, 0], |
||
426 | 'TTEST' => [316, 4, 2, 0], |
||
427 | 'PROB' => [317, -1, 2, 0], |
||
428 | 'DEVSQ' => [318, -1, 0, 0], |
||
429 | 'GEOMEAN' => [319, -1, 0, 0], |
||
430 | 'HARMEAN' => [320, -1, 0, 0], |
||
431 | 'SUMSQ' => [321, -1, 0, 0], |
||
432 | 'KURT' => [322, -1, 0, 0], |
||
433 | 'SKEW' => [323, -1, 0, 0], |
||
434 | 'ZTEST' => [324, -1, 0, 0], |
||
435 | 'LARGE' => [325, 2, 0, 0], |
||
436 | 'SMALL' => [326, 2, 0, 0], |
||
437 | 'QUARTILE' => [327, 2, 0, 0], |
||
438 | 'PERCENTILE' => [328, 2, 0, 0], |
||
439 | 'PERCENTRANK' => [329, -1, 0, 0], |
||
440 | 'MODE' => [330, -1, 2, 0], |
||
441 | 'TRIMMEAN' => [331, 2, 0, 0], |
||
442 | 'TINV' => [332, 2, 1, 0], |
||
443 | 'CONCATENATE' => [336, -1, 1, 0], |
||
444 | 'POWER' => [337, 2, 1, 0], |
||
445 | 'RADIANS' => [342, 1, 1, 0], |
||
446 | 'DEGREES' => [343, 1, 1, 0], |
||
447 | 'SUBTOTAL' => [344, -1, 0, 0], |
||
448 | 'SUMIF' => [345, -1, 0, 0], |
||
449 | 'COUNTIF' => [346, 2, 0, 0], |
||
450 | 'COUNTBLANK' => [347, 1, 0, 0], |
||
451 | 'ISPMT' => [350, 4, 1, 0], |
||
452 | 'DATEDIF' => [351, 3, 1, 0], |
||
453 | 'DATESTRING' => [352, 1, 1, 0], |
||
454 | 'NUMBERSTRING' => [353, 2, 1, 0], |
||
455 | 'ROMAN' => [354, -1, 1, 0], |
||
456 | 'GETPIVOTDATA' => [358, -1, 0, 0], |
||
457 | 'HYPERLINK' => [359, -1, 1, 0], |
||
458 | 'PHONETIC' => [360, 1, 0, 0], |
||
459 | 'AVERAGEA' => [361, -1, 0, 0], |
||
460 | 'MAXA' => [362, -1, 0, 0], |
||
461 | 'MINA' => [363, -1, 0, 0], |
||
462 | 'STDEVPA' => [364, -1, 0, 0], |
||
463 | 'VARPA' => [365, -1, 0, 0], |
||
464 | 'STDEVA' => [366, -1, 0, 0], |
||
465 | 'VARA' => [367, -1, 0, 0], |
||
466 | 'BAHTTEXT' => [368, 1, 0, 0], |
||
467 | ]; |
||
468 | |||
469 | /** |
||
470 | * The class constructor. |
||
471 | */ |
||
472 | 48 | public function __construct() |
|
473 | { |
||
474 | 48 | $this->currentCharacter = 0; |
|
475 | 48 | $this->currentToken = ''; // The token we are working on. |
|
476 | 48 | $this->formula = ''; // The formula to parse. |
|
477 | 48 | $this->lookAhead = ''; // The character ahead of the current char. |
|
478 | 48 | $this->parseTree = ''; // The parse tree to be generated. |
|
479 | 48 | $this->externalSheets = []; |
|
480 | 48 | $this->references = []; |
|
481 | 48 | } |
|
482 | |||
483 | /** |
||
484 | * Convert a token to the proper ptg value. |
||
485 | * |
||
486 | * @param mixed $token the token to convert |
||
487 | * |
||
488 | * @return mixed the converted token on success |
||
489 | */ |
||
490 | 18 | private function convert($token) |
|
533 | |||
534 | /** |
||
535 | * Convert a number token to ptgInt or ptgNum. |
||
536 | * |
||
537 | * @param mixed $num an integer or double for conversion to its ptg value |
||
538 | */ |
||
539 | 15 | private function convertNumber($num) |
|
553 | |||
554 | /** |
||
555 | * Convert a string token to ptgStr. |
||
556 | * |
||
557 | * @param string $string a string for conversion to its ptg value |
||
558 | * |
||
559 | * @return mixed the converted token on success |
||
560 | */ |
||
561 | 9 | private function convertString($string) |
|
571 | |||
572 | /** |
||
573 | * Convert a function to a ptgFunc or ptgFuncVarV depending on the number of |
||
574 | * args that it takes. |
||
575 | * |
||
576 | * @param string $token the name of the function for convertion to ptg value |
||
577 | * @param int $num_args the number of arguments the function receives |
||
578 | * |
||
579 | * @return string The packed ptg for the function |
||
580 | */ |
||
581 | 15 | private function convertFunction($token, $num_args) |
|
594 | |||
595 | /** |
||
596 | * Convert an Excel range such as A1:D4 to a ptgRefV. |
||
597 | * |
||
598 | * @param string $range An Excel range in the A1:A2 |
||
599 | * @param int $class |
||
600 | */ |
||
601 | 15 | private function convertRange2d($range, $class = 0) |
|
630 | |||
631 | /** |
||
632 | * Convert an Excel 3d range such as "Sheet1!A1:D4" or "Sheet1:Sheet2!A1:D4" to |
||
633 | * a ptgArea3d. |
||
634 | * |
||
635 | * @param string $token an Excel range in the Sheet1!A1:A2 format |
||
636 | * |
||
637 | * @return mixed the packed ptgArea3d token on success |
||
638 | */ |
||
639 | 3 | private function convertRange3d($token) |
|
663 | |||
664 | /** |
||
665 | * Convert an Excel reference such as A1, $B2, C$3 or $D$4 to a ptgRefV. |
||
666 | * |
||
667 | * @param string $cell An Excel cell reference |
||
668 | * |
||
669 | * @return string The cell in packed() format with the corresponding ptg |
||
670 | */ |
||
671 | 12 | private function convertRef2d($cell) |
|
682 | |||
683 | /** |
||
684 | * Convert an Excel 3d reference such as "Sheet1!A1" or "Sheet1:Sheet2!A1" to a |
||
685 | * ptgRef3d. |
||
686 | * |
||
687 | * @param string $cell An Excel cell reference |
||
688 | * |
||
689 | * @return mixed the packed ptgRef3d token on success |
||
690 | */ |
||
691 | 1 | private function convertRef3d($cell) |
|
707 | |||
708 | /** |
||
709 | * Convert an error code to a ptgErr. |
||
710 | * |
||
711 | * @param string $errorCode The error code for conversion to its ptg value |
||
712 | * |
||
713 | * @return string The error code ptgErr |
||
714 | */ |
||
715 | private function convertError($errorCode) |
||
736 | |||
737 | /** |
||
738 | * Look up the REF index that corresponds to an external sheet name |
||
739 | * (or range). If it doesn't exist yet add it to the workbook's references |
||
740 | * array. It assumes all sheet names given must exist. |
||
741 | * |
||
742 | * @param string $ext_ref The name of the external reference |
||
743 | * |
||
744 | * @return mixed The reference index in packed() format on success |
||
745 | */ |
||
746 | 4 | private function getRefIndex($ext_ref) |
|
797 | |||
798 | /** |
||
799 | * Look up the index that corresponds to an external sheet name. The hash of |
||
800 | * sheet names is updated by the addworksheet() method of the |
||
801 | * \PhpOffice\PhpSpreadsheet\Writer\Xls\Workbook class. |
||
802 | * |
||
803 | * @param string $sheet_name Sheet name |
||
804 | * |
||
805 | * @return int The sheet index, -1 if the sheet was not found |
||
806 | */ |
||
807 | 4 | private function getSheetIndex($sheet_name) |
|
815 | |||
816 | /** |
||
817 | * This method is used to update the array of sheet names. It is |
||
818 | * called by the addWorksheet() method of the |
||
819 | * \PhpOffice\PhpSpreadsheet\Writer\Xls\Workbook class. |
||
820 | * |
||
821 | * @see \PhpOffice\PhpSpreadsheet\Writer\Xls\Workbook::addWorksheet() |
||
822 | * |
||
823 | * @param string $name The name of the worksheet being added |
||
824 | * @param int $index The index of the worksheet being added |
||
825 | */ |
||
826 | 48 | public function setExtSheet($name, $index) |
|
830 | |||
831 | /** |
||
832 | * pack() row and column into the required 3 or 4 byte format. |
||
833 | * |
||
834 | * @param string $cell The Excel cell reference to be packed |
||
835 | * |
||
836 | * @return array Array containing the row and column in packed() format |
||
837 | */ |
||
838 | 17 | private function cellToPackedRowcol($cell) |
|
858 | |||
859 | /** |
||
860 | * pack() row range into the required 3 or 4 byte format. |
||
861 | * Just using maximum col/rows, which is probably not the correct solution. |
||
862 | * |
||
863 | * @param string $range The Excel range to be packed |
||
864 | * |
||
865 | * @return array Array containing (row1,col1,row2,col2) in packed() format |
||
866 | */ |
||
867 | private function rangeToPackedRange($range) |
||
898 | |||
899 | /** |
||
900 | * Convert an Excel cell reference such as A1 or $B2 or C$3 or $D$4 to a zero |
||
901 | * indexed row and column number. Also returns two (0,1) values to indicate |
||
902 | * whether the row or column are relative references. |
||
903 | * |
||
904 | * @param string $cell the Excel cell reference in A1 format |
||
905 | * |
||
906 | * @return array |
||
907 | */ |
||
908 | 17 | private function cellToRowcol($cell) |
|
932 | |||
933 | /** |
||
934 | * Advance to the next valid token. |
||
935 | */ |
||
936 | 18 | private function advance() |
|
977 | |||
978 | /** |
||
979 | * Checks if it's a valid token. |
||
980 | * |
||
981 | * @param mixed $token the token to check |
||
982 | * |
||
983 | * @return mixed The checked token or false on failure |
||
984 | */ |
||
985 | 18 | private function match($token) |
|
1060 | |||
1061 | /** |
||
1062 | * The parsing method. It parses a formula. |
||
1063 | * |
||
1064 | * @param string $formula the formula to parse, without the initial equal |
||
1065 | * sign (=) |
||
1066 | * |
||
1067 | * @return mixed true on success |
||
1068 | */ |
||
1069 | 18 | public function parse($formula) |
|
1080 | |||
1081 | /** |
||
1082 | * It parses a condition. It assumes the following rule: |
||
1083 | * Cond -> Expr [(">" | "<") Expr]. |
||
1084 | * |
||
1085 | * @return mixed The parsed ptg'd tree on success |
||
1086 | */ |
||
1087 | 18 | private function condition() |
|
1122 | |||
1123 | /** |
||
1124 | * It parses a expression. It assumes the following rule: |
||
1125 | * Expr -> Term [("+" | "-") Term] |
||
1126 | * -> "string" |
||
1127 | * -> "-" Term : Negative value |
||
1128 | * -> "+" Term : Positive value |
||
1129 | * -> Error code. |
||
1130 | * |
||
1131 | * @return mixed The parsed ptg'd tree on success |
||
1132 | */ |
||
1133 | 18 | private function expression() |
|
1190 | |||
1191 | /** |
||
1192 | * This function just introduces a ptgParen element in the tree, so that Excel |
||
1193 | * doesn't get confused when working with a parenthesized formula afterwards. |
||
1194 | * |
||
1195 | * @see fact() |
||
1196 | * |
||
1197 | * @return array The parsed ptg'd tree |
||
1198 | */ |
||
1199 | 1 | private function parenthesizedExpression() |
|
1205 | |||
1206 | /** |
||
1207 | * It parses a term. It assumes the following rule: |
||
1208 | * Term -> Fact [("*" | "/") Fact]. |
||
1209 | * |
||
1210 | * @return mixed The parsed ptg'd tree on success |
||
1211 | */ |
||
1212 | 18 | private function term() |
|
1230 | |||
1231 | /** |
||
1232 | * It parses a factor. It assumes the following rule: |
||
1233 | * Fact -> ( Expr ) |
||
1234 | * | CellRef |
||
1235 | * | CellRange |
||
1236 | * | Number |
||
1237 | * | Function. |
||
1238 | * |
||
1239 | * @return mixed The parsed ptg'd tree on success |
||
1240 | */ |
||
1241 | 18 | private function fact() |
|
1312 | |||
1313 | /** |
||
1314 | * It parses a function call. It assumes the following rule: |
||
1315 | * Func -> ( Expr [,Expr]* ). |
||
1316 | * |
||
1317 | * @return mixed The parsed ptg'd tree on success |
||
1318 | */ |
||
1319 | 15 | private function func() |
|
1354 | |||
1355 | /** |
||
1356 | * Creates a tree. In fact an array which may have one or two arrays (sub-trees) |
||
1357 | * as elements. |
||
1358 | * |
||
1359 | * @param mixed $value the value of this node |
||
1360 | * @param mixed $left the left array (sub-tree) or a final node |
||
1361 | * @param mixed $right the right array (sub-tree) or a final node |
||
1362 | * |
||
1363 | * @return array A tree |
||
1364 | */ |
||
1365 | 18 | private function createTree($value, $left, $right) |
|
1369 | |||
1370 | /** |
||
1371 | * Builds a string containing the tree in reverse polish notation (What you |
||
1372 | * would use in a HP calculator stack). |
||
1373 | * The following tree:. |
||
1374 | * |
||
1375 | * + |
||
1376 | * / \ |
||
1377 | * 2 3 |
||
1378 | * |
||
1379 | * produces: "23+" |
||
1380 | * |
||
1381 | * The following tree: |
||
1382 | * |
||
1383 | * + |
||
1384 | * / \ |
||
1385 | * 3 * |
||
1386 | * / \ |
||
1387 | * 6 A1 |
||
1388 | * |
||
1389 | * produces: "36A1*+" |
||
1390 | * |
||
1391 | * In fact all operands, functions, references, etc... are written as ptg's |
||
1392 | * |
||
1393 | * @param array $tree the optional tree to convert |
||
1394 | * |
||
1395 | * @return string The tree in reverse polish notation |
||
1396 | */ |
||
1397 | 18 | public function toReversePolish($tree = []) |
|
1439 | } |
||
1440 |
Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.
The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.
This check looks for comments that seem to be mostly valid code and reports them.