See Release Notes
Long Term Support Release
Differences Between: [Versions 310 and 401] [Versions 311 and 401] [Versions 39 and 401] [Versions 400 and 401]
1 <?php 2 /* 3 * Copyright 2017-present 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 * https://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 Iterator; 22 use IteratorIterator; 23 use ReturnTypeWillChange; 24 use Traversable; 25 26 use function count; 27 use function current; 28 use function next; 29 use function reset; 30 31 /** 32 * Iterator for wrapping a Traversable and caching its results. 33 * 34 * By caching results, this iterators allows a Traversable to be counted and 35 * rewound multiple times, even if the wrapped object does not natively support 36 * those operations (e.g. MongoDB\Driver\Cursor). 37 * 38 * @internal 39 */ 40 class CachingIterator implements Countable, Iterator 41 { 42 private const FIELD_KEY = 0; 43 private const FIELD_VALUE = 1; 44 45 /** @var array */ 46 private $items = []; 47 48 /** @var Iterator */ 49 private $iterator; 50 51 /** @var boolean */ 52 private $iteratorAdvanced = false; 53 54 /** @var boolean */ 55 private $iteratorExhausted = false; 56 57 /** 58 * Initialize the iterator and stores the first item in the cache. This 59 * effectively rewinds the Traversable and the wrapping IteratorIterator. 60 * Additionally, this mimics behavior of the SPL iterators and allows users 61 * to omit an explicit call to rewind() before using the other methods. 62 * 63 * @param Traversable $traversable 64 */ 65 public function __construct(Traversable $traversable) 66 { 67 $this->iterator = $traversable instanceof Iterator ? $traversable : new IteratorIterator($traversable); 68 69 $this->iterator->rewind(); 70 $this->storeCurrentItem(); 71 } 72 73 /** 74 * @see https://php.net/countable.count 75 */ 76 public function count(): int 77 { 78 $this->exhaustIterator(); 79 80 return count($this->items); 81 } 82 83 /** 84 * @see https://php.net/iterator.current 85 * @return mixed 86 */ 87 #[ReturnTypeWillChange] 88 public function current() 89 { 90 $currentItem = current($this->items); 91 92 return $currentItem !== false ? $currentItem[self::FIELD_VALUE] : false; 93 } 94 95 /** 96 * @see https://php.net/iterator.key 97 * @return mixed 98 */ 99 #[ReturnTypeWillChange] 100 public function key() 101 { 102 $currentItem = current($this->items); 103 104 return $currentItem !== false ? $currentItem[self::FIELD_KEY] : null; 105 } 106 107 /** 108 * @see https://php.net/iterator.next 109 */ 110 public function next(): void 111 { 112 if (! $this->iteratorExhausted) { 113 $this->iteratorAdvanced = true; 114 $this->iterator->next(); 115 116 $this->storeCurrentItem(); 117 118 $this->iteratorExhausted = ! $this->iterator->valid(); 119 } 120 121 next($this->items); 122 } 123 124 /** 125 * @see https://php.net/iterator.rewind 126 */ 127 public function rewind(): void 128 { 129 /* If the iterator has advanced, exhaust it now so that future iteration 130 * can rely on the cache. 131 */ 132 if ($this->iteratorAdvanced) { 133 $this->exhaustIterator(); 134 } 135 136 reset($this->items); 137 } 138 139 /** 140 * @see https://php.net/iterator.valid 141 */ 142 public function valid(): bool 143 { 144 return $this->key() !== null; 145 } 146 147 /** 148 * Ensures that the inner iterator is fully consumed and cached. 149 */ 150 private function exhaustIterator(): void 151 { 152 while (! $this->iteratorExhausted) { 153 $this->next(); 154 } 155 } 156 157 /** 158 * Stores the current item in the cache. 159 */ 160 private function storeCurrentItem(): void 161 { 162 if (! $this->iterator->valid()) { 163 return; 164 } 165 166 // Storing a new item in the internal cache 167 $this->items[] = [ 168 self::FIELD_KEY => $this->iterator->key(), 169 self::FIELD_VALUE => $this->iterator->current(), 170 ]; 171 } 172 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body