See Release Notes
Long Term Support Release
Differences Between: [Versions 39 and 311] [Versions 39 and 400] [Versions 39 and 401]
1 <?php 2 /* 3 * Copyright 2017 MongoDB, Inc. 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18 namespace MongoDB\Model; 19 20 use Countable; 21 use Generator; 22 use Iterator; 23 use Traversable; 24 use function count; 25 use function current; 26 use function key; 27 use function next; 28 use function reset; 29 30 /** 31 * Iterator for wrapping a Traversable and caching its results. 32 * 33 * By caching results, this iterators allows a Traversable to be counted and 34 * rewound multiple times, even if the wrapped object does not natively support 35 * those operations (e.g. MongoDB\Driver\Cursor). 36 * 37 * @internal 38 */ 39 class CachingIterator implements Countable, Iterator 40 { 41 /** @var array */ 42 private $items = []; 43 44 /** @var Generator */ 45 private $iterator; 46 47 /** @var boolean */ 48 private $iteratorAdvanced = false; 49 50 /** @var boolean */ 51 private $iteratorExhausted = false; 52 53 /** 54 * Initialize the iterator and stores the first item in the cache. This 55 * effectively rewinds the Traversable and the wrapping Generator, which 56 * will execute up to its first yield statement. Additionally, this mimics 57 * behavior of the SPL iterators and allows users to omit an explicit call 58 * to rewind() before using the other methods. 59 * 60 * @param Traversable $traversable 61 */ 62 public function __construct(Traversable $traversable) 63 { 64 $this->iterator = $this->wrapTraversable($traversable); 65 $this->storeCurrentItem(); 66 } 67 68 /** 69 * @see http://php.net/countable.count 70 * @return integer 71 */ 72 public function count() 73 { 74 $this->exhaustIterator(); 75 76 return count($this->items); 77 } 78 79 /** 80 * @see http://php.net/iterator.current 81 * @return mixed 82 */ 83 public function current() 84 { 85 return current($this->items); 86 } 87 88 /** 89 * @see http://php.net/iterator.key 90 * @return mixed 91 */ 92 public function key() 93 { 94 return key($this->items); 95 } 96 97 /** 98 * @see http://php.net/iterator.next 99 * @return void 100 */ 101 public function next() 102 { 103 if (! $this->iteratorExhausted) { 104 $this->iterator->next(); 105 $this->storeCurrentItem(); 106 } 107 108 next($this->items); 109 } 110 111 /** 112 * @see http://php.net/iterator.rewind 113 * @return void 114 */ 115 public function rewind() 116 { 117 /* If the iterator has advanced, exhaust it now so that future iteration 118 * can rely on the cache. 119 */ 120 if ($this->iteratorAdvanced) { 121 $this->exhaustIterator(); 122 } 123 124 reset($this->items); 125 } 126 127 /** 128 * @see http://php.net/iterator.valid 129 * @return boolean 130 */ 131 public function valid() 132 { 133 return $this->key() !== null; 134 } 135 136 /** 137 * Ensures that the inner iterator is fully consumed and cached. 138 */ 139 private function exhaustIterator() 140 { 141 while (! $this->iteratorExhausted) { 142 $this->next(); 143 } 144 } 145 146 /** 147 * Stores the current item in the cache. 148 */ 149 private function storeCurrentItem() 150 { 151 $key = $this->iterator->key(); 152 153 if ($key === null) { 154 return; 155 } 156 157 $this->items[$key] = $this->iterator->current(); 158 } 159 160 /** 161 * Wraps the Traversable with a Generator. 162 * 163 * @param Traversable $traversable 164 * @return Generator 165 */ 166 private function wrapTraversable(Traversable $traversable) 167 { 168 foreach ($traversable as $key => $value) { 169 yield $key => $value; 170 $this->iteratorAdvanced = true; 171 } 172 173 $this->iteratorExhausted = true; 174 } 175 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body