@@ -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 ) {
@@ -908,10 +915,23 @@ ZEND_API zend_result ZEND_FASTCALL zend_ast_evaluate(zval *result, zend_ast *ast
908915 return SUCCESS ;
909916 }
910917 case ZEND_AST_PROP :
918+ case ZEND_AST_NULLSAFE_PROP :
911919 {
912- if (UNEXPECTED (zend_ast_evaluate (& op1 , ast -> child [0 ], scope ) != SUCCESS )) {
920+ bool short_circuited ;
921+ if (UNEXPECTED (zend_ast_evaluate_ex (& op1 , ast -> child [0 ], scope , & short_circuited ) != SUCCESS )) {
913922 return FAILURE ;
914923 }
924+ if (short_circuited ) {
925+ * short_circuited_ptr = true;
926+ ZVAL_NULL (result );
927+ return SUCCESS ;
928+ }
929+ if (ast -> kind == ZEND_AST_NULLSAFE_PROP && Z_TYPE (op1 ) == IS_NULL ) {
930+ * short_circuited_ptr = true;
931+ ZVAL_NULL (result );
932+ return SUCCESS ;
933+ }
934+
915935 if (UNEXPECTED (zend_ast_evaluate (& op2 , ast -> child [1 ], scope ) != SUCCESS )) {
916936 zval_ptr_dtor_nogc (& op1 );
917937 return FAILURE ;
@@ -960,6 +980,12 @@ ZEND_API zend_result ZEND_FASTCALL zend_ast_evaluate(zval *result, zend_ast *ast
960980 return ret ;
961981}
962982
983+ ZEND_API zend_result ZEND_FASTCALL zend_ast_evaluate (zval * result , zend_ast * ast , zend_class_entry * scope )
984+ {
985+ bool short_circuited ;
986+ return zend_ast_evaluate_ex (result , ast , scope , & short_circuited );
987+ }
988+
963989static size_t ZEND_FASTCALL zend_ast_tree_size (zend_ast * ast )
964990{
965991 size_t size ;
0 commit comments