1<?php 2 3/** @file dualiterator.inc 4 * @ingroup Examples 5 * @brief class DualIterator 6 * @author Marcus Boerger 7 * @date 2003 - 2006 8 * 9 * SPL - Standard PHP Library 10 */ 11 12/** @ingroup Examples 13 * @brief Synchronous iteration over two iterators 14 * @author Marcus Boerger 15 * @version 1.3 16 */ 17class DualIterator implements Iterator 18{ 19 const CURRENT_LHS = 0x01; 20 const CURRENT_RHS = 0x02; 21 const CURRENT_ARRAY = 0x03; 22 const CURRENT_0 = 0x00; 23 24 const KEY_LHS = 0x10; 25 const KEY_RHS = 0x20; 26 const KEY_0 = 0x00; 27 28 const DEFAULT_FLAGS = 0x13; 29 30 private $lhs; 31 private $rhs; 32 private $flags; 33 34 /** construct iterator from two iterators 35 * 36 * @param lhs Left Hand Side Iterator 37 * @param rhs Right Hand Side Iterator 38 * @param flags iteration flags 39 */ 40 function __construct(Iterator $lhs, Iterator $rhs, 41 $flags = 0x13 /*DualIterator::DEFAULT_FLAGS*/) 42 { 43 $this->lhs = $lhs; 44 $this->rhs = $rhs; 45 $this->flags = $flags; 46 } 47 48 /** @return Left Hand Side Iterator 49 */ 50 function getLHS() 51 { 52 return $this->lhs; 53 } 54 55 /** @return Right Hand Side Iterator 56 */ 57 function getRHS() 58 { 59 return $this->rhs; 60 } 61 62 /** @param flags new flags 63 */ 64 function setFlags($flags) 65 { 66 $this->flags = $flags; 67 } 68 69 /** @return current flags 70 */ 71 function getFlags() 72 { 73 return $this->flags; 74 } 75 76 /** rewind both inner iterators 77 */ 78 function rewind(): void 79 { 80 $this->lhs->rewind(); 81 $this->rhs->rewind(); 82 } 83 84 /** @return whether both inner iterators are valid 85 */ 86 function valid(): bool 87 { 88 return $this->lhs->valid() && $this->rhs->valid(); 89 } 90 91 /** @return current value depending on CURRENT_* flags 92 */ 93 function current(): mixed 94 { 95 switch($this->flags & 0x0F) 96 { 97 default: 98 case self::CURRENT_ARRAY: 99 return array($this->lhs->current(), $this->rhs->current()); 100 case self::CURRENT_LHS: 101 return $this->lhs->current(); 102 case self::CURRENT_RHS: 103 return $this->rhs->current(); 104 case self::CURRENT_0: 105 return NULL; 106 } 107 } 108 109 /** @return key value depending on KEY_* flags 110 */ 111 function key(): mixed 112 { 113 switch($this->flags & 0xF0) 114 { 115 default: 116 case self::KEY_LHS: 117 return $this->lhs->key(); 118 case self::KEY_RHS: 119 return $this->rhs->key(); 120 case self::KEY_0: 121 return NULL; 122 } 123 } 124 125 /** move both inner iterators forward 126 */ 127 function next(): void 128 { 129 $this->lhs->next(); 130 $this->rhs->next(); 131 } 132 133 /** @return whether both inner iterators are valid and have identical 134 * current and key values or both are non valid. 135 */ 136 function areIdentical() 137 { 138 return $this->valid() 139 ? $this->lhs->current() === $this->rhs->current() 140 && $this->lhs->key() === $this->rhs->key() 141 : $this->lhs->valid() == $this->rhs->valid(); 142 } 143 144 /** @return whether both inner iterators are valid and have equal current 145 * and key values or both are non valid. 146 */ 147 function areEqual() 148 { 149 return $this->valid() 150 ? $this->lhs->current() == $this->rhs->current() 151 && $this->lhs->key() == $this->rhs->key() 152 : $this->lhs->valid() == $this->rhs->valid(); 153 } 154 155 /** Compare two iterators 156 * 157 * @param lhs Left Hand Side Iterator 158 * @param rhs Right Hand Side Iterator 159 * @param identical whether to use areEqual() or areIdentical() 160 * @return whether both iterators are equal/identical 161 * 162 * @note If one implements RecursiveIterator the other must do as well. 163 * And if both do then a recursive comparison is being used. 164 */ 165 static function compareIterators(Iterator $lhs, Iterator $rhs, 166 $identical = false) 167 { 168 if ($lhs instanceof RecursiveIterator) 169 { 170 if ($rhs instanceof RecursiveIterator) 171 { 172 $it = new RecursiveDualIterator($lhs, $rhs, 173 self::CURRENT_0 | self::KEY_0); 174 $it = new RecursiveCompareDualIterator($it); 175 } 176 else 177 { 178 return false; 179 } 180 } 181 else 182 { 183 $it = new DualIterator($lhs, $rhs, self::CURRENT_0 | self::KEY_0); 184 } 185 186 if ($identical) 187 { 188 foreach($it as $n) 189 { 190 if (!$it->areIdentical()) 191 { 192 return false; 193 } 194 } 195 } 196 else 197 { 198 foreach($it as $n) 199 { 200 if (!$it->areEqual()) 201 { 202 return false; 203 } 204 } 205 } 206 return $identical ? $it->areIdentical() : $it->areEqual(); 207 } 208} 209 210?> 211