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 相关文章推荐
phpinfo 系统查看参数函数代码
Jun 05 PHP
php 攻击方法之谈php+mysql注射语句构造
Oct 30 PHP
PHP执行zip与rar解压缩方法实现代码
Dec 05 PHP
PHP中使用smarty生成静态文件的例子
Apr 24 PHP
ThinkPHP CURD方法之where方法详解
Jun 18 PHP
smarty模板引擎中自定义函数的方法
Jan 22 PHP
PHP实现连接设备、通讯和发送命令的方法
Oct 13 PHP
php文件上传后端处理小技巧
May 22 PHP
PHP实现PDO操作mysql存储过程示例
Feb 13 PHP
PHP将整数数字转换为罗马数字实例分享
Mar 17 PHP
50个优秀经典PHP算法大集合 附源码
Aug 26 PHP
如何在Mac上通过docker配置PHP开发环境
May 29 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
php 随机排序广告的实现代码
2011/05/09 PHP
对象失去焦点时自己动提交数据的实现代码
2012/11/06 PHP
PHP仿qq空间或朋友圈发布动态、评论动态、回复评论、删除动态或评论的功能(上)
2017/05/26 PHP
Laravel框架自定义分页样式操作示例
2020/01/26 PHP
JS支持带x身份证号码验证函数
2008/08/10 Javascript
Mootools 1.2教程 滚动条(Slider)
2009/09/15 Javascript
JavaScript 通过模式匹配实现重载
2010/08/12 Javascript
原生js实现给指定元素的后面追加内容
2013/04/10 Javascript
浅谈javascript的调试
2015/01/28 Javascript
jquery trigger函数执行两次的解决方法
2016/02/29 Javascript
jQuery禁用快捷键例如禁用F5刷新 禁用右键菜单等的简单实现
2016/08/31 Javascript
原生js实现放大镜
2017/02/20 Javascript
JavaScript实现三级联动效果
2017/07/15 Javascript
Bootstrap4如何定制自己的颜色和风格
2018/02/26 Javascript
JS加密插件CryptoJS实现的Base64加密示例
2020/08/16 Javascript
解决前后端分离 vue+springboot 跨域 session+cookie失效问题
2019/05/13 Javascript
react使用antd表单赋值,用于修改弹框的操作
2020/10/29 Javascript
Vuex实现简单购物车
2021/01/10 Vue.js
python进阶教程之函数参数的多种传递方法
2014/08/30 Python
Python玩转加密的技巧【推荐】
2019/05/13 Python
django 中QuerySet特性功能详解
2019/07/25 Python
django项目用higcharts统计最近七天文章点击量
2019/08/17 Python
基于Python实现拆分和合并GIF动态图
2019/10/22 Python
opencv python Canny边缘提取实现过程解析
2020/02/03 Python
python实现mean-shift聚类算法
2020/06/10 Python
Python列表嵌套常见坑点及解决方案
2020/09/30 Python
解决pytorch 模型复制的一些问题
2021/03/03 Python
html5的自定义data-*属性与jquery的data()方法的使用
2014/07/02 HTML / CSS
澳大利亚天然护肤品、化妆品和健康产品一站式商店:Nourished Life
2018/12/02 全球购物
手工制作的豪华英式沙发和沙发床:Willow & Hall
2019/05/03 全球购物
2015新年寄语(一句话)
2014/12/08 职场文书
技术员岗位职责
2015/02/04 职场文书
工作推荐信模板
2015/03/25 职场文书
Go语言中break label与goto label的区别
2021/04/28 Golang
Python爬取英雄联盟MSI直播间弹幕并生成词云图
2021/06/01 Python
PyQt5结合QtDesigner实现文本框读写操作
2021/06/11 Python