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


Posted in PHP onAugust 09, 2013

刚接触到题的时候,我也没有考虑到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 相关文章推荐
对盗链说再见...
Oct 09 PHP
PHP filter_var() 函数 Filter 函数
Apr 25 PHP
PHP 过滤页面中的BOM(实现代码)
Jun 29 PHP
PHP大批量插入数据库的3种方法和速度对比
Jul 08 PHP
PHP中让curl支持sock5的代码实例
Jan 21 PHP
PHP进程同步代码实例
Feb 12 PHP
PHP isset()与empty()的使用区别详解
Feb 10 PHP
php格式文件打开的四种方法
Feb 24 PHP
PHP设计模式之单例模式定义与用法分析
Mar 26 PHP
thinkPHP框架通过Redis实现增删改查操作的方法详解
May 13 PHP
laravel 执行迁移回滚示例
Oct 23 PHP
php 下 html5 XHR2 + FormData + File API 上传文件操作实例分析
Feb 28 PHP
php接口与接口引用的深入解析
Aug 09 #PHP
解析数组非数字键名引号的必要性
Aug 09 #PHP
php防注入及开发安全详细解析
Aug 09 #PHP
分割GBK中文遭遇乱码的解决方法
Aug 09 #PHP
解析isset与is_null的区别
Aug 09 #PHP
PHP中怎样保持SESSION不过期 原理及方案介绍
Aug 08 #PHP
php中用socket模拟http中post或者get提交数据的示例代码
Aug 08 #PHP
You might like
smarty模板判断数组为空的方法
2015/06/10 PHP
yii实现model添加默认值的方法(2种方法)
2016/01/06 PHP
php封装的page分页类完整实例
2016/10/18 PHP
Javascript处理DOM元素事件实现代码
2012/05/23 Javascript
js弹出框轻量级插件jquery.boxy使用介绍
2013/01/15 Javascript
深入理解JavaScript系列(37):设计模式之享元模式详解
2015/03/04 Javascript
JavaScript入门系列之知识点总结
2016/03/24 Javascript
Angularjs中UI Router的使用方法
2016/05/14 Javascript
js实现可键盘控制的简单抽奖程序
2016/07/13 Javascript
js制作网站首页图片轮播特效代码
2016/08/30 Javascript
JS 实现可停顿的垂直滚动实例代码
2016/11/23 Javascript
Node.js连接MongoDB数据库产生的问题
2017/02/08 Javascript
JavaScript数据结构之二叉树的删除算法示例
2017/04/13 Javascript
jquery.guide.js新版上线操作向导镂空提示jQuery插件(推荐)
2017/05/20 jQuery
Vue 表单控件绑定的实现示例
2017/08/11 Javascript
如何开发出更好的JavaScript模块
2017/12/22 Javascript
JavaScript实现元素滚动条到达一定位置循环追加内容
2017/12/28 Javascript
浅谈用Webpack路径压缩图片上传尺寸获取的问题
2018/02/22 Javascript
浅谈React高阶组件
2018/03/28 Javascript
Vue瀑布流插件的使用示例
2018/09/19 Javascript
vue中的ref和$refs的使用
2018/11/22 Javascript
浅析Proxy可以优化vue的数据监听机制问题及实现思路
2018/11/29 Javascript
用node.js写一个jenkins发版脚本
2019/05/21 Javascript
用python写asp详细讲解
2013/12/16 Python
Python监控主机是否存活并以邮件报警
2015/09/22 Python
python中print()函数的“,”与java中System.out.print()函数中的“+”功能详解
2017/11/24 Python
Django如何配置mysql数据库
2018/05/04 Python
python实现多张图片拼接成大图
2019/01/15 Python
解决python线程卡死的问题
2019/02/18 Python
css3 伪类选择器快速复习小结
2019/09/10 HTML / CSS
教师党员思想汇报
2014/01/06 职场文书
团队口号大全
2014/06/06 职场文书
简易离婚协议书范本2014
2014/10/15 职场文书
大学生实训报告总结
2014/11/05 职场文书
小学生读书笔记范文
2015/06/30 职场文书
国庆节新闻稿
2015/07/17 职场文书