1<?php 2 3// Protocol Buffers - Google's data interchange format 4// Copyright 2008 Google Inc. All rights reserved. 5// https://developers.google.com/protocol-buffers/ 6// 7// Redistribution and use in source and binary forms, with or without 8// modification, are permitted provided that the following conditions are 9// met: 10// 11// * Redistributions of source code must retain the above copyright 12// notice, this list of conditions and the following disclaimer. 13// * Redistributions in binary form must reproduce the above 14// copyright notice, this list of conditions and the following disclaimer 15// in the documentation and/or other materials provided with the 16// distribution. 17// * Neither the name of Google Inc. nor the names of its 18// contributors may be used to endorse or promote products derived from 19// this software without specific prior written permission. 20// 21// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 24// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 25// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 26// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 27// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 31// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 33/** 34 * MapField and MapFieldIter are used by generated protocol message classes to 35 * manipulate map fields. 36 */ 37 38namespace Google\Protobuf\Internal; 39 40use Traversable; 41 42/** 43 * MapField is used by generated protocol message classes to manipulate map 44 * fields. It can be used like native PHP array. 45 */ 46class MapField implements \ArrayAccess, \IteratorAggregate, \Countable 47{ 48 /** 49 * @ignore 50 */ 51 private $container; 52 /** 53 * @ignore 54 */ 55 private $key_type; 56 /** 57 * @ignore 58 */ 59 private $value_type; 60 /** 61 * @ignore 62 */ 63 private $klass; 64 /** 65 * @ignore 66 */ 67 private $legacy_klass; 68 69 /** 70 * Constructs an instance of MapField. 71 * 72 * @param long $key_type Type of the stored key element. 73 * @param long $value_type Type of the stored value element. 74 * @param string $klass Message/Enum class name of value instance 75 * (message/enum fields only). 76 * @ignore 77 */ 78 public function __construct($key_type, $value_type, $klass = null) 79 { 80 $this->container = []; 81 $this->key_type = $key_type; 82 $this->value_type = $value_type; 83 $this->klass = $klass; 84 85 if ($this->value_type == GPBType::MESSAGE) { 86 $pool = DescriptorPool::getGeneratedPool(); 87 $desc = $pool->getDescriptorByClassName($klass); 88 if ($desc == NULL) { 89 new $klass; // No msg class instance has been created before. 90 $desc = $pool->getDescriptorByClassName($klass); 91 } 92 $this->klass = $desc->getClass(); 93 $this->legacy_klass = $desc->getLegacyClass(); 94 } 95 } 96 97 /** 98 * @ignore 99 */ 100 public function getKeyType() 101 { 102 return $this->key_type; 103 } 104 105 /** 106 * @ignore 107 */ 108 public function getValueType() 109 { 110 return $this->value_type; 111 } 112 113 /** 114 * @ignore 115 */ 116 public function getValueClass() 117 { 118 return $this->klass; 119 } 120 121 /** 122 * @ignore 123 */ 124 public function getLegacyValueClass() 125 { 126 return $this->legacy_klass; 127 } 128 129 /** 130 * Return the element at the given key. 131 * 132 * This will also be called for: $ele = $arr[$key] 133 * 134 * @param int|string $key The key of the element to be fetched. 135 * @return object The stored element at given key. 136 * @throws \ErrorException Invalid type for index. 137 * @throws \ErrorException Non-existing index. 138 * @todo need to add return type mixed (require update php version to 8.0) 139 */ 140 #[\ReturnTypeWillChange] 141 public function offsetGet($key) 142 { 143 return $this->container[$key]; 144 } 145 146 /** 147 * Assign the element at the given key. 148 * 149 * This will also be called for: $arr[$key] = $value 150 * 151 * @param int|string $key The key of the element to be fetched. 152 * @param object $value The element to be assigned. 153 * @return void 154 * @throws \ErrorException Invalid type for key. 155 * @throws \ErrorException Invalid type for value. 156 * @throws \ErrorException Non-existing key. 157 * @todo need to add return type void (require update php version to 7.1) 158 */ 159 #[\ReturnTypeWillChange] 160 public function offsetSet($key, $value) 161 { 162 $this->checkKey($this->key_type, $key); 163 164 switch ($this->value_type) { 165 case GPBType::SFIXED32: 166 case GPBType::SINT32: 167 case GPBType::INT32: 168 case GPBType::ENUM: 169 GPBUtil::checkInt32($value); 170 break; 171 case GPBType::FIXED32: 172 case GPBType::UINT32: 173 GPBUtil::checkUint32($value); 174 break; 175 case GPBType::SFIXED64: 176 case GPBType::SINT64: 177 case GPBType::INT64: 178 GPBUtil::checkInt64($value); 179 break; 180 case GPBType::FIXED64: 181 case GPBType::UINT64: 182 GPBUtil::checkUint64($value); 183 break; 184 case GPBType::FLOAT: 185 GPBUtil::checkFloat($value); 186 break; 187 case GPBType::DOUBLE: 188 GPBUtil::checkDouble($value); 189 break; 190 case GPBType::BOOL: 191 GPBUtil::checkBool($value); 192 break; 193 case GPBType::STRING: 194 GPBUtil::checkString($value, true); 195 break; 196 case GPBType::MESSAGE: 197 if (is_null($value)) { 198 trigger_error("Map element cannot be null.", E_USER_ERROR); 199 } 200 GPBUtil::checkMessage($value, $this->klass); 201 break; 202 default: 203 break; 204 } 205 206 $this->container[$key] = $value; 207 } 208 209 /** 210 * Remove the element at the given key. 211 * 212 * This will also be called for: unset($arr) 213 * 214 * @param int|string $key The key of the element to be removed. 215 * @return void 216 * @throws \ErrorException Invalid type for key. 217 * @todo need to add return type void (require update php version to 7.1) 218 */ 219 #[\ReturnTypeWillChange] 220 public function offsetUnset($key) 221 { 222 $this->checkKey($this->key_type, $key); 223 unset($this->container[$key]); 224 } 225 226 /** 227 * Check the existence of the element at the given key. 228 * 229 * This will also be called for: isset($arr) 230 * 231 * @param int|string $key The key of the element to be removed. 232 * @return bool True if the element at the given key exists. 233 * @throws \ErrorException Invalid type for key. 234 */ 235 public function offsetExists($key): bool 236 { 237 $this->checkKey($this->key_type, $key); 238 return isset($this->container[$key]); 239 } 240 241 /** 242 * @ignore 243 */ 244 public function getIterator(): Traversable 245 { 246 return new MapFieldIter($this->container, $this->key_type); 247 } 248 249 /** 250 * Return the number of stored elements. 251 * 252 * This will also be called for: count($arr) 253 * 254 * @return integer The number of stored elements. 255 */ 256 public function count(): int 257 { 258 return count($this->container); 259 } 260 261 /** 262 * @ignore 263 */ 264 private function checkKey($key_type, &$key) 265 { 266 switch ($key_type) { 267 case GPBType::SFIXED32: 268 case GPBType::SINT32: 269 case GPBType::INT32: 270 GPBUtil::checkInt32($key); 271 break; 272 case GPBType::FIXED32: 273 case GPBType::UINT32: 274 GPBUtil::checkUint32($key); 275 break; 276 case GPBType::SFIXED64: 277 case GPBType::SINT64: 278 case GPBType::INT64: 279 GPBUtil::checkInt64($key); 280 break; 281 case GPBType::FIXED64: 282 case GPBType::UINT64: 283 GPBUtil::checkUint64($key); 284 break; 285 case GPBType::BOOL: 286 GPBUtil::checkBool($key); 287 break; 288 case GPBType::STRING: 289 GPBUtil::checkString($key, true); 290 break; 291 default: 292 trigger_error( 293 "Given type cannot be map key.", 294 E_USER_ERROR); 295 break; 296 } 297 } 298} 299