php中如何使对象可以像数组一样进行foreach循环

2015-01-24信息快讯网

php中如何使对象可以像数组一样进行foreach循环呢?下面小编就详细的为大家介绍一下吧!需要的朋友可以 过来参考下

刚接触到题的时候,我也没有考虑到Iterator模式,试了几个一般想法,失败以后。。。。就直接去翻看了foreach的源码实现,期望发现foreach处理对象的时候是否有什么特殊性,可以做为突破口。

跟踪了半天以后发现了核心逻辑中的一个奇怪的switch:

switch (zend_iterator_unwrap(array, &iter TSRMLS_CC)) {
        default:
        case ZEND_ITER_INVALID:
               .....
               break
        case ZEND_ITER_PLAIN_OBJECT: {
                ......
            break;
     case ZEND_ITER_PLAIN_ARRAY:
            .....
            break;
        case ZEND_ITER_OBJECT:
            ......
            break;
}

从这个结构,我们可以看到,对象分为ZEND_ITER_OBJECT和ZEND_ITER_PLAIN_OBJECT, 这是什么意思呢?
ZEND_API enum zend_object_iterator_kind zend_iterator_unwrap(
    zval *array_ptr, zend_object_iterator **iter TSRMLS_DC)
{
    switch (Z_TYPE_P(array_ptr)) {
        case IS_OBJECT:
            if (Z_OBJ_HT_P(array_ptr) == &iterator_object_handlers) {
                *iter = (zend_object_iterator *)zend_object_store_get_object(array_ptr TSRMLS_CC);
                return ZEND_ITER_OBJECT;
            }
            if (HASH_OF(array_ptr)) {
                return ZEND_ITER_PLAIN_OBJECT;
            }
            return ZEND_ITER_INVALID;
        case IS_ARRAY:
            if (HASH_OF(array_ptr)) {
                return ZEND_ITER_PLAIN_ARRAY;
            }
            return ZEND_ITER_INVALID;
        default:
            return ZEND_ITER_INVALID;
    }
}

这就要讲到PHP的内置接口Iterator了,PHP5开始支持了接口, 并且内置了Iterator接口, 所以如果你定义了一个类,并实现了Iterator接口,那么你的这个类对象就是ZEND_ITER_OBJECT,否则就是ZEND_ITER_PLAIN_OBJECT.

对于ZEND_ITER_PLAIN_OBJECT的类,foreach会通过HASH_OF获取该对象的默认属性数组,然后对该数组进行foreach.

而对于ZEND_ITER_OBJECT的类对象,则会通过调用对象实现的Iterator接口相关函数来进行foreach,iterator接口:

Iterator extends Traversable {
/* 方法 */
abstract public mixed current ( void )
abstract public scalar key ( void )
abstract public void next ( void )
abstract public void rewind ( void )
abstract public boolean valid ( void )
}

所以, 对于这道笔试题, 可以作出如下的答案:
class sample implements Iterator
{
    private $_items = array(1,2,3,4,5,6,7);
    public function __construct() {
                  ;//void
    }
    public function rewind() { reset($this->_items); }
    public function current() { return current($this->_items); }
    public function key() { return key($this->_items); }
    public function next() { return next($this->_items); }
    public function valid() { return ( $this->current() !== false ); }
}
$sa = new sample();
foreach($sa as $key => $val){
    print $key . "=>" .$val;
}

以上代码在我的php 5.3下运行正常。

php获取网卡的MAC地址支持WIN/LINUX系统
yii框架配置默认controller和action示例
php数组查找函数in_array()、array_search()、array_key_exists()使用实例
smarty模板中使用get、post、request、cookies、session变量的方法
php中有关字符串的4个函数substr、strrchr、strstr、ereg介绍和使用例子
PHP函数addslashes和mysql_real_escape_string的区别
CodeIgniter框架提示Disallowed Key Characters的解决办法
PHP5.5在windows安装使用memcached服务端的方法
用PHP和Shell写Hadoop的MapReduce程序
PHP header()函数常用方法总结
PHP扩展模块Pecl、Pear以及Perl的区别
PHP中的Memcache详解
PHP包含文件函数include、include_once、require、require_once区别总结
php警告Creating default object from empty value 问题的解决方法
PHP把网页保存为word文件的三种方法
PHP的password_hash()使用实例
php导出word文档与excel电子表格的简单示例代码
Drupal7 form表单二次开发要点与实例
PHP $_FILES中error返回值详解
浅析PHP原理之变量分离/引用(Variables Separation)
php接口与接口引用的深入解析
php number_format() 函数通过千位分组来格式化数字的实现代码
注意:php5.4删除了session_unregister函数
ueditor 1.2.6 使用方法说明
如何使用FireFox插件FirePHP调试PHP
请离开include_once和require_once
php/js获取客户端mac地址的实现代码
如何修改和添加Apache的默认站点目录
Apache实现Web Server负载均衡详解(不考虑Session版)
如何在Ubuntu下启动Apache的Rewrite功能
如何解决CI框架的Disallowed Key Characters错误提示
解析:php调用MsSQL存储过程使用内置RETVAL获取过程中的return值
解决PHP mysql_query执行超时(Fatal error: Maximum execution time …)
Smarty foreach控制循环次数的实现详解
php修改NetBeans默认字体的大小
解析PHP跳出循环的方法以及continue、break、exit的区别介绍
mongo Table类文件 获取MongoCursor(游标)的实现方法分析
深入解析php中的foreach问题
浅析HTTP消息头网页缓存控制以及header常用指令介绍
©2014-2024 dbsqp.com