@@ -237,7 +237,7 @@ ZEND_API struct _zend_property_info *zend_get_property_info(zend_class_entry *ce
237
237
EG (std_property_info ).flags = ZEND_ACC_PUBLIC ;
238
238
EG (std_property_info ).name = Z_STRVAL_P (member );
239
239
EG (std_property_info ).name_length = Z_STRLEN_P (member );
240
- EG (std_property_info ).h = zend_get_hash_value ( EG ( std_property_info ). name , EG ( std_property_info ). name_length + 1 ) ;
240
+ EG (std_property_info ).h = h ;
241
241
property_info = & EG (std_property_info );
242
242
}
243
243
return property_info ;
@@ -268,6 +268,30 @@ ZEND_API int zend_check_property_access(zend_object *zobj, char *prop_info_name
268
268
return zend_verify_property_access (property_info , zobj -> ce TSRMLS_CC ) ? SUCCESS : FAILURE ;
269
269
}
270
270
271
+ static int zend_get_property_guard (zend_object * zobj , zend_property_info * property_info , zval * member , zend_guard * * pguard )
272
+ {
273
+ zend_property_info info ;
274
+ zend_guard stub ;
275
+
276
+ if (!property_info ) {
277
+ property_info = & info ;
278
+ info .name = Z_STRVAL_P (member );
279
+ info .name_length = Z_STRLEN_P (member );
280
+ info .h = zend_get_hash_value (Z_STRVAL_P (member ), Z_STRLEN_P (member ) + 1 );
281
+ }
282
+ if (!zobj -> guards ) {
283
+ ALLOC_HASHTABLE (zobj -> guards );
284
+ zend_hash_init (zobj -> guards , 0 , NULL , NULL , 0 );
285
+ } else if (zend_hash_quick_find (zobj -> guards , property_info -> name , property_info -> name_length + 1 , property_info -> h , (void * * ) pguard ) == SUCCESS ) {
286
+ return SUCCESS ;
287
+ }
288
+ stub .in_get = 0 ;
289
+ stub .in_set = 0 ;
290
+ stub .in_unset = 0 ;
291
+ stub .in_isset = 0 ;
292
+ return zend_hash_quick_add (zobj -> guards , property_info -> name , property_info -> name_length + 1 , property_info -> h , (void * * )& stub , sizeof (stub ), (void * * ) pguard );
293
+ }
294
+
271
295
zval * zend_std_read_property (zval * object , zval * member , int type TSRMLS_DC )
272
296
{
273
297
zend_object * zobj ;
@@ -276,11 +300,9 @@ zval *zend_std_read_property(zval *object, zval *member, int type TSRMLS_DC)
276
300
zval * rv = NULL ;
277
301
zend_property_info * property_info ;
278
302
int silent ;
279
- zend_bool use_get ;
280
303
281
304
silent = (type == BP_VAR_IS );
282
305
zobj = Z_OBJ_P (object );
283
- use_get = (zobj -> ce -> __get && !zobj -> in_get );
284
306
285
307
if (member -> type != IS_STRING ) {
286
308
ALLOC_ZVAL (tmp_member );
@@ -296,14 +318,18 @@ zval *zend_std_read_property(zval *object, zval *member, int type TSRMLS_DC)
296
318
#endif
297
319
298
320
/* make zend_get_property_info silent if we have getter - we may want to use it */
299
- property_info = zend_get_property_info (zobj -> ce , member , use_get TSRMLS_CC );
321
+ property_info = zend_get_property_info (zobj -> ce , member , ( zobj -> ce -> __get != NULL ) TSRMLS_CC );
300
322
301
323
if (!property_info || zend_hash_quick_find (zobj -> properties , property_info -> name , property_info -> name_length + 1 , property_info -> h , (void * * ) & retval ) == FAILURE ) {
302
- if (use_get ) {
324
+ zend_guard * guard ;
325
+
326
+ if (zobj -> ce -> __get &&
327
+ zend_get_property_guard (zobj , property_info , member , & guard ) == SUCCESS &&
328
+ !guard -> in_get ) {
303
329
/* have getter - try with it! */
304
- zobj -> in_get = 1 ; /* prevent circular getting */
330
+ guard -> in_get = 1 ; /* prevent circular getting */
305
331
rv = zend_std_call_getter (object , member TSRMLS_CC );
306
- zobj -> in_get = 0 ;
332
+ guard -> in_get = 0 ;
307
333
308
334
if (rv ) {
309
335
retval = & rv ;
@@ -333,10 +359,8 @@ static void zend_std_write_property(zval *object, zval *member, zval *value TSRM
333
359
zval * * variable_ptr ;
334
360
int setter_done = 0 ;
335
361
zend_property_info * property_info ;
336
- zend_bool use_set ;
337
362
338
363
zobj = Z_OBJ_P (object );
339
- use_set = (zobj -> ce -> __set && !zobj -> in_set );
340
364
341
365
if (member -> type != IS_STRING ) {
342
366
ALLOC_ZVAL (tmp_member );
@@ -347,7 +371,7 @@ static void zend_std_write_property(zval *object, zval *member, zval *value TSRM
347
371
member = tmp_member ;
348
372
}
349
373
350
- property_info = zend_get_property_info (zobj -> ce , member , use_set TSRMLS_CC );
374
+ property_info = zend_get_property_info (zobj -> ce , member , ( zobj -> ce -> __set != NULL ) TSRMLS_CC );
351
375
352
376
if (property_info && zend_hash_quick_find (zobj -> properties , property_info -> name , property_info -> name_length + 1 , property_info -> h , (void * * ) & variable_ptr ) == SUCCESS ) {
353
377
if (* variable_ptr == value ) {
@@ -368,13 +392,17 @@ static void zend_std_write_property(zval *object, zval *member, zval *value TSRM
368
392
}
369
393
}
370
394
} else {
371
- if (use_set ) {
372
- zobj -> in_set = 1 ; /* prevent circular setting */
395
+ zend_guard * guard ;
396
+
397
+ if (zobj -> ce -> __set &&
398
+ zend_get_property_guard (zobj , property_info , member , & guard ) == SUCCESS &&
399
+ !guard -> in_set ) {
400
+ guard -> in_set = 1 ; /* prevent circular setting */
373
401
if (zend_std_call_setter (object , member , value TSRMLS_CC ) != SUCCESS ) {
374
402
/* for now, just ignore it - __set should take care of warnings, etc. */
375
403
}
376
404
setter_done = 1 ;
377
- zobj -> in_set = 0 ;
405
+ guard -> in_set = 0 ;
378
406
}
379
407
}
380
408
@@ -482,10 +510,8 @@ static zval **zend_std_get_property_ptr_ptr(zval *object, zval *member TSRMLS_DC
482
510
zval tmp_member ;
483
511
zval * * retval ;
484
512
zend_property_info * property_info ;
485
- zend_bool use_get ;
486
513
487
514
zobj = Z_OBJ_P (object );
488
- use_get = (zobj -> ce -> __get && !zobj -> in_get );
489
515
490
516
if (member -> type != IS_STRING ) {
491
517
tmp_member = * member ;
@@ -498,12 +524,15 @@ static zval **zend_std_get_property_ptr_ptr(zval *object, zval *member TSRMLS_DC
498
524
fprintf (stderr , "Ptr object #%d property: %s\n" , Z_OBJ_HANDLE_P (object ), Z_STRVAL_P (member ));
499
525
#endif
500
526
501
- property_info = zend_get_property_info (zobj -> ce , member , use_get TSRMLS_CC );
527
+ property_info = zend_get_property_info (zobj -> ce , member , ( zobj -> ce -> __get != NULL ) TSRMLS_CC );
502
528
503
529
if (!property_info || zend_hash_quick_find (zobj -> properties , property_info -> name , property_info -> name_length + 1 , property_info -> h , (void * * ) & retval ) == FAILURE ) {
504
530
zval * new_zval ;
531
+ zend_guard * guard ;
505
532
506
- if (!use_get ) {
533
+ if (!zobj -> ce -> __get ||
534
+ zend_get_property_guard (zobj , property_info , member , & guard ) != SUCCESS ||
535
+ guard -> in_get ) {
507
536
/* we don't have access controls - will just add it */
508
537
new_zval = & EG (uninitialized_zval );
509
538
@@ -527,10 +556,8 @@ static void zend_std_unset_property(zval *object, zval *member TSRMLS_DC)
527
556
zend_object * zobj ;
528
557
zval * tmp_member = NULL ;
529
558
zend_property_info * property_info ;
530
- zend_bool use_unset ;
531
559
532
560
zobj = Z_OBJ_P (object );
533
- use_unset = (zobj -> ce -> __unset && !zobj -> in_unset );
534
561
535
562
if (member -> type != IS_STRING ) {
536
563
ALLOC_ZVAL (tmp_member );
@@ -541,14 +568,18 @@ static void zend_std_unset_property(zval *object, zval *member TSRMLS_DC)
541
568
member = tmp_member ;
542
569
}
543
570
544
- property_info = zend_get_property_info (zobj -> ce , member , 0 TSRMLS_CC );
571
+ property_info = zend_get_property_info (zobj -> ce , member , ( zobj -> ce -> __unset != NULL ) TSRMLS_CC );
545
572
546
573
if (!property_info || zend_hash_del (zobj -> properties , property_info -> name , property_info -> name_length + 1 ) == FAILURE ) {
547
- if (use_unset ) {
574
+ zend_guard * guard ;
575
+
576
+ if (zobj -> ce -> __unset &&
577
+ zend_get_property_guard (zobj , property_info , member , & guard ) == SUCCESS &&
578
+ !guard -> in_unset ) {
548
579
/* have unseter - try with it! */
549
- zobj -> in_unset = 1 ; /* prevent circular unsetting */
580
+ guard -> in_unset = 1 ; /* prevent circular setting */
550
581
zend_std_call_unsetter (object , member TSRMLS_CC );
551
- zobj -> in_unset = 0 ;
582
+ guard -> in_unset = 0 ;
552
583
}
553
584
}
554
585
@@ -895,10 +926,8 @@ static int zend_std_has_property(zval *object, zval *member, int has_set_exists
895
926
zval * * value ;
896
927
zval * tmp_member = NULL ;
897
928
zend_property_info * property_info ;
898
- zend_bool use_isset ;
899
929
900
930
zobj = Z_OBJ_P (object );
901
- use_isset = (zobj -> ce -> __isset && !zobj -> in_isset );
902
931
903
932
if (member -> type != IS_STRING ) {
904
933
ALLOC_ZVAL (tmp_member );
@@ -916,26 +945,33 @@ static int zend_std_has_property(zval *object, zval *member, int has_set_exists
916
945
property_info = zend_get_property_info (zobj -> ce , member , 1 TSRMLS_CC );
917
946
918
947
if (!property_info || zend_hash_quick_find (zobj -> properties , property_info -> name , property_info -> name_length + 1 , property_info -> h , (void * * ) & value ) == FAILURE ) {
948
+ zend_guard * guard ;
949
+
919
950
result = 0 ;
920
- if (use_isset && (has_set_exists != 2 )) {
951
+ if ((has_set_exists != 2 ) &&
952
+ zobj -> ce -> __isset &&
953
+ zend_get_property_guard (zobj , property_info , member , & guard ) == SUCCESS &&
954
+ !guard -> in_isset ) {
921
955
zval * rv ;
922
956
923
957
/* have issetter - try with it! */
924
- zobj -> in_isset = 1 ; /* prevent circular getting */
958
+ guard -> in_isset = 1 ; /* prevent circular getting */
925
959
rv = zend_std_call_issetter (object , member TSRMLS_CC );
926
- zobj -> in_isset = 0 ;
927
960
if (rv ) {
928
961
result = zend_is_true (rv );
929
962
zval_ptr_dtor (& rv );
930
- if (has_set_exists && result && !EG (exception ) && zobj -> ce -> __get && !zobj -> in_get ) {
963
+ if (has_set_exists && result && !EG (exception ) && zobj -> ce -> __get && !guard -> in_get ) {
964
+ guard -> in_get = 1 ;
931
965
rv = zend_std_call_getter (object , member TSRMLS_CC );
966
+ guard -> in_get = 0 ;
932
967
if (rv ) {
933
968
rv -> refcount ++ ;
934
969
result = i_zend_is_true (rv );
935
970
zval_ptr_dtor (& rv );
936
971
}
937
972
}
938
973
}
974
+ guard -> in_isset = 0 ;
939
975
}
940
976
} else {
941
977
switch (has_set_exists ) {
0 commit comments