@@ -231,6 +231,49 @@ protected function resolveExprFuncCall(Expr\FuncCall $node): mixed
231231 return $ reflectedFunction ->invoke (...$ resolvedArgs );
232232 }
233233
234+ /**
235+ * Resolves new expression by instantiating the class with constructor arguments
236+ *
237+ * @throws \Throwable In case of any errors during class instantiation
238+ */
239+ protected function resolveExprNew (Expr \New_ $ node ): object
240+ {
241+ $ classToInstantiateNode = $ node ->class ;
242+
243+ // Resolve class name - it can be a Name node or an expression
244+ if ($ classToInstantiateNode instanceof Node \Name) {
245+ // Unwrap resolved class name if we have it inside attributes
246+ if ($ classToInstantiateNode ->hasAttribute ('resolvedName ' )) {
247+ $ classToInstantiateNode = $ classToInstantiateNode ->getAttribute ('resolvedName ' );
248+ }
249+ $ className = $ classToInstantiateNode ->toString ();
250+ } else {
251+ // It's an expression, resolve it to get class name
252+ $ className = $ this ->resolve ($ classToInstantiateNode );
253+ if (!is_string ($ className )) {
254+ throw new ReflectionException ("Unable to resolve class name for instantiation. " );
255+ }
256+ }
257+
258+ // Resolve constructor arguments
259+ $ resolvedArgs = [];
260+ foreach ($ node ->args as $ argumentNode ) {
261+ $ value = $ this ->resolve ($ argumentNode ->value );
262+ // if constructor uses named arguments, then unpack argument name first
263+ if (isset ($ argumentNode ->name )) {
264+ $ name = $ this ->resolve ($ argumentNode ->name );
265+ $ resolvedArgs [$ name ] = $ value ;
266+ } else {
267+ // otherwise simply add argument to the list
268+ $ resolvedArgs [] = $ value ;
269+ }
270+ }
271+
272+ // Use ReflectionClass to safely instantiate the class
273+ $ reflectionClass = new \ReflectionClass ($ className );
274+ return $ reflectionClass ->newInstance (...$ resolvedArgs );
275+ }
276+
234277 protected function resolveScalarFloat (Float_ $ node ): float
235278 {
236279 return $ node ->value ;
0 commit comments