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 字符串 小常识
Jun 05 PHP
php 应用程序安全防范技术研究
Sep 25 PHP
PHP 冒泡排序算法的实现代码
Aug 08 PHP
javascript,php获取函数参数对象的代码
Feb 03 PHP
探讨php中防止SQL注入最好的方法是什么
Jun 10 PHP
php实现的一个很好用HTML解析器类可用于采集数据
Sep 23 PHP
ThinkPHP采用实现三级循环代码实例
Jul 18 PHP
ThinkPHP框架设计及扩展详解
Nov 25 PHP
PHP转盘抽奖接口实例
Feb 09 PHP
浅析php设计模式之数据对象映射模式
Mar 03 PHP
利用PHP将图片转换成base64编码的实现方法
Sep 13 PHP
实现PHP搜索加分页
Oct 12 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
判“新”函数:得到今天与明天的秒数
2006/10/09 PHP
PHP实现对文本数据库的常用操作方法实例演示
2014/07/04 PHP
php中有关合并某一字段键值相同的数组合并的改进
2015/03/10 PHP
使用PHPExcel实现数据批量导出为excel表格的方法(必看)
2017/06/09 PHP
Laravel中Facade的加载过程与原理详解
2017/09/22 PHP
php微信扫码支付 php公众号支付
2019/03/24 PHP
详解PHP素材图片上传、下载功能
2019/04/12 PHP
extjs 列表框(multiselect)的动态添加列表项的方法
2009/07/31 Javascript
基于jquery实现的鼠标滑过按钮改变背景图片
2011/07/15 Javascript
javascript实现日历控件(年月日关闭按钮)
2012/12/12 Javascript
js写的方法实现上传图片之后查看大图
2014/03/05 Javascript
点评js异步加载的4种方式
2015/12/22 Javascript
javascript每日必学之循环
2016/02/19 Javascript
jQuery niceScroll滚动条错位问题的解决方法
2018/02/03 jQuery
JS module的导出和导入的实现代码
2019/02/25 Javascript
微信小程序template模板与component组件的区别和使用详解
2019/05/22 Javascript
Python中实现字符串类型与字典类型相互转换的方法
2014/08/18 Python
python编写暴力破解FTP密码小工具
2014/11/19 Python
Python实现提取文章摘要的方法
2015/04/21 Python
python更新列表的方法
2015/07/28 Python
简单实现python爬虫功能
2015/12/31 Python
python递归查询菜单并转换成json实例
2017/03/27 Python
使用Python进行QQ批量登录的实例代码
2018/06/11 Python
使用Python自动化破解自定义字体混淆信息的方法实例
2019/02/13 Python
Django数据库类库MySQLdb使用详解
2019/04/28 Python
梅尔倒谱系数(MFCC)实现
2019/06/19 Python
python启动应用程序和终止应用程序的方法
2019/06/28 Python
python使用装饰器作日志处理的方法
2019/07/11 Python
Python替换月份为英文缩写的实现方法
2019/07/15 Python
python单例模式的应用场景实例讲解
2021/02/24 Python
Html5自定义字体解决方法
2019/10/09 HTML / CSS
Bloomingdale’s阿联酋:选购奢华时尚、美容及更多
2020/09/22 全球购物
德国二手设计师时装和复古时装跳蚤市场:Mädchenflohmarkt
2020/11/09 全球购物
建筑设计师岗位职责
2013/11/18 职场文书
自我评价怎么写正确呢?
2013/12/02 职场文书
财务方面个人工作的自我评价
2013/12/28 职场文书