comparison vendor/nikic/php-parser/doc/component/Constant_expression_evaluation.markdown @ 13:5fb285c0d0e3

Update Drupal core to 8.4.7 via Composer. Security update; I *think* we've been lucky to get away with this so far, as we don't support self-registration which seems to be used by the so-called "drupalgeddon 2" attack that 8.4.5 was vulnerable to.
author Chris Cannam
date Mon, 23 Apr 2018 09:33:26 +0100
parents
children
comparison
equal deleted inserted replaced
12:7a779792577d 13:5fb285c0d0e3
1 Constant expression evaluation
2 ==============================
3
4 Initializers for constants, properties, parameters, etc. have limited support for expressions. For
5 example:
6
7 ```php
8 <?php
9 class Test {
10 const SECONDS_IN_HOUR = 60 * 60;
11 const SECONDS_IN_DAY = 24 * self::SECONDS_IN_HOUR;
12 }
13 ```
14
15 PHP-Parser supports evaluation of such constant expressions through the `ConstExprEvaluator` class:
16
17 ```php
18 <?php
19
20 use PhpParser\{ConstExprEvaluator, ConstExprEvaluationException};
21
22 $evalutator = new ConstExprEvaluator();
23 try {
24 $value = $evalutator->evaluateSilently($someExpr);
25 } catch (ConstExprEvaluationException $e) {
26 // Either the expression contains unsupported expression types,
27 // or an error occurred during evaluation
28 }
29 ```
30
31 Error handling
32 --------------
33
34 The constant evaluator provides two methods, `evaluateDirectly()` and `evaluateSilently()`, which
35 differ in error behavior. `evaluateDirectly()` will evaluate the expression as PHP would, including
36 any generated warnings or Errors. `evaluateSilently()` will instead convert warnings and Errors into
37 a `ConstExprEvaluationException`. For example:
38
39 ```php
40 <?php
41
42 use PhpParser\{ConstExprEvaluator, ConstExprEvaluationException};
43 use PhpParser\Node\{Expr, Scalar};
44
45 $evaluator = new ConstExprEvaluator();
46
47 // 10 / 0
48 $expr = new Expr\BinaryOp\Div(new Scalar\LNumber(10), new Scalar\LNumber(0));
49
50 var_dump($evaluator->evaluateDirectly($expr)); // float(INF)
51 // Warning: Division by zero
52
53 try {
54 $evaluator->evaluateSilently($expr);
55 } catch (ConstExprEvaluationException $e) {
56 var_dump($e->getPrevious()->getMessage()); // Division by zero
57 }
58 ```
59
60 For the purposes of static analysis, you will likely want to use `evaluateSilently()` and leave
61 erroring expressions unevaluated.
62
63 Unsupported expressions and evaluator fallback
64 ----------------------------------------------
65
66 The constant expression evaluator supports all expression types that are permitted in constant
67 expressions, apart from the following:
68
69 * `Scalar\MagicConst\*`
70 * `Expr\ConstFetch` (only null/false/true are handled)
71 * `Expr\ClassConstFetch`
72
73 Handling these expression types requires non-local information, such as which global constants are
74 defined. By default, the evaluator will throw a `ConstExprEvaluationException` when it encounters
75 an unsupported expression type.
76
77 It is possible to override this behavior and support resolution for these expression types by
78 specifying an evaluation fallback function:
79
80 ```php
81 <?php
82
83 use PhpParser\{ConstExprEvaluator, ConstExprEvaluationException};
84 use PhpParser\Node\Expr;
85
86 $evalutator = new ConstExprEvaluator(function(Expr $expr) {
87 if ($expr instanceof Expr\ConstFetch) {
88 return fetchConstantSomehow($expr);
89 }
90 if ($expr instanceof Expr\ClassConstFetch) {
91 return fetchClassConstantSomehow($expr);
92 }
93 // etc.
94 throw new ConstExprEvaluationException(
95 "Expression of type {$expr->getType()} cannot be evaluated");
96 });
97
98 try {
99 $evalutator->evaluateSilently($someExpr);
100 } catch (ConstExprEvaluationException $e) {
101 // Handle exception
102 }
103 ```
104
105 Implementers are advised to ensure that evaluation of indirect constant references cannot lead to
106 infinite recursion. For example, the following code could lead to infinite recursion if constant
107 lookup is implemented naively.
108
109 ```php
110 <?php
111 class Test {
112 const A = self::B;
113 const B = self::A;
114 }
115 ```