- 本文地址: https://www.laruence.com/2008/10/31/574.html
- 转载请注明出处
中午的时候,收到一封求教信,是关于这样的一道面试题:
使对象可以像数组一样进行foreach循环,要求属性必须是私有。
刚接触到题的时候,我也没有考虑到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, 所以, 对于这道笔试题, 可以作出如下的答案:
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源码很关键啊
When you contacting Alexa Amazon, you have the option of sending an email, having Amazon call you, and live to chat. This article will show you how to talk with a customer service representative at Amazon. If you want to call Amazon directly, contact our customer service. Contacting Amazon Prime was a pure delight. We didn’t have to wait through a lengthy automated system; just a few options one being the customer support team.
https://alexaamazo.com/
Amazon Alexa is a useful add-on for users who have Alexa devices. The app can provide the latest updates on what’s happening in the world, play your favourite songs, address your questions, make lists and more.
改为
public function valid()
{
return $this->key() !== NULL;
}
$t = [
‘a’ => ‘yrt’,
‘yrt’ => ‘燕睿涛’,
3,
false,
‘燕睿涛’
];
循环输出有false的质的时候就会截断~~
最近在准备腾讯面试,看到了这个题,感觉到似乎有些问题?这样的实现只能对自己实现的迭代器遍历,且只能遍历封装好的数组属性,如果是一个已经定义好的类呢,里面的私有属性并不是封装在一个数组中,怎么遍历呢?
[…] 本文地址: http://www.laruence.com/2008/10/31/574.html […]
这个设计模式,应该起来比较难
[…] 在鸟哥的blog中,很久以前一篇文章对iterator的实现作了一些说明:http://www.laruence.com/2008/10/31/574.html 但是并没有对false的值的处理作相关说明 […]
next方法在接口的定义中其返回值为void
abstract public void next ( void )
话说我不知道SPL。。。残念
文章不错
这个题,其实考的就是 PHP SPL吧,不用看源码吧…
class test {
private $a = 1;
private $b = 2;
function getVars() {
$array = get_defined_vars();
return $array[‘this’];
}
}
$test = new test();
$testArr = $test->getVars();
print_r($testArr);
getVars();
print_r($testArr);
汗,这题是我出的,居然在这儿看到答案。。。面试题目要改一下了。
@alexsun, 幸会,幸会~~
关于SPL的中文资料很少,只能顶着E文
顶!
呵呵,这段时间也正在研究PHP源代码,比较想了解PHP的内部实现。
前几天正在想PHP是如何实现foreach循环的呢,正好搜到了。
foreach的原代码位置是哪里?楼主教一手吧 呵呵
foreach的结构相对来说比较复杂,它不是一整块的代码块,
它是在语法分析阶段, 做了一些工作.
大体就是,在语法分析阶段(zend_language_parser.y)的时候,分别通过定位,foreach开始,中间代码,结束,从而设置出一个带有的循环的OPCODES序列..大体就是这样,如果有兴趣,可以看看上面提到的源文件.
实现一个完整的迭代器不是那么容易的事情。PHP这种弱类型语言的做法比较灵活。JAVA的实现就比较复杂;C++这种半弱不强的就更难一点。类型的POD,trivial判断,还有参数传导需要很多技巧……
果然很土
在Zend Framework源码中可以看到大量SPL的应用
在看ZF代码之前我也确实还不知道居然有SPL这个东西
又要看源代码啊 🙂
呵呵,绕了弯路,不过, 一切的一切都是可以在源码找到答案的,呵呵
“对于ZEND_ITER_OBJECT的类对象,则会通过调用对象实现的Iterator接口相关函数来进行foreach”,这句话太关键了。
经验主义害死人啊,非常感谢楼主,我看明白了。
非常期待楼主出本PHP源码分析的书,从源码分析果然很好、很强大啊。
土了, 竟然不知道SPL,惭愧。
都是牛头哇!!!
哈哈
其实直接去php手册搜会更快知道怎么弄
不过这个php的源代码实现的似乎有点囧
恩,我走了弯路,我还想着是不是可以通过其他的什么方式来更简单的实现。