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 相关文章推荐
一个php作的文本留言本的例子(五)
Oct 09 PHP
php5新改动之短标记启用方法
Sep 11 PHP
PHP逐行输出(ob_flush与flush的组合)
Feb 04 PHP
php define的第二个参数使用方法
Nov 04 PHP
php表单提交与$_POST实例分析
Jan 26 PHP
在PHP程序中使用Rust扩展的方法
Jul 03 PHP
Linux系统下使用XHProf和XHGui分析PHP运行性能
Dec 08 PHP
php关闭warning问题的解决方法
May 17 PHP
PHP Mysqli 常用代码集合
Nov 12 PHP
CI框架表单验证实例详解
Nov 21 PHP
详解PHP中的序列化、反序列化操作
Mar 21 PHP
详解如何在云服务器上部署Laravel
Jun 30 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下使用SimpleXML 处理XML 文件
2010/02/27 PHP
基于session_unset与session_destroy的区别详解
2013/06/03 PHP
smarty模板引擎基础知识入门
2015/03/30 PHP
PHP实现支持加盐的图片加密解密
2016/09/09 PHP
PHP Header失效的原因分析及解决方法
2016/11/16 PHP
php实现在线考试系统【附源码】
2018/09/18 PHP
jquery的颜色选择插件实例代码
2008/10/02 Javascript
深入理解Javascript中的循环优化
2013/11/09 Javascript
jQuery插件实现大图全屏图片相册
2015/03/14 Javascript
Nodejs学习笔记之入门篇
2015/04/16 NodeJs
json对象与数组以及转换成js对象的简单实现方法
2016/06/24 Javascript
javascript特效实现——当前时间和倒计时效果的简单实例
2016/07/20 Javascript
jQuery简单创建节点的方法
2016/09/09 Javascript
JavaScript每天必学之事件
2016/09/18 Javascript
webpack 开发和生产并行设置的方法
2018/11/08 Javascript
JS双向链表实现与使用方法示例(增加一个previous属性实现)
2019/01/31 Javascript
关于Vue中axios的封装实例详解
2019/10/20 Javascript
[02:55]含熏伴清风,风行者至宝、屠夫身心及典藏宝瓶二展示
2020/09/08 DOTA
Python getopt模块处理命令行选项实例
2014/05/13 Python
Python中的time模块与datetime模块用法总结
2016/06/30 Python
Python实现自定义顺序、排列写入数据到Excel的方法
2018/04/23 Python
django从请求到响应的过程深入讲解
2018/08/01 Python
python 三元运算符使用解析
2019/09/16 Python
使用matplotlib动态刷新指定曲线实例
2020/04/23 Python
python实现二分类和多分类的ROC曲线教程
2020/06/15 Python
分享8款纯CSS3实现的搜索框功能
2017/09/14 HTML / CSS
html5文本内容_动力节点Java学院整理
2017/07/11 HTML / CSS
详解如何通过H5(浏览器/WebView/其他)唤起本地app
2017/12/11 HTML / CSS
俄罗斯品牌服装和鞋子在线商店:BRIONITY
2020/03/26 全球购物
同步和异步有何异同,在什么情况下分别使用他们?
2012/12/28 面试题
护理职业应聘自荐书
2013/09/29 职场文书
教师实习自我鉴定
2013/12/18 职场文书
经理助理岗位职责
2014/03/05 职场文书
小学竞选班干部演讲稿
2014/08/20 职场文书
个人收入证明模板
2014/09/18 职场文书
奥巴马开学演讲观后感
2015/06/12 职场文书