How can an object perform a foreach loop like an array?
I didn't take into account the Iterator mode when I first got into touch with the question. I tried some general ideas, and after the failure .... I directly looked at the source code implementation of foreach, hoping to find out whether there is any special feature when foreach processes objects. It can be used as a breakthrough.
After tracking for half a day, we found a strange switch in the core logic:
- 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;
- }
From this structure, we can see that the objects are divided into ZEND_ITER_OBJECT and ZEND_ITER_PLAIN_OBJECT. What does this mean?
- 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;
- }
- }
This is about PHP's built-in interface Iterator. PHP5 starts to support interfaces and has built-in Iterator interfaces. Therefore, if you define a class and implement the Iterator interface, then, your class object is ZEND_ITER_OBJECT. Otherwise, it is ZEND_ITER_PLAIN_OBJECT.
For the class ZEND_ITER_PLAIN_OBJECT, foreach obtains the default attribute array of the object through HASH_OF, and then performs foreach on the array.
For the class object of ZEND_ITER_OBJECT, The foreach and Iterator interfaces are performed by calling the iterator Interface related functions implemented by the object:
IteratorExtends
Traversable{/* Method */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)
}
Therefore, you can give the following answers to this question:
- 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;
- }
The above code runs normally in my php 5.3.
Address: http://www.laruence.com/2008/10/31/574.html