foreach 遍历数组很常见,同样foreach也可以遍历对象
做如下测试:
class my
{
public $a = 'a';
protected $b = 'b';
private $c = 'c';
private $data = array('fantasy','windows','linux');
// 内部foreach遍历class
function traversable()
{
foreach($this as $key=>$val)
{
echo $key.'=>';
print_r($val);
echo '
';
}
}
}
$m = new my();
// 外部foreach遍历class
foreach($m as $key=>$val)
{
echo $key.'=>';
print_r($val);
echo '
';
}
echo '--------------------------
';
// 内部foreach遍历class
$m->traversable();
a=>a
--------------------------
a=>a
b=>b
c=>c
data=>Array ( [0] => fantasy [1] => windows [2] => linux )
今天在写PDO的时候发现可以这样写:
foreach($db->query('SELECT * FROM tab') as $row)
{
print_r($row);
}
object(PDOStatement)#2 (1) {
["queryString"]=>
string(18) "SELECT * FROM user"
}
关于迭代器看下面的例子:
class test implements Iterator
{
public $a = 'a';
private $data = array('apple','banlance','current');
private $point = 0;
public function __construct()
{
$this->point = 0;
}
public function current()
{
return $this->data[$this->point];
}
public function key()
{
return $this->point;
}
public function next()
{
++$this->point;
}
public function rewind()
{
$this->point=0;
}
public function valid()
{
return isset($this->data[$this->point]);
}
}
$t = new test();
foreach($t as $val)
{
print_r($val);
echo '
';
}
apple
banlance
current
// 迭代过程伪代码
while(valid)
{
current/key
next
}
rewind
so,之前的foreach对class的处理过程是一种默认方法,如果是继承iterator的class被foreach遍历的时候是上面这种方式
由此情况去套用 PDO的写法还是行不通,因为如果我们var_dump上面的哪个test类结果是这样的:
test Object
(
[a] => a
[data:test:private] => Array
(
[0] => apple
[1] => banlance
[2] => current
)
[point:test:private] => 0
)
由此我们可以猜测PDOStatement继承了一种迭代的接口但是并不是iterator
查看手册可以发现:
PDOStatement implements Traversable
由此明白了,PDOStatement的迭代实现都是在内部,继承iterator是php脚本的实现方式。
大致总结下:
foreach是可以遍历数组的,也可以遍历对象。对象只能罗列出public的属性,如果想要foreach罗列出保护的属性可以让class继承iterator并实现其中的方法,这样foreach遍历一个class的时候是按照class内部实现的iterator进行处理的。
-------------------------------------------------------------
PDO的问题:
PDO::query() 返回的是对象 PDOStatement (继承的Traversable这个空接口,必须由Iterator or iteratorAggregate 接口实现)。
PDOStatement 实现了Iterator接口的方法,其实现方法中操作的就是非public修饰的属性,这个属性里面存储的是查询结果集。
至此,foreach($db->query('sql..') as $row) 的执行过程明白了