对于php来说,foreach是十分不便好用的一个语法,简直对于每一个PHPer它都是日常接触最多的申请之一。那么对象是否能通过foreach来遍历呢?

答案是必定的,然而有个条件,那就是对象的遍历只能取得它的公共属性。

// 一般遍历class A{    public $a1 = '1';    public $a2 = '2';    public $a3 = '3';    private $a4 = '4';    protected $a5 = '5';    public $a6 = '6';    public function test()    {        echo 'test';    }}$a = new A();foreach ($a as $k => $v) {    echo $k, '===', $v, PHP_EOL;}// a1===1// a2===2// a3===3// a6===6

不论是办法还是受爱护或者公有的变量,都无奈遍历进去。只有公共的属性能力被遍历进去。其实,咱们之前在讲设计模式时讲过的迭代器模式就是专门用来进行对象遍历的,而且PHP曾经为咱们筹备好了相干的接口,咱们只须要去实现这个接口就能够实现迭代器模式的创立了。具体的内容能够参考之前的设计模式系列文章:PHP设计模式之迭代器模式

// 实现迭代器接口class B implements Iterator{    private $var = [];    public function __construct($array)    {        if (is_array($array)) {            $this->var = $array;        }    }    public function rewind()    {        echo "rewinding\n";        reset($this->var);    }    public function current()    {        $var = current($this->var);        echo "current: $var\n";        return $var;    }    public function key()    {        $var = key($this->var);        echo "key: $var\n";        return $var;    }    public function next()    {        $var = next($this->var);        echo "next: $var\n";        return $var;    }    public function valid()    {        $var = $this->current() !== false;        echo "valid: {$var}\n";        return $var;    }}$b = new B([1, 2, 3, 4]);foreach ($b as $k => $v) {    echo $k, '===', $v, PHP_EOL;}// rewinding// current: 1// valid: 1// current: 1// key: 0// 0===1// next: 2// current: 2// valid: 1// current: 2// key: 1// 1===2// next: 3// current: 3// valid: 1// current: 3// key: 2// 2===3// next: 4// current: 4// valid: 1// current: 4// key: 3// 3===4// next:// current:// valid:

如果明天的文章只是讲之前讲过的迭代器模式,那就太没意思了,所以,咱们还要来学习一个更有意思的利用。那就是让对象能够像数组一样进行操作。这个其实也是应用PHP早已为咱们筹备好的一个接口:ArrayAccess。

// 让类能够像数组一样操作class C implements ArrayAccess, IteratorAggregate{    private $container = [];    public function __construct()    {        $this->container = [            "one" => 1,            "two" => 2,            "three" => 3,        ];    }    public function offsetSet($offset, $value)    {        if (is_null($offset)) {            $this->container[] = $value;        } else {            $this->container[$offset] = $value;        }    }    public function offsetExists($offset)    {        return isset($this->container[$offset]);    }    public function offsetUnset($offset)    {        unset($this->container[$offset]);    }    public function offsetGet($offset)    {        return isset($this->container[$offset]) ? $this->container[$offset] : null;    }    public function getIterator() {        return new B($this->container);    }}$c = new C();var_dump($c);$c['four'] = 4;var_dump($c);$c[] = 5;$c[] = 6;var_dump($c);foreach($c as $k=>$v){    echo $k, '===', $v, PHP_EOL;}// rewinding// current: 1// valid: 1// current: 1// key: one// one===1// next: 2// current: 2// valid: 1// current: 2// key: two// two===2// next: 3// current: 3// valid: 1// current: 3// key: three// three===3// next: 4// current: 4// valid: 1// current: 4// key: four// four===4// next: 5// current: 5// valid: 1// current: 5// key: 0// 0===5// next: 6// current: 6// valid: 1// current: 6// key: 1// 1===6// next: // current: // valid: 

这个接口须要咱们实现四个办法:

  • offsetSet($offset, $value),依据偏移量设置值
  • offsetExists($offset),依据偏移量确定是否存在内容
  • offsetUnset($offset),依据偏移量删除内容
  • offsetGet($offset),依据依稀量获取内容

这里的偏移量就是咱们常说的下标。通过实现这四个办法,咱们就能够像操作数组一样的操作对象。当然,日常开发中咱们可能并不会很常常的应用包含迭代器在内的这些对象遍历的能力。通常咱们会间接去将对象转换成数组 (array) obj 来进行下一步的操作。不过,在java中,特地是JavaBean中会常常在类的外部有一个 List<T> 为本人的对象来示意本身的汇合状态。通过比照,咱们发现PHP也齐全能够实现这样的能力,而且应用迭代器和 ArrayAccess 接口还可能更不便的实现相似的能力。这是十分有用的一种常识扩大,或者下一个我的项目中你就能使用上这些能力哦!

测试代码:
https://github.com/zhangyue0503/dev-blog/blob/master/php/201912/source/PHP%E6%80%8E%E4%B9%88%E9%81%8D%E5%8E%86%E5%AF%B9%E8%B1%A1%EF%BC%9F.php

参考文档:

https://www.php.net/manual/zh/language.oop5.iterations.php

各自媒体平台均可搜寻【硬核项目经理】