@@ -498,10 +498,11 @@ zend_class_entry *zend_ast_fetch_class(zend_ast *ast, zend_class_entry *scope)
498498 return zend_fetch_class_with_scope (zend_ast_get_str (ast ), ast -> attr | ZEND_FETCH_CLASS_EXCEPTION , scope );
499499}
500500
501- ZEND_API zend_result ZEND_FASTCALL zend_ast_evaluate (zval * result , zend_ast * ast , zend_class_entry * scope )
501+ ZEND_API zend_result ZEND_FASTCALL zend_ast_evaluate_ex (zval * result , zend_ast * ast , zend_class_entry * scope , bool * short_circuited_ptr )
502502{
503503 zval op1 , op2 ;
504504 zend_result ret = SUCCESS ;
505+ * short_circuited_ptr = false;
505506
506507 switch (ast -> kind ) {
507508 case ZEND_AST_BINARY_OP :
@@ -733,10 +734,16 @@ ZEND_API zend_result ZEND_FASTCALL zend_ast_evaluate(zval *result, zend_ast *ast
733734 zend_error_noreturn (E_COMPILE_ERROR , "Cannot use [] for reading" );
734735 }
735736
736- if (UNEXPECTED (zend_ast_evaluate (& op1 , ast -> child [0 ], scope ) != SUCCESS )) {
737+ bool short_circuited ;
738+ if (UNEXPECTED (zend_ast_evaluate_ex (& op1 , ast -> child [0 ], scope , & short_circuited ) != SUCCESS )) {
737739 ret = FAILURE ;
738740 break ;
739741 }
742+ if (short_circuited ) {
743+ * short_circuited_ptr = true;
744+ ZVAL_NULL (result );
745+ return SUCCESS ;
746+ }
740747
741748 // DIM on objects is disallowed because it allows executing arbitrary expressions
742749 if (Z_TYPE (op1 ) == IS_OBJECT ) {
@@ -902,10 +909,23 @@ ZEND_API zend_result ZEND_FASTCALL zend_ast_evaluate(zval *result, zend_ast *ast
902909 return SUCCESS ;
903910 }
904911 case ZEND_AST_PROP :
912+ case ZEND_AST_NULLSAFE_PROP :
905913 {
906- if (UNEXPECTED (zend_ast_evaluate (& op1 , ast -> child [0 ], scope ) != SUCCESS )) {
914+ bool short_circuited ;
915+ if (UNEXPECTED (zend_ast_evaluate_ex (& op1 , ast -> child [0 ], scope , & short_circuited ) != SUCCESS )) {
907916 return FAILURE ;
908917 }
918+ if (short_circuited ) {
919+ * short_circuited_ptr = true;
920+ ZVAL_NULL (result );
921+ return SUCCESS ;
922+ }
923+ if (ast -> kind == ZEND_AST_NULLSAFE_PROP && Z_TYPE (op1 ) == IS_NULL ) {
924+ * short_circuited_ptr = true;
925+ ZVAL_NULL (result );
926+ return SUCCESS ;
927+ }
928+
909929 if (UNEXPECTED (zend_ast_evaluate (& op2 , ast -> child [1 ], scope ) != SUCCESS )) {
910930 zval_ptr_dtor_nogc (& op1 );
911931 return FAILURE ;
@@ -954,6 +974,12 @@ ZEND_API zend_result ZEND_FASTCALL zend_ast_evaluate(zval *result, zend_ast *ast
954974 return ret ;
955975}
956976
977+ ZEND_API zend_result ZEND_FASTCALL zend_ast_evaluate (zval * result , zend_ast * ast , zend_class_entry * scope )
978+ {
979+ bool short_circuited ;
980+ return zend_ast_evaluate_ex (result , ast , scope , & short_circuited );
981+ }
982+
957983static size_t ZEND_FASTCALL zend_ast_tree_size (zend_ast * ast )
958984{
959985 size_t size ;
0 commit comments