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 相关文章推荐
第十节 抽象方法和抽象类 [10]
Oct 09 PHP
用PHP+MySql编写聊天室
Oct 09 PHP
WordPress判断用户是否登录的代码
Mar 17 PHP
PHP删除非空目录的函数代码小结
Feb 28 PHP
javascript some()函数用法详解
Nov 13 PHP
WordPress主题中添加文章列表页页码导航的PHP代码实例
Dec 22 PHP
PHP实现长文章分页实例代码(附源码)
Feb 03 PHP
详解PHP中foreach的用法和实例
Oct 25 PHP
关于php几种字符串连接的效率比较(详解)
Feb 22 PHP
php curl获取到json对象并转成数组array的方法
May 31 PHP
安装docker和docker-compose实例详解
Jul 30 PHP
laravel5.6中的外键约束示例
Oct 23 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程序之die调试法 快速解决错误
2009/09/17 PHP
PHP中全面阻止SQL注入式攻击分析小结
2012/01/30 PHP
摘自织梦CMS中的图片处理类
2015/08/08 PHP
php反射学习之不用new方法实例化类操作示例
2019/06/14 PHP
键盘 keycode的值 javascript时触发事件时很有用的要素
2009/11/02 Javascript
收集的10个免费的jQuery相册
2011/02/26 Javascript
Jquery阻止事件冒泡 event.stopPropagation
2011/12/11 Javascript
Extjs Label的 fieldLabel和html属性值对齐的方法
2014/06/15 Javascript
jQuery获取访问者IP地址的方法(基于新浪API与QQ查询接口)
2016/05/25 Javascript
jquery动态添加文本并获取值的方法
2016/10/12 Javascript
AngularJS中指令的四种基本形式实例分析
2016/11/22 Javascript
Bootstrap整体框架之JavaScript插件架构
2016/12/15 Javascript
基于JS设计12306登录页面
2016/12/28 Javascript
AngularJs 利用百度地图API 定位当前位置 获取地址信息
2017/01/18 Javascript
vue-cli项目如何使用vue-resource获取本地的json数据(模拟服务端返回数据)
2017/08/04 Javascript
jQuery实现所有验证通过方可提交的表单验证
2017/11/21 jQuery
vue中eventbus被多次触发以及踩过的坑
2017/12/02 Javascript
webpack dll打包重复问题优化的解决
2018/10/10 Javascript
微信小程序8种数据通信的方式小结
2020/02/03 Javascript
通过实例解析JavaScript常用排序算法
2020/09/02 Javascript
[01:15:12]DOTA2上海特级锦标赛主赛事日 - 1 败者组第一轮#4Newbee VS CDEC
2016/03/03 DOTA
Windows下python2.7.8安装图文教程
2016/05/26 Python
Python爬取APP下载链接的实现方法
2016/09/30 Python
Tensorflow简单验证码识别应用
2017/05/25 Python
Django使用Celery异步任务队列的使用
2018/03/13 Python
解决Pycharm中import时无法识别自己写的程序方法
2018/05/18 Python
python3 enum模块的应用实例详解
2019/08/12 Python
python实现交并比IOU教程
2020/04/16 Python
Python 爬虫性能相关总结
2020/08/03 Python
Python3使用 GitLab API 进行批量合并分支
2020/10/15 Python
HTML5 audio标签使用js进行播放控制实例
2015/04/24 HTML / CSS
2014城乡环境综合治理工作总结
2014/12/19 职场文书
学长教您写论文:经验总结
2019/07/09 职场文书
详解MySQL主从复制及读写分离
2021/05/07 MySQL
Nginx源码编译安装过程记录
2021/11/17 Servers
python数据可视化使用pyfinance分析证券收益示例详解
2021/11/20 Python