simPod /
graphql-php
| 1 | <?php |
||
| 2 | |||
| 3 | declare(strict_types=1); |
||
| 4 | |||
| 5 | namespace GraphQL\Utils; |
||
| 6 | |||
| 7 | use ArrayAccess; |
||
| 8 | use GraphQL\Type\Definition\EnumValueDefinition; |
||
| 9 | use InvalidArgumentException; |
||
| 10 | use SplObjectStorage; |
||
| 11 | use function array_key_exists; |
||
| 12 | use function array_search; |
||
| 13 | use function array_splice; |
||
| 14 | use function is_array; |
||
| 15 | use function is_float; |
||
| 16 | use function is_int; |
||
| 17 | use function is_object; |
||
| 18 | use function is_string; |
||
| 19 | |||
| 20 | /** |
||
| 21 | * Similar to PHP array, but allows any type of data to act as key (including arrays, objects, scalars) |
||
| 22 | * |
||
| 23 | * Note: unfortunately when storing array as key - access and modification is O(N) |
||
| 24 | * (yet this should rarely be the case and should be avoided when possible) |
||
| 25 | */ |
||
| 26 | class MixedStore implements ArrayAccess |
||
| 27 | { |
||
| 28 | /** @var EnumValueDefinition[] */ |
||
| 29 | private $standardStore; |
||
| 30 | |||
| 31 | /** @var mixed[] */ |
||
| 32 | private $floatStore; |
||
| 33 | |||
| 34 | /** @var SplObjectStorage */ |
||
| 35 | private $objectStore; |
||
| 36 | |||
| 37 | /** @var callable[] */ |
||
| 38 | private $arrayKeys; |
||
| 39 | |||
| 40 | /** @var EnumValueDefinition[] */ |
||
| 41 | private $arrayValues; |
||
| 42 | |||
| 43 | /** @var callable[] */ |
||
| 44 | private $lastArrayKey; |
||
| 45 | |||
| 46 | /** @var mixed */ |
||
| 47 | private $lastArrayValue; |
||
| 48 | |||
| 49 | /** @var mixed */ |
||
| 50 | private $nullValue; |
||
| 51 | |||
| 52 | /** @var bool */ |
||
| 53 | private $nullValueIsSet; |
||
| 54 | |||
| 55 | /** @var mixed */ |
||
| 56 | private $trueValue; |
||
| 57 | |||
| 58 | /** @var bool */ |
||
| 59 | private $trueValueIsSet; |
||
| 60 | |||
| 61 | /** @var mixed */ |
||
| 62 | private $falseValue; |
||
| 63 | |||
| 64 | /** @var bool */ |
||
| 65 | private $falseValueIsSet; |
||
| 66 | |||
| 67 | 22 | public function __construct() |
|
| 68 | { |
||
| 69 | 22 | $this->standardStore = []; |
|
| 70 | 22 | $this->floatStore = []; |
|
| 71 | 22 | $this->objectStore = new SplObjectStorage(); |
|
| 72 | 22 | $this->arrayKeys = []; |
|
| 73 | 22 | $this->arrayValues = []; |
|
| 74 | 22 | $this->nullValueIsSet = false; |
|
| 75 | 22 | $this->trueValueIsSet = false; |
|
| 76 | 22 | $this->falseValueIsSet = false; |
|
| 77 | 22 | } |
|
| 78 | |||
| 79 | /** |
||
| 80 | * Whether a offset exists |
||
| 81 | * |
||
| 82 | * @link http://php.net/manual/en/arrayaccess.offsetexists.php |
||
| 83 | * |
||
| 84 | * @param mixed $offset <p> |
||
| 85 | * An offset to check for. |
||
| 86 | * </p> |
||
| 87 | * |
||
| 88 | * @return bool true on success or false on failure. |
||
| 89 | * </p> |
||
| 90 | * <p> |
||
| 91 | * The return value will be casted to boolean if non-boolean was returned. |
||
| 92 | */ |
||
| 93 | 30 | public function offsetExists($offset) |
|
| 94 | { |
||
| 95 | 30 | if ($offset === false) { |
|
| 96 | 1 | return $this->falseValueIsSet; |
|
| 97 | } |
||
| 98 | 30 | if ($offset === true) { |
|
| 99 | 1 | return $this->trueValueIsSet; |
|
| 100 | } |
||
| 101 | 29 | if (is_int($offset) || is_string($offset)) { |
|
| 102 | 23 | return array_key_exists($offset, $this->standardStore); |
|
| 103 | } |
||
| 104 | 8 | if (is_float($offset)) { |
|
| 105 | 1 | return array_key_exists((string) $offset, $this->floatStore); |
|
| 106 | } |
||
| 107 | 7 | if (is_object($offset)) { |
|
| 108 | 3 | return $this->objectStore->offsetExists($offset); |
|
| 109 | } |
||
| 110 | 5 | if (is_array($offset)) { |
|
| 111 | 4 | foreach ($this->arrayKeys as $index => $entry) { |
|
| 112 | 4 | if ($entry === $offset) { |
|
| 113 | 4 | $this->lastArrayKey = $offset; |
|
| 114 | 4 | $this->lastArrayValue = $this->arrayValues[$index]; |
|
| 115 | |||
| 116 | 4 | return true; |
|
| 117 | } |
||
| 118 | } |
||
| 119 | } |
||
| 120 | 2 | if ($offset === null) { |
|
| 121 | 1 | return $this->nullValueIsSet; |
|
| 122 | } |
||
| 123 | |||
| 124 | 1 | return false; |
|
| 125 | } |
||
| 126 | |||
| 127 | /** |
||
| 128 | * Offset to retrieve |
||
| 129 | * |
||
| 130 | * @link http://php.net/manual/en/arrayaccess.offsetget.php |
||
| 131 | * |
||
| 132 | * @param mixed $offset <p> |
||
| 133 | * The offset to retrieve. |
||
| 134 | * </p> |
||
| 135 | * |
||
| 136 | * @return mixed Can return all value types. |
||
| 137 | */ |
||
| 138 | 29 | public function offsetGet($offset) |
|
| 139 | { |
||
| 140 | 29 | if ($offset === true) { |
|
| 141 | 1 | return $this->trueValue; |
|
| 142 | } |
||
| 143 | 29 | if ($offset === false) { |
|
| 144 | 1 | return $this->falseValue; |
|
| 145 | } |
||
| 146 | 28 | if (is_int($offset) || is_string($offset)) { |
|
| 147 | 22 | return $this->standardStore[$offset]; |
|
| 148 | } |
||
| 149 | 8 | if (is_float($offset)) { |
|
| 150 | 1 | return $this->floatStore[(string) $offset]; |
|
| 151 | } |
||
| 152 | 7 | if (is_object($offset)) { |
|
| 153 | 3 | return $this->objectStore->offsetGet($offset); |
|
| 154 | } |
||
| 155 | 5 | if (is_array($offset)) { |
|
| 156 | // offsetGet is often called directly after offsetExists, so optimize to avoid second loop: |
||
| 157 | 4 | if ($this->lastArrayKey === $offset) { |
|
| 158 | 4 | return $this->lastArrayValue; |
|
| 159 | } |
||
| 160 | foreach ($this->arrayKeys as $index => $entry) { |
||
| 161 | if ($entry === $offset) { |
||
| 162 | return $this->arrayValues[$index]; |
||
| 163 | } |
||
| 164 | } |
||
| 165 | } |
||
| 166 | 1 | if ($offset === null) { |
|
| 167 | 1 | return $this->nullValue; |
|
| 168 | } |
||
| 169 | |||
| 170 | return null; |
||
| 171 | } |
||
| 172 | |||
| 173 | /** |
||
| 174 | * Offset to set |
||
| 175 | * |
||
| 176 | * @link http://php.net/manual/en/arrayaccess.offsetset.php |
||
| 177 | * |
||
| 178 | * @param mixed $offset <p> |
||
| 179 | * The offset to assign the value to. |
||
| 180 | * </p> |
||
| 181 | * @param mixed $value <p> |
||
| 182 | * The value to set. |
||
| 183 | * </p> |
||
| 184 | * |
||
| 185 | * @return void |
||
| 186 | */ |
||
| 187 | 22 | public function offsetSet($offset, $value) |
|
| 188 | { |
||
| 189 | 22 | if ($offset === false) { |
|
| 190 | 1 | $this->falseValue = $value; |
|
| 191 | 1 | $this->falseValueIsSet = true; |
|
| 192 | 22 | } elseif ($offset === true) { |
|
| 193 | 1 | $this->trueValue = $value; |
|
| 194 | 1 | $this->trueValueIsSet = true; |
|
| 195 | 21 | } elseif (is_int($offset) || is_string($offset)) { |
|
| 196 | 15 | $this->standardStore[$offset] = $value; |
|
| 197 | 10 | } elseif (is_float($offset)) { |
|
| 198 | 1 | $this->floatStore[(string) $offset] = $value; |
|
| 199 | 9 | } elseif (is_object($offset)) { |
|
| 200 | 6 | $this->objectStore[$offset] = $value; |
|
| 201 | 5 | } elseif (is_array($offset)) { |
|
| 202 | 4 | $this->arrayKeys[] = $offset; |
|
| 203 | 4 | $this->arrayValues[] = $value; |
|
| 204 | 1 | } elseif ($offset === null) { |
|
| 205 | 1 | $this->nullValue = $value; |
|
| 206 | 1 | $this->nullValueIsSet = true; |
|
| 207 | } else { |
||
| 208 | throw new InvalidArgumentException('Unexpected offset type: ' . Utils::printSafe($offset)); |
||
| 209 | } |
||
| 210 | 22 | } |
|
| 211 | |||
| 212 | /** |
||
| 213 | * Offset to unset |
||
| 214 | * |
||
| 215 | * @link http://php.net/manual/en/arrayaccess.offsetunset.php |
||
| 216 | * |
||
| 217 | * @param mixed $offset <p> |
||
| 218 | * The offset to unset. |
||
| 219 | * </p> |
||
| 220 | * |
||
| 221 | * @return void |
||
| 222 | */ |
||
| 223 | 6 | public function offsetUnset($offset) |
|
| 224 | { |
||
| 225 | 6 | if ($offset === true) { |
|
| 226 | 1 | $this->trueValue = null; |
|
| 227 | 1 | $this->trueValueIsSet = false; |
|
| 228 | 6 | } elseif ($offset === false) { |
|
| 229 | 1 | $this->falseValue = null; |
|
| 230 | 1 | $this->falseValueIsSet = false; |
|
| 231 | 5 | } elseif (is_int($offset) || is_string($offset)) { |
|
| 232 | 1 | unset($this->standardStore[$offset]); |
|
| 233 | 4 | } elseif (is_float($offset)) { |
|
| 234 | 1 | unset($this->floatStore[(string) $offset]); |
|
| 235 | 3 | } elseif (is_object($offset)) { |
|
| 236 | 1 | $this->objectStore->offsetUnset($offset); |
|
| 237 | 2 | } elseif (is_array($offset)) { |
|
| 238 | 1 | $index = array_search($offset, $this->arrayKeys, true); |
|
| 239 | |||
| 240 | 1 | if ($index !== false) { |
|
| 241 | 1 | array_splice($this->arrayKeys, $index, 1); |
|
|
0 ignored issues
–
show
Bug
introduced
by
Loading history...
|
|||
| 242 | 1 | array_splice($this->arrayValues, $index, 1); |
|
| 243 | } |
||
| 244 | 1 | } elseif ($offset === null) { |
|
| 245 | 1 | $this->nullValue = null; |
|
| 246 | 1 | $this->nullValueIsSet = false; |
|
| 247 | } |
||
| 248 | 6 | } |
|
| 249 | } |
||
| 250 |