Page Menu
Home
WickedGov Phorge
Search
Configure Global Search
Log In
Files
F4091975
ConstExprEvaluator.php
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Size
9 KB
Referenced Files
None
Subscribers
None
ConstExprEvaluator.php
View Options
<?php
namespace
PhpParser
;
use
function
array_merge
;
use
PhpParser\Node\Expr
;
use
PhpParser\Node\Scalar
;
/**
* Evaluates constant expressions.
*
* This evaluator is able to evaluate all constant expressions (as defined by PHP), which can be
* evaluated without further context. If a subexpression is not of this type, a user-provided
* fallback evaluator is invoked. To support all constant expressions that are also supported by
* PHP (and not already handled by this class), the fallback evaluator must be able to handle the
* following node types:
*
* * All Scalar\MagicConst\* nodes.
* * Expr\ConstFetch nodes. Only null/false/true are already handled by this class.
* * Expr\ClassConstFetch nodes.
*
* The fallback evaluator should throw ConstExprEvaluationException for nodes it cannot evaluate.
*
* The evaluation is dependent on runtime configuration in two respects: Firstly, floating
* point to string conversions are affected by the precision ini setting. Secondly, they are also
* affected by the LC_NUMERIC locale.
*/
class
ConstExprEvaluator
{
private
$fallbackEvaluator
;
/**
* Create a constant expression evaluator.
*
* The provided fallback evaluator is invoked whenever a subexpression cannot be evaluated. See
* class doc comment for more information.
*
* @param callable|null $fallbackEvaluator To call if subexpression cannot be evaluated
*/
public
function
__construct
(?
callable
$fallbackEvaluator
=
null
)
{
$this
->
fallbackEvaluator
=
$fallbackEvaluator
??
function
(
Expr
$expr
)
{
throw
new
ConstExprEvaluationException
(
"Expression of type {$expr->getType()} cannot be evaluated"
);
};
}
/**
* Silently evaluates a constant expression into a PHP value.
*
* Thrown Errors, warnings or notices will be converted into a ConstExprEvaluationException.
* The original source of the exception is available through getPrevious().
*
* If some part of the expression cannot be evaluated, the fallback evaluator passed to the
* constructor will be invoked. By default, if no fallback is provided, an exception of type
* ConstExprEvaluationException is thrown.
*
* See class doc comment for caveats and limitations.
*
* @param Expr $expr Constant expression to evaluate
* @return mixed Result of evaluation
*
* @throws ConstExprEvaluationException if the expression cannot be evaluated or an error occurred
*/
public
function
evaluateSilently
(
Expr
$expr
)
{
set_error_handler
(
function
(
$num
,
$str
,
$file
,
$line
)
{
throw
new
\ErrorException
(
$str
,
0
,
$num
,
$file
,
$line
);
});
try
{
return
$this
->
evaluate
(
$expr
);
}
catch
(
\Throwable
$e
)
{
if
(!
$e
instanceof
ConstExprEvaluationException
)
{
$e
=
new
ConstExprEvaluationException
(
"An error occurred during constant expression evaluation"
,
0
,
$e
);
}
throw
$e
;
}
finally
{
restore_error_handler
();
}
}
/**
* Directly evaluates a constant expression into a PHP value.
*
* May generate Error exceptions, warnings or notices. Use evaluateSilently() to convert these
* into a ConstExprEvaluationException.
*
* If some part of the expression cannot be evaluated, the fallback evaluator passed to the
* constructor will be invoked. By default, if no fallback is provided, an exception of type
* ConstExprEvaluationException is thrown.
*
* See class doc comment for caveats and limitations.
*
* @param Expr $expr Constant expression to evaluate
* @return mixed Result of evaluation
*
* @throws ConstExprEvaluationException if the expression cannot be evaluated
*/
public
function
evaluateDirectly
(
Expr
$expr
)
{
return
$this
->
evaluate
(
$expr
);
}
private
function
evaluate
(
Expr
$expr
)
{
if
(
$expr
instanceof
Scalar\LNumber
||
$expr
instanceof
Scalar\DNumber
||
$expr
instanceof
Scalar\String_
)
{
return
$expr
->
value
;
}
if
(
$expr
instanceof
Expr\Array_
)
{
return
$this
->
evaluateArray
(
$expr
);
}
// Unary operators
if
(
$expr
instanceof
Expr\UnaryPlus
)
{
return
+
$this
->
evaluate
(
$expr
->
expr
);
}
if
(
$expr
instanceof
Expr\UnaryMinus
)
{
return
-
$this
->
evaluate
(
$expr
->
expr
);
}
if
(
$expr
instanceof
Expr\BooleanNot
)
{
return
!
$this
->
evaluate
(
$expr
->
expr
);
}
if
(
$expr
instanceof
Expr\BitwiseNot
)
{
return
~
$this
->
evaluate
(
$expr
->
expr
);
}
if
(
$expr
instanceof
Expr\BinaryOp
)
{
return
$this
->
evaluateBinaryOp
(
$expr
);
}
if
(
$expr
instanceof
Expr\Ternary
)
{
return
$this
->
evaluateTernary
(
$expr
);
}
if
(
$expr
instanceof
Expr\ArrayDimFetch
&&
null
!==
$expr
->
dim
)
{
return
$this
->
evaluate
(
$expr
->
var
)[
$this
->
evaluate
(
$expr
->
dim
)];
}
if
(
$expr
instanceof
Expr\ConstFetch
)
{
return
$this
->
evaluateConstFetch
(
$expr
);
}
return
(
$this
->
fallbackEvaluator
)(
$expr
);
}
private
function
evaluateArray
(
Expr\Array_
$expr
)
{
$array
=
[];
foreach
(
$expr
->
items
as
$item
)
{
if
(
null
!==
$item
->
key
)
{
$array
[
$this
->
evaluate
(
$item
->
key
)]
=
$this
->
evaluate
(
$item
->
value
);
}
elseif
(
$item
->
unpack
)
{
$array
=
array_merge
(
$array
,
$this
->
evaluate
(
$item
->
value
));
}
else
{
$array
[]
=
$this
->
evaluate
(
$item
->
value
);
}
}
return
$array
;
}
private
function
evaluateTernary
(
Expr\Ternary
$expr
)
{
if
(
null
===
$expr
->
if
)
{
return
$this
->
evaluate
(
$expr
->
cond
)
?:
$this
->
evaluate
(
$expr
->
else
);
}
return
$this
->
evaluate
(
$expr
->
cond
)
?
$this
->
evaluate
(
$expr
->
if
)
:
$this
->
evaluate
(
$expr
->
else
);
}
private
function
evaluateBinaryOp
(
Expr\BinaryOp
$expr
)
{
if
(
$expr
instanceof
Expr\BinaryOp\Coalesce
&&
$expr
->
left
instanceof
Expr\ArrayDimFetch
)
{
// This needs to be special cased to respect BP_VAR_IS fetch semantics
return
$this
->
evaluate
(
$expr
->
left
->
var
)[
$this
->
evaluate
(
$expr
->
left
->
dim
)]
??
$this
->
evaluate
(
$expr
->
right
);
}
// The evaluate() calls are repeated in each branch, because some of the operators are
// short-circuiting and evaluating the RHS in advance may be illegal in that case
$l
=
$expr
->
left
;
$r
=
$expr
->
right
;
switch
(
$expr
->
getOperatorSigil
())
{
case
'&'
:
return
$this
->
evaluate
(
$l
)
&
$this
->
evaluate
(
$r
);
case
'|'
:
return
$this
->
evaluate
(
$l
)
|
$this
->
evaluate
(
$r
);
case
'^'
:
return
$this
->
evaluate
(
$l
)
^
$this
->
evaluate
(
$r
);
case
'&&'
:
return
$this
->
evaluate
(
$l
)
&&
$this
->
evaluate
(
$r
);
case
'||'
:
return
$this
->
evaluate
(
$l
)
||
$this
->
evaluate
(
$r
);
case
'??'
:
return
$this
->
evaluate
(
$l
)
??
$this
->
evaluate
(
$r
);
case
'.'
:
return
$this
->
evaluate
(
$l
)
.
$this
->
evaluate
(
$r
);
case
'/'
:
return
$this
->
evaluate
(
$l
)
/
$this
->
evaluate
(
$r
);
case
'=='
:
return
$this
->
evaluate
(
$l
)
==
$this
->
evaluate
(
$r
);
case
'>'
:
return
$this
->
evaluate
(
$l
)
>
$this
->
evaluate
(
$r
);
case
'>='
:
return
$this
->
evaluate
(
$l
)
>=
$this
->
evaluate
(
$r
);
case
'==='
:
return
$this
->
evaluate
(
$l
)
===
$this
->
evaluate
(
$r
);
case
'and'
:
return
$this
->
evaluate
(
$l
)
and
$this
->
evaluate
(
$r
);
case
'or'
:
return
$this
->
evaluate
(
$l
)
or
$this
->
evaluate
(
$r
);
case
'xor'
:
return
$this
->
evaluate
(
$l
)
xor
$this
->
evaluate
(
$r
);
case
'-'
:
return
$this
->
evaluate
(
$l
)
-
$this
->
evaluate
(
$r
);
case
'%'
:
return
$this
->
evaluate
(
$l
)
%
$this
->
evaluate
(
$r
);
case
'*'
:
return
$this
->
evaluate
(
$l
)
*
$this
->
evaluate
(
$r
);
case
'!='
:
return
$this
->
evaluate
(
$l
)
!=
$this
->
evaluate
(
$r
);
case
'!=='
:
return
$this
->
evaluate
(
$l
)
!==
$this
->
evaluate
(
$r
);
case
'+'
:
return
$this
->
evaluate
(
$l
)
+
$this
->
evaluate
(
$r
);
case
'**'
:
return
$this
->
evaluate
(
$l
)
**
$this
->
evaluate
(
$r
);
case
'<<'
:
return
$this
->
evaluate
(
$l
)
<<
$this
->
evaluate
(
$r
);
case
'>>'
:
return
$this
->
evaluate
(
$l
)
>>
$this
->
evaluate
(
$r
);
case
'<'
:
return
$this
->
evaluate
(
$l
)
<
$this
->
evaluate
(
$r
);
case
'<='
:
return
$this
->
evaluate
(
$l
)
<=
$this
->
evaluate
(
$r
);
case
'<=>'
:
return
$this
->
evaluate
(
$l
)
<=>
$this
->
evaluate
(
$r
);
}
throw
new
\Exception
(
'Should not happen'
);
}
private
function
evaluateConstFetch
(
Expr\ConstFetch
$expr
)
{
$name
=
$expr
->
name
->
toLowerString
();
switch
(
$name
)
{
case
'null'
:
return
null
;
case
'false'
:
return
false
;
case
'true'
:
return
true
;
}
return
(
$this
->
fallbackEvaluator
)(
$expr
);
}
}
File Metadata
Details
Attached
Mime Type
text/x-php
Expires
Aug 18 2026, 12:00 (5 w, 2 h ago)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
ff/b2/65aa56eb1e42153d35ff2e00fb1c
Default Alt Text
ConstExprEvaluator.php (9 KB)
Attached To
Mode
rMWPROD MediaWiki Production
Attached
Detach File
Event Timeline
Log In to Comment