]> granicus.if.org Git - php/commitdiff
Make foreach on spl'ed objects work with break, too
authorMarcus Boerger <helly@php.net>
Sun, 25 May 2003 19:10:44 +0000 (19:10 +0000)
committerMarcus Boerger <helly@php.net>
Sun, 25 May 2003 19:10:44 +0000 (19:10 +0000)
ext/spl/php_spl.c
ext/spl/php_spl.h
ext/spl/spl_foreach.c
ext/spl/spl_foreach.h

index 3794afdfa6e6941a25af3c6d2e93d7fada3d24c2..a60c504d3379fd9230baaeefe86ad79c3f560e6b 100755 (executable)
@@ -102,6 +102,7 @@ static void spl_init_globals(zend_spl_globals *spl_globals)
 #ifdef SPL_FOREACH
        ZEND_EXECUTE_HOOK(ZEND_FE_RESET);
        ZEND_EXECUTE_HOOK(ZEND_FE_FETCH);
+       ZEND_EXECUTE_HOOK(ZEND_SWITCH_FREE);
 #endif
 
 #if defined(SPL_ARRAY_READ) | defined(SPL_ARRAY_WRITE)
@@ -195,6 +196,7 @@ PHP_MSHUTDOWN_FUNCTION(spl)
 #ifdef SPL_FOREACH
        ZEND_EXECUTE_HOOK_RESTORE(ZEND_FE_RESET);
        ZEND_EXECUTE_HOOK_RESTORE(ZEND_FE_FETCH);
+       ZEND_EXECUTE_HOOK_RESTORE(ZEND_SWITCH_FREE);
 #endif
 
 #if defined(SPL_ARRAY_READ) | defined(SPL_ARRAY_WRITE)
index 137e451cd58442fea454f025a6795d38ce378c8f..d06090d52d078165952e9723d56b9d644f774d73 100755 (executable)
@@ -63,6 +63,7 @@ ZEND_BEGIN_MODULE_GLOBALS(spl)
 #ifdef SPL_FOREACH
        ZEND_EXECUTE_HOOK_PTR(ZEND_FE_RESET);
        ZEND_EXECUTE_HOOK_PTR(ZEND_FE_FETCH);
+       ZEND_EXECUTE_HOOK_PTR(ZEND_SWITCH_FREE);
 #endif
 #if defined(SPL_ARRAY_READ) | defined(SPL_ARRAY_WRITE)
        ZEND_EXECUTE_HOOK_PTR(ZEND_FETCH_DIM_R);
