19
19
use phpDocumentor \Reflection \Php \Constant as ConstantElement ;
20
20
use phpDocumentor \Reflection \Php \File as FileElement ;
21
21
use phpDocumentor \Reflection \Php \StrategyContainer ;
22
+ use phpDocumentor \Reflection \Php \ValueEvaluator \ConstantEvaluator ;
23
+ use PhpParser \ConstExprEvaluationException ;
22
24
use PhpParser \Node \Arg ;
25
+ use PhpParser \Node \Expr ;
23
26
use PhpParser \Node \Expr \FuncCall ;
24
27
use PhpParser \Node \Name ;
25
- use PhpParser \Node \Scalar \String_ ;
26
28
use PhpParser \Node \Stmt \Expression ;
27
29
use PhpParser \Node \VariadicPlaceholder ;
28
30
use PhpParser \PrettyPrinter \Standard as PrettyPrinter ;
29
- use RuntimeException ;
30
31
31
32
use function assert ;
32
33
use function sprintf ;
@@ -43,13 +44,20 @@ final class Define extends AbstractFactory
43
44
/** @var PrettyPrinter */
44
45
private $ valueConverter ;
45
46
47
+ /** @var ConstantEvaluator */
48
+ private $ constantEvaluator ;
49
+
46
50
/**
47
51
* Initializes the object.
48
52
*/
49
- public function __construct (DocBlockFactoryInterface $ docBlockFactory , PrettyPrinter $ prettyPrinter )
50
- {
53
+ public function __construct (
54
+ DocBlockFactoryInterface $ docBlockFactory ,
55
+ PrettyPrinter $ prettyPrinter ,
56
+ ?ConstantEvaluator $ constantEvaluator = null
57
+ ) {
51
58
parent ::__construct ($ docBlockFactory );
52
59
$ this ->valueConverter = $ prettyPrinter ;
60
+ $ this ->constantEvaluator = $ constantEvaluator ?? new ConstantEvaluator ();
53
61
}
54
62
55
63
public function matches (ContextStack $ context , object $ object ): bool
@@ -85,12 +93,7 @@ protected function doCreate(
85
93
StrategyContainer $ strategies
86
94
): void {
87
95
$ expression = $ object ->expr ;
88
- if (!$ expression instanceof FuncCall) {
89
- throw new RuntimeException (
90
- 'Provided expression is not a function call; this should not happen because the `create` method '
91
- . ' checks the given object again using `matches` '
92
- );
93
- }
96
+ assert ($ expression instanceof FuncCall);
94
97
95
98
[$ name , $ value ] = $ expression ->args ;
96
99
@@ -102,8 +105,13 @@ protected function doCreate(
102
105
$ file = $ context ->search (FileElement::class);
103
106
assert ($ file instanceof FileElement);
104
107
108
+ $ fqsen = $ this ->determineFqsen ($ name , $ context );
109
+ if ($ fqsen === null ) {
110
+ return ;
111
+ }
112
+
105
113
$ constant = new ConstantElement (
106
- $ this -> determineFqsen ( $ name ) ,
114
+ $ fqsen ,
107
115
$ this ->createDocBlock ($ object ->getDocComment (), $ context ->getTypeContext ()),
108
116
$ this ->determineValue ($ value ),
109
117
new Location ($ object ->getLine ()),
@@ -122,15 +130,27 @@ private function determineValue(?Arg $value): ?string
122
130
return $ this ->valueConverter ->prettyPrintExpr ($ value ->value );
123
131
}
124
132
125
- private function determineFqsen (Arg $ name ): Fqsen
133
+ private function determineFqsen (Arg $ name, ContextStack $ context ): ? Fqsen
126
134
{
127
- $ nameString = $ name ->value ;
128
- assert ( $ nameString instanceof String_);
135
+ return $ this -> fqsenFromExpression ( $ name ->value , $ context ) ;
136
+ }
129
137
130
- if (strpos ($ nameString ->value , '\\' ) === false ) {
131
- return new Fqsen (sprintf ('\\%s ' , $ nameString ->value ));
138
+ private function fqsenFromExpression (Expr $ nameString , ContextStack $ context ): ?Fqsen
139
+ {
140
+ try {
141
+ return $ this ->fqsenFromString ($ this ->constantEvaluator ->evaluate ($ nameString , $ context ));
142
+ } catch (ConstExprEvaluationException $ e ) {
143
+ //Ignore any errors as we cannot evaluate all expressions
144
+ return null ;
145
+ }
146
+ }
147
+
148
+ private function fqsenFromString (string $ nameString ): Fqsen
149
+ {
150
+ if (strpos ($ nameString , '\\' ) === false ) {
151
+ return new Fqsen (sprintf ('\\%s ' , $ nameString ));
132
152
}
133
153
134
- return new Fqsen (sprintf ('%s ' , $ nameString-> value ));
154
+ return new Fqsen (sprintf ('%s ' , $ nameString ));
135
155
}
136
156
}
0 commit comments