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 相关文章推荐
防止MySQL注入或HTML表单滥用的PHP程序
Jan 21 PHP
解析如何去掉CodeIgniter URL中的index.php
Jun 25 PHP
json的键名为数字时的调用方式(示例代码)
Nov 15 PHP
CodeIgniter安全相关设置汇总
Jul 03 PHP
php将日期格式转换成xx天前的格式
Apr 16 PHP
PHP封装的HttpClient类用法实例
Jun 17 PHP
浅谈PHP拦截器之__set()与__get()的理解与使用方法
Oct 18 PHP
PHP获取当前URL路径的处理方法(适用于多条件筛选列表)
Feb 10 PHP
php使用PDO下exec()函数查询执行后受影响行数的方法
Mar 28 PHP
PHP使用new StdClass()创建空对象的方法分析
Jun 06 PHP
PHP使用SOAP调用API操作示例
Dec 25 PHP
PHP PDOStatement::execute讲解
Jan 31 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 Mysql编程之高级技巧
2008/08/27 PHP
PHP学习之字符串比较和查找
2011/04/17 PHP
Laravel 5框架学习之Eloquent (laravel 的ORM)
2015/04/08 PHP
php中通用的excel导出方法实例
2017/12/30 PHP
php微信开发之关键词回复功能
2018/06/13 PHP
Jquery插件写法笔记整理
2012/09/06 Javascript
js jquery分别实现动态的文件上传操作按钮的添加和删除
2014/01/13 Javascript
关于js函数解释(包括内嵌,对象等)
2016/11/20 Javascript
nodeJS删除文件方法示例
2016/12/25 NodeJs
如何使用electron-builder及electron-updater给项目配置自动更新
2018/12/24 Javascript
JS添加或删除HTML dom元素的方法实例分析
2019/03/05 Javascript
微信小程序学习笔记之跳转页面、传递参数获得数据操作图文详解
2019/03/28 Javascript
详解vue为什么要求组件模板只能有一个根元素
2019/07/22 Javascript
vue实现配置全局访问路径头(axios)
2019/11/01 Javascript
解决VUEX的mapState/...mapState等取值问题
2020/07/24 Javascript
vue 使用饿了么UI仿写teambition的筛选功能
2021/03/01 Vue.js
分析python服务器拒绝服务攻击代码
2014/01/16 Python
Python爬取读者并制作成PDF
2015/03/10 Python
使用Python操作excel文件的实例代码
2017/10/15 Python
Python语言描述KNN算法与Kd树
2017/12/13 Python
Python实现的逻辑回归算法示例【附测试csv文件下载】
2018/12/28 Python
对Python获取屏幕截图的4种方法详解
2019/08/27 Python
美国美妆网站:B-Glowing
2016/10/12 全球购物
美国首屈一指的高品质珠宝设计师和零售商:Allurez
2018/01/23 全球购物
法国在线宠物店:zooplus.fr
2018/02/23 全球购物
值类型与引用类型有什么不同?请举例说明?并分别列举几种相应的数据类型
2015/10/24 面试题
交通专业个人自荐信格式
2013/09/23 职场文书
车间工艺员岗位职责
2013/12/09 职场文书
中式结婚主持词
2014/03/14 职场文书
应届大专毕业生自我鉴定
2014/04/08 职场文书
《她是我的朋友》教学反思
2014/04/26 职场文书
市场营销调查计划书
2014/05/02 职场文书
外贸采购员岗位职责
2015/04/03 职场文书
建筑工程挂靠协议书
2016/03/23 职场文书
2016年感恩教师节活动总结
2016/04/01 职场文书
python基于opencv批量生成验证码的示例
2021/04/28 Python