@@ -29,6 +29,9 @@ ZEND_API zend_class_entry *zend_ce_arrayaccess;
29
29
ZEND_API zend_class_entry * zend_ce_serializable ;
30
30
ZEND_API zend_class_entry * zend_ce_countable ;
31
31
ZEND_API zend_class_entry * zend_ce_stringable ;
32
+ ZEND_API zend_class_entry * zend_ce_internal_iterator ;
33
+
34
+ static zend_object_handlers zend_internal_iterator_handlers ;
32
35
33
36
/* {{{ zend_call_method
34
37
Only returns the returned zval if retval_ptr != NULL */
@@ -287,12 +290,9 @@ ZEND_API zend_object_iterator *zend_user_it_get_new_iterator(zend_class_entry *c
287
290
/* {{{ zend_implement_traversable */
288
291
static int zend_implement_traversable (zend_class_entry * interface , zend_class_entry * class_type )
289
292
{
290
- /* check that class_type is traversable at c-level or implements at least one of 'aggregate' and 'Iterator' */
293
+ /* Check that class_type implements at least one of 'IteratorAggregate' or 'Iterator' */
291
294
uint32_t i ;
292
295
293
- if (class_type -> get_iterator || (class_type -> parent && class_type -> parent -> get_iterator )) {
294
- return SUCCESS ;
295
- }
296
296
if (class_type -> num_interfaces ) {
297
297
ZEND_ASSERT (class_type -> ce_flags & ZEND_ACC_RESOLVED_INTERFACES );
298
298
for (i = 0 ; i < class_type -> num_interfaces ; i ++ ) {
@@ -479,6 +479,164 @@ static int zend_implement_serializable(zend_class_entry *interface, zend_class_e
479
479
}
480
480
/* }}}*/
481
481
482
+ typedef struct {
483
+ zend_object std ;
484
+ zend_object_iterator * iter ;
485
+ zend_bool rewind_called ;
486
+ } zend_internal_iterator ;
487
+
488
+ static zend_object * zend_internal_iterator_create (zend_class_entry * ce ) {
489
+ zend_internal_iterator * intern = emalloc (sizeof (zend_internal_iterator ));
490
+ zend_object_std_init (& intern -> std , ce );
491
+ intern -> std .handlers = & zend_internal_iterator_handlers ;
492
+ intern -> iter = NULL ;
493
+ intern -> rewind_called = 0 ;
494
+ return & intern -> std ;
495
+ }
496
+
497
+ ZEND_API int zend_create_internal_iterator_zval (zval * return_value , zval * obj ) {
498
+ zend_class_entry * scope = EG (current_execute_data )-> func -> common .scope ;
499
+ ZEND_ASSERT (scope -> get_iterator != zend_user_it_get_new_iterator );
500
+ zend_object_iterator * iter = scope -> get_iterator (Z_OBJCE_P (obj ), obj , /* by_ref */ 0 );
501
+ if (!iter ) {
502
+ return FAILURE ;
503
+ }
504
+
505
+ zend_internal_iterator * intern =
506
+ (zend_internal_iterator * ) zend_internal_iterator_create (zend_ce_internal_iterator );
507
+ intern -> iter = iter ;
508
+ ZVAL_OBJ (return_value , & intern -> std );
509
+ return SUCCESS ;
510
+ }
511
+
512
+ static void zend_internal_iterator_free (zend_object * obj ) {
513
+ zend_internal_iterator * intern = (zend_internal_iterator * ) obj ;
514
+ if (intern -> iter ) {
515
+ zend_iterator_dtor (intern -> iter );
516
+ }
517
+ zend_object_std_dtor (& intern -> std );
518
+ }
519
+
520
+ static zend_internal_iterator * zend_internal_iterator_fetch (zval * This ) {
521
+ zend_internal_iterator * intern = (zend_internal_iterator * ) Z_OBJ_P (This );
522
+ if (!intern -> iter ) {
523
+ zend_throw_error (NULL , "The InternalIterator object has not been properly initialized" );
524
+ return NULL ;
525
+ }
526
+ return intern ;
527
+ }
528
+
529
+ /* Many iterators will now behave correctly if rewind() is not called, make sure it happens. */
530
+ static int zend_internal_iterator_ensure_rewound (zend_internal_iterator * intern ) {
531
+ if (!intern -> rewind_called ) {
532
+ zend_object_iterator * iter = intern -> iter ;
533
+ intern -> rewind_called = 1 ;
534
+ if (iter -> funcs -> rewind ) {
535
+ iter -> funcs -> rewind (iter );
536
+ if (UNEXPECTED (EG (exception ))) {
537
+ return FAILURE ;
538
+ }
539
+ }
540
+ }
541
+ return SUCCESS ;
542
+ }
543
+
544
+
545
+ ZEND_METHOD (InternalIterator , __construct ) {
546
+ zend_throw_error (NULL , "Cannot manually construct InternalIterator" );
547
+ }
548
+
549
+ ZEND_METHOD (InternalIterator , current ) {
550
+ ZEND_PARSE_PARAMETERS_NONE ();
551
+
552
+ zend_internal_iterator * intern = zend_internal_iterator_fetch (ZEND_THIS );
553
+ if (!intern ) {
554
+ RETURN_THROWS ();
555
+ }
556
+
557
+ if (zend_internal_iterator_ensure_rewound (intern ) == FAILURE ) {
558
+ RETURN_THROWS ();
559
+ }
560
+
561
+ zval * data = intern -> iter -> funcs -> get_current_data (intern -> iter );
562
+ if (data ) {
563
+ ZVAL_COPY_DEREF (return_value , data );
564
+ }
565
+ }
566
+
567
+ ZEND_METHOD (InternalIterator , key ) {
568
+ ZEND_PARSE_PARAMETERS_NONE ();
569
+
570
+ zend_internal_iterator * intern = zend_internal_iterator_fetch (ZEND_THIS );
571
+ if (!intern ) {
572
+ RETURN_THROWS ();
573
+ }
574
+
575
+ if (zend_internal_iterator_ensure_rewound (intern ) == FAILURE ) {
576
+ RETURN_THROWS ();
577
+ }
578
+
579
+ if (intern -> iter -> funcs -> get_current_key ) {
580
+ intern -> iter -> funcs -> get_current_key (intern -> iter , return_value );
581
+ } else {
582
+ RETURN_LONG (intern -> iter -> index );
583
+ }
584
+ }
585
+
586
+ ZEND_METHOD (InternalIterator , next ) {
587
+ ZEND_PARSE_PARAMETERS_NONE ();
588
+
589
+ zend_internal_iterator * intern = zend_internal_iterator_fetch (ZEND_THIS );
590
+ if (!intern ) {
591
+ RETURN_THROWS ();
592
+ }
593
+
594
+ if (zend_internal_iterator_ensure_rewound (intern ) == FAILURE ) {
595
+ RETURN_THROWS ();
596
+ }
597
+
598
+ intern -> iter -> funcs -> move_forward (intern -> iter );
599
+ intern -> iter -> index ++ ;
600
+ }
601
+
602
+ ZEND_METHOD (InternalIterator , valid ) {
603
+ ZEND_PARSE_PARAMETERS_NONE ();
604
+
605
+ zend_internal_iterator * intern = zend_internal_iterator_fetch (ZEND_THIS );
606
+ if (!intern ) {
607
+ RETURN_THROWS ();
608
+ }
609
+
610
+ if (zend_internal_iterator_ensure_rewound (intern ) == FAILURE ) {
611
+ RETURN_THROWS ();
612
+ }
613
+
614
+ RETURN_BOOL (intern -> iter -> funcs -> valid (intern -> iter ) == SUCCESS );
615
+ }
616
+
617
+ ZEND_METHOD (InternalIterator , rewind ) {
618
+ ZEND_PARSE_PARAMETERS_NONE ();
619
+
620
+ zend_internal_iterator * intern = zend_internal_iterator_fetch (ZEND_THIS );
621
+ if (!intern ) {
622
+ RETURN_THROWS ();
623
+ }
624
+
625
+ if (!intern -> iter -> funcs -> rewind ) {
626
+ /* Allow calling rewind() if no iteration has happened yet,
627
+ * even if the iterator does not support rewinding. */
628
+ if (intern -> iter -> index != 0 ) {
629
+ zend_throw_error (NULL , "Iterator does not support rewinding" );
630
+ RETURN_THROWS ();
631
+ }
632
+ intern -> iter -> index = 0 ;
633
+ return ;
634
+ }
635
+
636
+ intern -> iter -> funcs -> rewind (intern -> iter );
637
+ intern -> iter -> index = 0 ;
638
+ }
639
+
482
640
/* {{{ function tables */
483
641
static const zend_function_entry zend_funcs_aggregate [] = {
484
642
ZEND_ABSTRACT_ME (iterator , getIterator , arginfo_class_IteratorAggregate_getIterator )
@@ -519,11 +677,23 @@ static const zend_function_entry zend_funcs_stringable[] = {
519
677
ZEND_ABSTRACT_ME (Stringable , __toString , arginfo_class_Stringable___toString )
520
678
ZEND_FE_END
521
679
};
680
+
681
+ static const zend_function_entry zend_funcs_internal_iterator [] = {
682
+ ZEND_ME (InternalIterator , __construct , arginfo_class_InternalIterator___construct , ZEND_ACC_PRIVATE )
683
+ ZEND_ME (InternalIterator , current , arginfo_class_InternalIterator_current , ZEND_ACC_PUBLIC )
684
+ ZEND_ME (InternalIterator , next , arginfo_class_InternalIterator_next , ZEND_ACC_PUBLIC )
685
+ ZEND_ME (InternalIterator , key , arginfo_class_InternalIterator_key , ZEND_ACC_PUBLIC )
686
+ ZEND_ME (InternalIterator , valid , arginfo_class_InternalIterator_valid , ZEND_ACC_PUBLIC )
687
+ ZEND_ME (InternalIterator , rewind , arginfo_class_InternalIterator_rewind , ZEND_ACC_PUBLIC )
688
+ ZEND_FE_END
689
+ };
522
690
/* }}} */
523
691
524
692
/* {{{ zend_register_interfaces */
525
693
ZEND_API void zend_register_interfaces (void )
526
694
{
695
+ zend_class_entry ce ;
696
+
527
697
REGISTER_MAGIC_INTERFACE (traversable , Traversable );
528
698
529
699
REGISTER_MAGIC_INTERFACE (aggregate , IteratorAggregate );
@@ -534,7 +704,6 @@ ZEND_API void zend_register_interfaces(void)
534
704
535
705
REGISTER_MAGIC_INTERFACE (serializable , Serializable );
536
706
537
- zend_class_entry ce ;
538
707
INIT_CLASS_ENTRY (ce , "ArrayAccess" , zend_funcs_arrayaccess );
539
708
zend_ce_arrayaccess = zend_register_internal_interface (& ce );
540
709
@@ -543,5 +712,15 @@ ZEND_API void zend_register_interfaces(void)
543
712
544
713
INIT_CLASS_ENTRY (ce , "Stringable" , zend_funcs_stringable );
545
714
zend_ce_stringable = zend_register_internal_interface (& ce );
715
+
716
+ INIT_CLASS_ENTRY (ce , "InternalIterator" , zend_funcs_internal_iterator );
717
+ zend_ce_internal_iterator = zend_register_internal_class (& ce );
718
+ zend_class_implements (zend_ce_internal_iterator , 1 , zend_ce_iterator );
719
+ zend_ce_internal_iterator -> ce_flags |= ZEND_ACC_FINAL ;
720
+ zend_ce_internal_iterator -> create_object = zend_internal_iterator_create ;
721
+
722
+ memcpy (& zend_internal_iterator_handlers , zend_get_std_object_handlers (),
723
+ sizeof (zend_object_handlers ));
724
+ zend_internal_iterator_handlers .free_obj = zend_internal_iterator_free ;
546
725
}
547
726
/* }}} */
0 commit comments