@@ -684,22 +684,6 @@ static ZEND_COLD void zend_throw_no_prop_backing_value_access(zend_string *class
684
684
ZSTR_VAL (class_name ), ZSTR_VAL (prop_name ));
685
685
}
686
686
687
- static bool zend_call_get_hook (
688
- const zend_property_info * prop_info , zend_string * prop_name ,
689
- zend_function * get , zend_object * zobj , zval * rv )
690
- {
691
- if (!zend_should_call_hook (prop_info , zobj )) {
692
- if (UNEXPECTED (prop_info -> flags & ZEND_ACC_VIRTUAL )) {
693
- zend_throw_no_prop_backing_value_access (zobj -> ce -> name , prop_name , /* is_read */ true);
694
- }
695
- return false;
696
- }
697
-
698
- zend_call_known_instance_method_with_0_params (get , zobj , rv );
699
-
700
- return true;
701
- }
702
-
703
687
ZEND_API zval * zend_std_read_property (zend_object * zobj , zend_string * name , int type , void * * cache_slot , zval * rv ) /* {{{ */
704
688
{
705
689
zval * retval ;
@@ -808,8 +792,9 @@ ZEND_API zval *zend_std_read_property(zend_object *zobj, zend_string *name, int
808
792
809
793
zend_class_entry * ce = zobj -> ce ;
810
794
811
- if (!zend_call_get_hook (prop_info , name , get , zobj , rv )) {
812
- if (EG (exception )) {
795
+ if (!zend_should_call_hook (prop_info , zobj )) {
796
+ if (UNEXPECTED (prop_info -> flags & ZEND_ACC_VIRTUAL )) {
797
+ zend_throw_no_prop_backing_value_access (zobj -> ce -> name , name , /* is_read */ true);
813
798
return & EG (uninitialized_zval );
814
799
}
815
800
@@ -826,12 +811,19 @@ ZEND_API zval *zend_std_read_property(zend_object *zobj, zend_string *name, int
826
811
goto try_again ;
827
812
}
828
813
829
- if (EXPECTED (cache_slot
814
+ /* Compute simple get before calling hook, as the hook may release zobj. */
815
+ bool cache_simple_get = cache_slot
830
816
&& zend_execute_ex == execute_ex
831
817
&& zobj -> ce -> default_object_handlers -> read_property == zend_std_read_property
832
818
&& !zobj -> ce -> create_object
833
819
&& !zend_is_in_hook (prop_info )
834
- && !(prop_info -> hooks [ZEND_PROPERTY_HOOK_GET ]-> common .fn_flags & ZEND_ACC_RETURN_REFERENCE ))) {
820
+ && !(prop_info -> hooks [ZEND_PROPERTY_HOOK_GET ]-> common .fn_flags & ZEND_ACC_RETURN_REFERENCE );
821
+
822
+ zend_call_known_instance_method_with_0_params (get , zobj , rv );
823
+
824
+ /* Only cache simple get after calling the hook to provide better error
825
+ * messages for accidentally recursive hooks. */
826
+ if (EXPECTED (cache_simple_get )) {
835
827
ZEND_SET_PROPERTY_HOOK_SIMPLE_GET (cache_slot );
836
828
}
837
829
@@ -2229,14 +2221,17 @@ ZEND_API int zend_std_has_property(zend_object *zobj, zend_string *name, int has
2229
2221
}
2230
2222
2231
2223
zval rv ;
2232
- if (!zend_call_get_hook (prop_info , name , get , zobj , & rv )) {
2233
- if (EG (exception )) {
2224
+ if (!zend_should_call_hook (prop_info , zobj )) {
2225
+ if (UNEXPECTED (prop_info -> flags & ZEND_ACC_VIRTUAL )) {
2226
+ zend_throw_no_prop_backing_value_access (zobj -> ce -> name , name , /* is_read */ true);
2234
2227
return 0 ;
2235
2228
}
2236
2229
property_offset = prop_info -> offset ;
2237
2230
goto try_again ;
2238
2231
}
2239
2232
2233
+ zend_call_known_instance_method_with_0_params (get , zobj , & rv );
2234
+
2240
2235
if (has_set_exists == ZEND_PROPERTY_NOT_EMPTY ) {
2241
2236
result = zend_is_true (& rv );
2242
2237
} else {
0 commit comments