http://cn2.php.net/manual/en/function.print-r.phpRemember that print_r() will move the array pointer to the end. Use reset() to bring it back to beginning.== Test Code Below ==<?php
$a=array("test1", "test2", "test3");
echo current($a);
$t=print_r($a, true);
echo current($a);
?>
== Output ==test1test1测试表明使用print_r函数后,数组内部指针被移到起始元素位置了而不是末端,如何解释?

解决方案 »

  1.   

    print_r的函数在php5.3.2中是这么定义的
    PHP_FUNCTION(print_r)
    {
            zval *var;
            zend_bool do_return = 0;         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z|b", &var, &do_return) == FAILURE) {
                    RETURN_FALSE;
            }            if (do_return) {
                    php_start_ob_buffer (NULL, 0, 1 TSRMLS_CC);
            }            zend_print_zval_r(var, 0 TSRMLS_CC);        if (do_return) {
                    php_ob_get_buffer (return_value TSRMLS_CC);
                    php_end_ob_buffer (0, 0 TSRMLS_CC);
            } else {
                    RETURN_TRUE;
            }    
    }
    可以看出,实际上干活的是zend_print_zval_r,是它输出了变量,追踪这个函数
    ZEND_API void zend_print_zval_r(zval *expr, int indent TSRMLS_DC)
    {
            zend_print_zval_r_ex(zend_write, expr, indent TSRMLS_CC);
    }
    实际上调用了zend_print_zval_r_ex,继续追踪
    ZEND_API void zend_print_zval_r_ex(zend_write_func_t write_func, zval *expr, int indent TSRMLS_DC) /* {{{ */
    {
            switch (Z_TYPE_P(expr)) {
                    case IS_ARRAY:
                            ZEND_PUTS_EX("Array\n");
                            if (++Z_ARRVAL_P(expr)->nApplyCount>1) {
                                    ZEND_PUTS_EX(" *RECURSION*");
                                    Z_ARRVAL_P(expr)->nApplyCount--;
                                    return;
                            }    
                            print_hash(write_func, Z_ARRVAL_P(expr), indent, 0 TSRMLS_CC);
                            Z_ARRVAL_P(expr)->nApplyCount--;
                            break;
                    case IS_OBJECT:
                            {
                                    HashTable *properties;
                                    char *class_name = NULL;
                                    zend_uint clen;
                                    int is_temp;                                if (Z_OBJ_HANDLER_P(expr, get_class_name)) {
                                            Z_OBJ_HANDLER_P(expr, get_class_name)(expr, &class_name, &clen, 0 TSRMLS_CC);
                                    }
                                    if (class_name) {
                                            ZEND_PUTS_EX(class_name);
                                    } else {
                                            ZEND_PUTS_EX("Unknown Class");
                                    }
                                    ZEND_PUTS_EX(" Object\n");
                                    if (class_name) {
                                            efree(class_name);
                                    }
                                    if ((properties = Z_OBJDEBUG_P(expr, is_temp)) == NULL) {
                                            break;
                                    }
                                    if (++properties->nApplyCount>1) {
                                            ZEND_PUTS_EX(" *RECURSION*");
                                            properties->nApplyCount--;
                                            return;
                                    }
                                    print_hash(write_func, properties, indent, 1 TSRMLS_CC);
                                    properties->nApplyCount--;
                                    if (is_temp) {
                                            zend_hash_destroy(properties);
                                            efree(properties);
                                    }
                                    break;
                            }
                    default:
                            zend_print_zval_ex(write_func, expr, indent);
                            break;
            }
    }
    可见,输出数组时,实际上工作的是print_hash,继续追踪
    static void print_hash(zend_write_func_t write_func, HashTable *ht, int indent, zend_bool is_object TSRMLS_DC) /* {{{ */
    {
            zval **tmp;
            char *string_key;
            HashPosition iterator;
            ulong num_key;
            uint str_len;
            int i;        for (i = 0; i < indent; i++) {
                    ZEND_PUTS_EX(" ");
            }
            ZEND_PUTS_EX("(\n");
            indent += PRINT_ZVAL_INDENT;
            zend_hash_internal_pointer_reset_ex(ht, &iterator);
            while (zend_hash_get_current_data_ex(ht, (void **) &tmp, &iterator) == SUCCESS) {
                    for (i = 0; i < indent; i++) {
                            ZEND_PUTS_EX(" ");
                    }
                    ZEND_PUTS_EX("[");
                    switch (zend_hash_get_current_key_ex(ht, &string_key, &str_len, &num_key, 0, &iterator)) {
                            case HASH_KEY_IS_STRING:
                                    if (is_object) {
                                            char *prop_name, *class_name;
                                            int mangled = zend_unmangle_property_name(string_key, str_len - 1, &class_name, &prop_name);                                        ZEND_PUTS_EX(prop_name);
                                            if (class_name && mangled == SUCCESS) {
                                                    if (class_name[0]=='*') {
                                                            ZEND_PUTS_EX(":protected");
                                                    } else {
                                                            ZEND_PUTS_EX(":");
                                                            ZEND_PUTS_EX(class_name);
                                                            ZEND_PUTS_EX(":private");
                                                    }
                                            }
                                    } else {
                                            ZEND_WRITE_EX(string_key, str_len-1);
                                    }
                                    break;
                            case HASH_KEY_IS_LONG:
                                    {
                                            char key[25];
                                            snprintf(key, sizeof(key), "%ld", num_key);
                                            ZEND_PUTS_EX(key);
                                    }
                                    break;
                    }
                    ZEND_PUTS_EX("] => ");
                    zend_print_zval_r_ex(write_func, *tmp, indent+PRINT_ZVAL_INDENT TSRMLS_CC);
                    ZEND_PUTS_EX("\n");
                    zend_hash_move_forward_ex(ht, &iterator);
            }
            indent -= PRINT_ZVAL_INDENT;
            for (i = 0; i < indent; i++) {
                    ZEND_PUTS_EX(" ");
            }
            ZEND_PUTS_EX(")\n");
    }重点是这两句,含义是把ht->pListHead赋值给iterator
    HashPosition iterator;
    zend_hash_internal_pointer_reset_ex(ht, &iterator);
    综上,print_r输出数组时,根本没有用到数组的内部迭代器,因此用后无需reset但是最好还是reset一下,因为老版本的php可能用到了内部迭代器,
    用后不reset可能导致代码无法在老版本的php环境中运行。应该是php的文档没有跟上代码,有些迟滞了,将来会更新的。