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
Discuz! 5.0.0论坛程序中加入一段js代码,让会员点击下载附件前自动弹出提示窗口
Apr 18 PHP
php debug 安装技巧
Apr 30 PHP
解析php二分法查找数组是否包含某一元素
May 23 PHP
PHP设计模式之命令模式的深入解析
Jun 13 PHP
php异步多线程swoole用法实例
Nov 14 PHP
php结合mysql与mysqli扩展处理事务的方法
Jun 29 PHP
iOS+PHP注册登录系统 PHP部分(上)
Dec 26 PHP
PHP 类与构造函数解析
Feb 06 PHP
Yii2 如何在modules中添加验证码的方法
Jun 19 PHP
phpfpm的作用和用法
Oct 10 PHP
分享几种好用的PHP自定义加密函数(可逆/不可逆)
Sep 15 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
模拟xcopy的函数
2006/10/09 PHP
php 缩略图实现函数代码
2011/06/23 PHP
PHP 转义使用详解
2013/07/15 PHP
php创建session的方法实例详解
2015/01/27 PHP
php实现字符串反转输出的方法
2015/03/14 PHP
php实现用已经过去多长时间的方式显示时间
2015/06/05 PHP
Joomla数据库操作之JFactory::getDBO用法
2016/05/05 PHP
thinkPHP数据库增删改查操作方法实例详解
2016/12/06 PHP
JS解密入门 最终变量劫持
2008/06/25 Javascript
关于javaScript注册click事件传递参数的不成功问题
2014/07/18 Javascript
javascript中bind函数的作用实例介绍
2014/09/28 Javascript
JavaScript通过prototype给对象定义属性用法实例
2015/03/23 Javascript
理解Javascript的动态语言特性
2015/06/17 Javascript
JavaScript多图片上传案例
2015/09/28 Javascript
Jquery元素追加和删除的实现方法
2016/05/24 Javascript
原生js实现网易轮播图效果
2020/04/10 Javascript
jQuery插件ajaxFileUpload使用实例解析
2016/10/19 Javascript
利用JS实现页面删除并重新排序功能
2016/12/09 Javascript
jquery实现提示语淡入效果
2017/05/05 jQuery
Angular项目中$scope.$apply()方法的使用详解
2017/07/26 Javascript
js 取消页面可以选中文字的功能方法
2018/01/02 Javascript
浅谈javascript错误处理
2019/08/11 Javascript
Windows系统下使用flup搭建Nginx和Python环境的方法
2015/12/25 Python
使用python生成杨辉三角形的示例代码
2018/08/29 Python
Python使用while循环花式打印乘法表
2019/01/28 Python
python manage.py runserver流程解析
2019/11/08 Python
Keras: model实现固定部分layer,训练部分layer操作
2020/06/28 Python
h5实现获取用户地理定位的实例代码
2017/07/17 HTML / CSS
意大利制造的男鞋和女鞋:SCAROSSO
2018/03/07 全球购物
zooplus波兰:在线宠物店
2019/07/21 全球购物
简述索引存取方法的作用和建立索引的原则
2013/03/26 面试题
简历中自我评价范文3则
2013/12/14 职场文书
企业元宵节主持词
2014/03/25 职场文书
党员学习正风肃纪思想汇报
2014/09/12 职场文书
2016入党积极分子党课学习心得体会
2015/10/09 职场文书
仅用几行Python代码就能复制她的U盘文件?
2021/06/26 Python