說明:本文章主要講述PHP的對象遍歷(Iterator)知識點。因爲Laravel框架中就在集合(Collection)中用到了對象遍歷知識點,故記錄並學習之。同時,做者會將開發過程當中的一些截圖和代碼黏上去,提升閱讀效率。php
Laravel中在基礎集合類IlluminateSupportCollection
、路由類中IlluminateRoutingRouteCollection
和分頁類中IlluminatePaginationPaginator
等,都用到了對象遍歷這個小知識點,這些類都是實現了IteratorAggregate
這個接口,這個接口定義getIterator()
,返回的是迭代器對象。PHP標準擴展庫中提供了不少默認迭代器實現類,比較經常使用的是數組迭代器對象ArrayIterator,參考官網:迭代器。laravel
PHP5提供了遍歷對象屬性的方法,並且默認是可見屬性,如代碼中foreach遍歷對象屬性,默認的都是可見屬性:程序員
<?php /** * Created by PhpStorm. * User: liuxiang * Date: 16/7/20 * Time: 17:29 */ class TestIterator { /** * @var string */ public $name = 'PHP'; /** * @var string */ public $address = 'php.net'; /** * @var string */ protected $sex = 'man'; /** * @var int */ private $age = 20; } $testIterator = new TestIterator(); foreach ($testIterator as $key => $value) { echo $key.':'.$value.PHP_EOL; }
輸出的是:api
name:PHP address:php.net
若是須要遍歷對象的不可見屬性,則在對象內部定義一個遍歷方法:數組
public function unAccessIterator() { echo 'Iterator the unaccess fields:'.PHP_EOL; foreach ($this as $key => $value) { echo $key.':'.$value.PHP_EOL; } }
對象外部訪問:composer
$testIterator->unAccessIterator();
將能夠遍歷對象的不可見屬性,輸出結果:框架
Iterator the unaccess fields: name:PHP address:php.net sex:man age:20
PHP提供了Iterator接口,用來定義迭代器對象來自定義遍歷,因此利用Iterator接口來構造迭代器,須要實現Iterator定義的幾個方法:學習
<?php /** * Created by PhpStorm. * User: liuxiang * Date: 16/7/20 * Time: 17:29 */ class TestIterator implements Iterator{ /** * @var string */ public $name = 'PHP'; /** * @var string */ public $address = 'php.net'; /** * @var string */ protected $sex = 'man'; /** * @var int */ private $age = 20; /** * @var array */ private $composerPackage; public function __construct($composerPackage = []) { $this->composerPackage = $composerPackage; } public function unAccessIterator() { echo 'Iterator the unaccess fields:'.PHP_EOL; foreach ($this as $key => $value) { echo $key.':'.$value.PHP_EOL; } } /** * Return the current element * @link http://php.net/manual/en/iterator.current.php * @return mixed Can return any type. * @since 5.0.0 */ public function current() { // TODO: Implement current() method. echo 'Return the current element:'.PHP_EOL; return current($this->composerPackage); } /** * Move forward to next element * @link http://php.net/manual/en/iterator.next.php * @return void Any returned value is ignored. * @since 5.0.0 */ public function next() { // TODO: Implement next() method. echo 'Move forward to next element:'.PHP_EOL; return next($this->composerPackage); } /** * Return the key of the current element * @link http://php.net/manual/en/iterator.key.php * @return mixed scalar on success, or null on failure. * @since 5.0.0 */ public function key() { // TODO: Implement key() method. echo 'Return the key of the current element:'.PHP_EOL; return key($this->composerPackage); } /** * Checks if current position is valid * @link http://php.net/manual/en/iterator.valid.php * @return boolean The return value will be casted to boolean and then evaluated. * Returns true on success or false on failure. * @since 5.0.0 */ public function valid() { // TODO: Implement valid() method. echo 'Checks if current position is valid:'.PHP_EOL; return current($this->composerPackage) !== false; } /** * Rewind the Iterator to the first element * @link http://php.net/manual/en/iterator.rewind.php * @return void Any returned value is ignored. * @since 5.0.0 */ public function rewind() { // TODO: Implement rewind() method. echo 'Rewind the Iterator to the first element:'.PHP_EOL; reset($this->composerPackage); } } /* $testIterator = new TestIterator(); foreach ($testIterator as $key => $value) { echo $key.':'.$value.PHP_EOL; } $testIterator->unAccessIterator();*/ $testIterator = new TestIterator([ 'symfony/http-foundation', 'symfony/http-kernel', 'guzzle/guzzle', 'monolog/monolog' ]); foreach ($testIterator as $key => $value) { echo $key.':'.$value.PHP_EOL; }
成員變量$composerPackage是不可見的,經過實現Iterator接口,一樣能夠遍歷自定義的可不見屬性,輸出結果以下:this
Rewind the Iterator to the first element: Checks if current position is valid: Return the current element: Return the key of the current element: 0:symfony/http-foundation Move forward to next element: Checks if current position is valid: Return the current element: Return the key of the current element: 1:symfony/http-kernel Move forward to next element: Checks if current position is valid: Return the current element: Return the key of the current element: 2:guzzle/guzzle Move forward to next element: Checks if current position is valid: Return the current element: Return the key of the current element: 3:monolog/monolog Move forward to next element: Checks if current position is valid:
PHP真心爲程序員考慮了不少,實現IteratorAggragate接口後只需實現getIterator()
方法直接返回迭代器對象,就不須要實現Iterator接口須要的一些方法來建立一些迭代器對象,由於PHP已經提供了不少迭代器對象如ArrayIterator對象。因此再重構下上面代碼:lua
class TestCollection implements IteratorAggregate{ ... /** * @var array */ private $composerPackage; ... /** * Retrieve an external iterator * @link http://php.net/manual/en/iteratoraggregate.getiterator.php * @return Traversable An instance of an object implementing <b>Iterator</b> or * <b>Traversable</b> * @since 5.0.0 */ public function getIterator() { // TODO: Implement getIterator() method. return new ArrayIterator($this->composerPackage); } } $testCollection = new TestCollection([ 'symfony/http-foundation', 'symfony/http-kernel', 'guzzle/guzzle', 'monolog/monolog' ]); foreach ($testCollection as $key => $value) { echo $key.':'.$value.PHP_EOL; }
一樣的,能遍歷$testCollection對象的不可見屬性$composerPackage,輸出結果:
0:symfony/http-foundation 1:symfony/http-kernel 2:guzzle/guzzle 3:monolog/monolog
文章開頭聊到Laravel中就用到了IteratorAggragate這個接口,能夠看看文件的源碼。
總結:PHP提供的對象遍歷特性功能仍是頗有用處的,下一篇準備看下generator生成器知識點,generator提供了另一種方式定義Iterator。多多使用Laravel,研究Laravel源碼並模仿之,也不錯哦。