@@ -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,17 +290,15 @@ 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
/* Abstract class can implement Traversable only, in which case the extending class must
297
297
* implement Iterator or IteratorAggregate. */
298
298
if (class_type -> ce_flags & ZEND_ACC_EXPLICIT_ABSTRACT_CLASS ) {
299
299
return SUCCESS ;
300
300
}
301
+
301
302
if (class_type -> num_interfaces ) {
302
303
ZEND_ASSERT (class_type -> ce_flags & ZEND_ACC_RESOLVED_INTERFACES );
303
304
for (i = 0 ; i < class_type -> num_interfaces ; i ++ ) {
@@ -484,9 +485,169 @@ static int zend_implement_serializable(zend_class_entry *interface, zend_class_e
484
485
}
485
486
/* }}}*/
486
487
488
+ typedef struct {
489
+ zend_object std ;
490
+ zend_object_iterator * iter ;
491
+ zend_bool rewind_called ;
492
+ } zend_internal_iterator ;
493
+
494
+ static zend_object * zend_internal_iterator_create (zend_class_entry * ce ) {
495
+ zend_internal_iterator * intern = emalloc (sizeof (zend_internal_iterator ));
496
+ zend_object_std_init (& intern -> std , ce );
497
+ intern -> std .handlers = & zend_internal_iterator_handlers ;
498
+ intern -> iter = NULL ;
499
+ intern -> rewind_called = 0 ;
500
+ return & intern -> std ;
501
+ }
502
+
503
+ ZEND_API int zend_create_internal_iterator_zval (zval * return_value , zval * obj ) {
504
+ zend_class_entry * scope = EG (current_execute_data )-> func -> common .scope ;
505
+ ZEND_ASSERT (scope -> get_iterator != zend_user_it_get_new_iterator );
506
+ zend_object_iterator * iter = scope -> get_iterator (Z_OBJCE_P (obj ), obj , /* by_ref */ 0 );
507
+ if (!iter ) {
508
+ return FAILURE ;
509
+ }
510
+
511
+ zend_internal_iterator * intern =
512
+ (zend_internal_iterator * ) zend_internal_iterator_create (zend_ce_internal_iterator );
513
+ intern -> iter = iter ;
514
+ ZVAL_OBJ (return_value , & intern -> std );
515
+ return SUCCESS ;
516
+ }
517
+
518
+ static void zend_internal_iterator_free (zend_object * obj ) {
519
+ zend_internal_iterator * intern = (zend_internal_iterator * ) obj ;
520
+ if (intern -> iter ) {
521
+ zend_iterator_dtor (intern -> iter );
522
+ }
523
+ zend_object_std_dtor (& intern -> std );
524
+ }
525
+
526
+ static zend_internal_iterator * zend_internal_iterator_fetch (zval * This ) {
527
+ zend_internal_iterator * intern = (zend_internal_iterator * ) Z_OBJ_P (This );
528
+ if (!intern -> iter ) {
529
+ zend_throw_error (NULL , "The InternalIterator object has not been properly initialized" );
530
+ return NULL ;
531
+ }
532
+ return intern ;
533
+ }
534
+
535
+ /* Many iterators will now behave correctly if rewind() is not called, make sure it happens. */
536
+ static int zend_internal_iterator_ensure_rewound (zend_internal_iterator * intern ) {
537
+ if (!intern -> rewind_called ) {
538
+ zend_object_iterator * iter = intern -> iter ;
539
+ intern -> rewind_called = 1 ;
540
+ if (iter -> funcs -> rewind ) {
541
+ iter -> funcs -> rewind (iter );
542
+ if (UNEXPECTED (EG (exception ))) {
543
+ return FAILURE ;
544
+ }
545
+ }
546
+ }
547
+ return SUCCESS ;
548
+ }
549
+
550
+
551
+ ZEND_METHOD (InternalIterator , __construct ) {
552
+ zend_throw_error (NULL , "Cannot manually construct InternalIterator" );
553
+ }
554
+
555
+ ZEND_METHOD (InternalIterator , current ) {
556
+ ZEND_PARSE_PARAMETERS_NONE ();
557
+
558
+ zend_internal_iterator * intern = zend_internal_iterator_fetch (ZEND_THIS );
559
+ if (!intern ) {
560
+ RETURN_THROWS ();
561
+ }
562
+
563
+ if (zend_internal_iterator_ensure_rewound (intern ) == FAILURE ) {
564
+ RETURN_THROWS ();
565
+ }
566
+
567
+ zval * data = intern -> iter -> funcs -> get_current_data (intern -> iter );
568
+ if (data ) {
569
+ ZVAL_COPY_DEREF (return_value , data );
570
+ }
571
+ }
572
+
573
+ ZEND_METHOD (InternalIterator , key ) {
574
+ ZEND_PARSE_PARAMETERS_NONE ();
575
+
576
+ zend_internal_iterator * intern = zend_internal_iterator_fetch (ZEND_THIS );
577
+ if (!intern ) {
578
+ RETURN_THROWS ();
579
+ }
580
+
581
+ if (zend_internal_iterator_ensure_rewound (intern ) == FAILURE ) {
582
+ RETURN_THROWS ();
583
+ }
584
+
585
+ if (intern -> iter -> funcs -> get_current_key ) {
586
+ intern -> iter -> funcs -> get_current_key (intern -> iter , return_value );
587
+ } else {
588
+ RETURN_LONG (intern -> iter -> index );
589
+ }
590
+ }
591
+
592
+ ZEND_METHOD (InternalIterator , next ) {
593
+ ZEND_PARSE_PARAMETERS_NONE ();
594
+
595
+ zend_internal_iterator * intern = zend_internal_iterator_fetch (ZEND_THIS );
596
+ if (!intern ) {
597
+ RETURN_THROWS ();
598
+ }
599
+
600
+ if (zend_internal_iterator_ensure_rewound (intern ) == FAILURE ) {
601
+ RETURN_THROWS ();
602
+ }
603
+
604
+ intern -> iter -> funcs -> move_forward (intern -> iter );
605
+ intern -> iter -> index ++ ;
606
+ }
607
+
608
+ ZEND_METHOD (InternalIterator , valid ) {
609
+ ZEND_PARSE_PARAMETERS_NONE ();
610
+
611
+ zend_internal_iterator * intern = zend_internal_iterator_fetch (ZEND_THIS );
612
+ if (!intern ) {
613
+ RETURN_THROWS ();
614
+ }
615
+
616
+ if (zend_internal_iterator_ensure_rewound (intern ) == FAILURE ) {
617
+ RETURN_THROWS ();
618
+ }
619
+
620
+ RETURN_BOOL (intern -> iter -> funcs -> valid (intern -> iter ) == SUCCESS );
621
+ }
622
+
623
+ ZEND_METHOD (InternalIterator , rewind ) {
624
+ ZEND_PARSE_PARAMETERS_NONE ();
625
+
626
+ zend_internal_iterator * intern = zend_internal_iterator_fetch (ZEND_THIS );
627
+ if (!intern ) {
628
+ RETURN_THROWS ();
629
+ }
630
+
631
+ if (!intern -> iter -> funcs -> rewind ) {
632
+ /* Allow calling rewind() if no iteration has happened yet,
633
+ * even if the iterator does not support rewinding. */
634
+ if (intern -> iter -> index != 0 ) {
635
+ zend_throw_error (NULL , "Iterator does not support rewinding" );
636
+ RETURN_THROWS ();
637
+ }
638
+ intern -> iter -> index = 0 ;
639
+ return ;
640
+ }
641
+
642
+ intern -> iter -> funcs -> rewind (intern -> iter );
643
+ intern -> iter -> index = 0 ;
644
+ }
645
+
487
646
/* {{{ zend_register_interfaces */
488
647
ZEND_API void zend_register_interfaces (void )
489
648
{
649
+ zend_class_entry ce ;
650
+
490
651
REGISTER_MAGIC_INTERFACE (traversable , Traversable );
491
652
492
653
REGISTER_MAGIC_INTERFACE (aggregate , IteratorAggregate );
@@ -497,7 +658,6 @@ ZEND_API void zend_register_interfaces(void)
497
658
498
659
REGISTER_MAGIC_INTERFACE (serializable , Serializable );
499
660
500
- zend_class_entry ce ;
501
661
INIT_CLASS_ENTRY (ce , "ArrayAccess" , class_ArrayAccess_methods );
502
662
zend_ce_arrayaccess = zend_register_internal_interface (& ce );
503
663
@@ -506,5 +666,15 @@ ZEND_API void zend_register_interfaces(void)
506
666
507
667
INIT_CLASS_ENTRY (ce , "Stringable" , class_Stringable_methods );
508
668
zend_ce_stringable = zend_register_internal_interface (& ce );
669
+
670
+ INIT_CLASS_ENTRY (ce , "InternalIterator" , class_InternalIterator_methods );
671
+ zend_ce_internal_iterator = zend_register_internal_class (& ce );
672
+ zend_class_implements (zend_ce_internal_iterator , 1 , zend_ce_iterator );
673
+ zend_ce_internal_iterator -> ce_flags |= ZEND_ACC_FINAL ;
674
+ zend_ce_internal_iterator -> create_object = zend_internal_iterator_create ;
675
+
676
+ memcpy (& zend_internal_iterator_handlers , zend_get_std_object_handlers (),
677
+ sizeof (zend_object_handlers ));
678
+ zend_internal_iterator_handlers .free_obj = zend_internal_iterator_free ;
509
679
}
510
680
/* }}} */
0 commit comments