index cc92d2a59741467db878a1b57512a6bb95a6eaf9..abf64ccd57f1cb5e1927782d204977c6f07ab516 100755 (executable)
@@ -37,8 +37,9 @@
        memset(emalloc(size), 0, size)
 
 typedef struct {
-       zend_uint        index;
+       zval             *obj;
        zend_class_entry *obj_ce;
+       zend_uint        index;
        zend_uint        is_ce_assoc;
        zend_function    *f_next;
        zend_function    *f_rewind;
@@ -51,33 +52,41 @@ typedef struct {
 ZEND_EXECUTE_HOOK_FUNCTION(ZEND_FE_RESET)
 {
        zval **obj, *retval;
-
-       if (EX(opline)->extended_value) {
-               obj = spl_get_zval_ptr_ptr(&EX(opline)->op1, EX(Ts) TSRMLS_CC);
-               if (spl_implements(obj, spl_ce_iterator TSRMLS_CC)) {
-                       spl_unlock_zval_ptr_ptr(&EX(opline)->op1, EX(Ts) TSRMLS_CC);
-                       spl_begin_method_call_ex(obj, NULL, NULL, "new_iterator", sizeof("new_iterator")-1, &retval TSRMLS_CC);
-                       EX_T(EX(opline)->result.u.var).var.ptr = retval;
-                       EX_T(EX(opline)->result.u.var).var.ptr_ptr = &EX_T(EX(opline)->result.u.var).var.ptr;   
-                       /* EX(opline)->result.u.EA.type = 0; */
-
-                       PZVAL_LOCK(retval);
-
-                       NEXT_OPCODE();
-               } else if (spl_implements(obj, spl_ce_forward TSRMLS_CC)) {
-                       spl_unlock_zval_ptr_ptr(&EX(opline)->op1, EX(Ts) TSRMLS_CC);
-
-                       EX_T(EX(opline)->result.u.var).var.ptr = *obj;
-                       EX_T(EX(opline)->result.u.var).var.ptr_ptr = &EX_T(EX(opline)->result.u.var).var.ptr;   
-                       /* EX(opline)->result.u.EA.type = 0; */
-
-                       (*obj)->refcount++;
-                       PZVAL_LOCK(*obj);
-
-                       NEXT_OPCODE();
+       spl_foreach_proxy proxy;
+
+       obj = spl_get_zval_ptr_ptr(&EX(opline)->op1, EX(Ts) TSRMLS_CC);
+       if (spl_implements(obj, spl_ce_iterator TSRMLS_CC)) {
+               spl_unlock_zval_ptr_ptr(&EX(opline)->op1, EX(Ts) TSRMLS_CC);
+               spl_begin_method_call_ex(obj, NULL, NULL, "new_iterator", sizeof("new_iterator")-1, &retval TSRMLS_CC);
+               if (!spl_implements(&retval, spl_ce_forward TSRMLS_CC)) {
+                       php_error_docref(NULL TSRMLS_CC, E_WARNING, "Objects created by new_iterator() must implement spl::forward");
+                       ZEND_EXECUTE_HOOK_ORIGINAL(ZEND_FE_RESET);
                }
+               PZVAL_LOCK(retval);
+       } else if (spl_implements(obj, spl_ce_forward TSRMLS_CC)) {
+               spl_unlock_zval_ptr_ptr(&EX(opline)->op1, EX(Ts) TSRMLS_CC);
+               (*obj)->refcount += 2; /* lock two times */
+               retval = *obj;
+       } else {
+               ZEND_EXECUTE_HOOK_ORIGINAL(ZEND_FE_RESET);
        }
-       ZEND_EXECUTE_HOOK_ORIGINAL(ZEND_FE_RESET);
+
+       /* create the proxy */
+       memset(&proxy, 0, sizeof(spl_foreach_proxy));
+       proxy.obj = retval;
+       proxy.obj_ce = spl_get_class_entry(retval TSRMLS_CC);
+       proxy.is_ce_assoc = spl_implements(&retval, spl_ce_assoc TSRMLS_CC);
+       /* And pack it into a zval. Since it is nowhere accessible using a 
+        * zval of type STRING is the fastest approach of storing the proxy.
+        */
+       ALLOC_INIT_ZVAL(retval);
+       ZVAL_STRINGL(retval, (char*)&proxy, sizeof(spl_foreach_proxy), 1);
+       retval->refcount += 2; /* lock two times */
+       /* return the created proxy container */
+       EX_T(EX(opline)->result.u.var).var.ptr = retval;
+       EX_T(EX(opline)->result.u.var).var.ptr_ptr = &EX_T(EX(opline)->result.u.var).var.ptr;
+
+       NEXT_OPCODE();
 }
 /* }}} */
 
@@ -109,24 +118,22 @@ ZEND_EXECUTE_HOOK_FUNCTION(ZEND_FE_FETCH)
        znode *op1 = &EX(opline)->op1;
        zval **obj = spl_get_zval_ptr_ptr(op1, EX(Ts) TSRMLS_CC);
        zval more, tmp, *value, *key, *result;
-       spl_foreach_proxy *proxy = (spl_foreach_proxy*)op1->u.EA.type;
+       spl_foreach_proxy *proxy;
 
-       if (proxy || spl_implements(obj, spl_ce_forward TSRMLS_CC)) {
-               if (!proxy) {
-                       (spl_foreach_proxy*)op1->u.EA.type = proxy = ezalloc(sizeof(spl_foreach_proxy));
-                       proxy->obj_ce = spl_get_class_entry(*obj TSRMLS_CC);
-               }
-               
+       if (Z_TYPE_PP(obj) == IS_STRING) {
                spl_unlock_zval_ptr_ptr(op1, EX(Ts) TSRMLS_CC);
                PZVAL_LOCK(*obj);
 
+               proxy = (spl_foreach_proxy*)Z_STRVAL_PP(obj);
+               obj = &proxy->obj; /* will be optimized out */
+
                if (proxy->index++) {
                        spl_begin_method_call_this(obj, proxy->obj_ce, &proxy->f_next, "next", sizeof("next")-1, &tmp TSRMLS_CC);
                } else {
-                       proxy->is_ce_assoc = spl_implements(obj, spl_ce_assoc TSRMLS_CC);
                        if (spl_implements(obj, spl_ce_sequence TSRMLS_CC)) {
                                spl_begin_method_call_this(obj, proxy->obj_ce, &proxy->f_rewind, "rewind", sizeof("rewind")-1, &tmp TSRMLS_CC);
                        }
+                       op_array->opcodes[EX(opline)->op2.u.opline_num].op2 = *op1;
                }
 
                spl_begin_method_call_this(obj, proxy->obj_ce, &proxy->f_more, "has_more", sizeof("has_more")-1, &more TSRMLS_CC);
@@ -195,8 +202,6 @@ ZEND_EXECUTE_HOOK_FUNCTION(ZEND_FE_FETCH)
 #endif
                        NEXT_OPCODE();
                }
-               efree(proxy);
-               op1->u.EA.type = 0;
                EX(opline) = op_array->opcodes+EX(opline)->op2.u.opline_num;
                return 0;
        }
@@ -204,6 +209,31 @@ ZEND_EXECUTE_HOOK_FUNCTION(ZEND_FE_FETCH)
 }
 /* }}} */
 
+/* {{{ ZEND_EXECUTE_HOOK_FUNCTION(ZEND_SWITCH_FREE) */
+ZEND_EXECUTE_HOOK_FUNCTION(ZEND_SWITCH_FREE)
+{
+       znode *op1 = &EX(opline)->op1;
+       znode *op2 = &EX(opline)->op2;
+       zval *tmp, **obj = spl_get_zval_ptr_ptr(op2, EX(Ts) TSRMLS_CC);
+       spl_foreach_proxy *proxy;
+
+       if (obj) {
+               proxy = (spl_foreach_proxy*)Z_STRVAL_PP(obj);
+               tmp = *obj;
+               *obj = proxy->obj; /* restore */
+
+               zval_dtor(tmp);
+               FREE_ZVAL(tmp);
+
+               spl_unlock_zval_ptr_ptr(op1, EX(Ts) TSRMLS_CC);
+               PZVAL_LOCK(*obj);
+               
+               SET_UNUSED(*op2);
+       }
+       ZEND_EXECUTE_HOOK_ORIGINAL(ZEND_SWITCH_FREE);
+}
+/* }}} */
+
 /*
  * Local variables:
  * tab-width: 4
index 427f331233ae3b532cf78495752d5b45e0e66e13..768ecd2ceaa45cb5d6196c154870d8bb647bc7b0 100755 (executable)
@@ -24,6 +24,7 @@
 
 ZEND_EXECUTE_HOOK_FUNCTION(ZEND_FE_RESET);
 ZEND_EXECUTE_HOOK_FUNCTION(ZEND_FE_FETCH);
+ZEND_EXECUTE_HOOK_FUNCTION(ZEND_SWITCH_FREE);
 
 #endif /* SPL_FOREACH_H */