1<?php 2 3// Protocol Buffers - Google's data interchange format 4// Copyright 2008 Google Inc. All rights reserved. 5// 6// Use of this source code is governed by a BSD-style 7// license that can be found in the LICENSE file or at 8// https://developers.google.com/open-source/licenses/bsd 9 10/** 11 * MapField and MapFieldIter are used by generated protocol message classes to 12 * manipulate map fields. 13 */ 14 15namespace Google\Protobuf\Internal; 16 17use Traversable; 18 19/** 20 * MapField is used by generated protocol message classes to manipulate map 21 * fields. It can be used like native PHP array. 22 */ 23class MapField implements \ArrayAccess, \IteratorAggregate, \Countable 24{ 25 /** 26 * @ignore 27 */ 28 private $container; 29 /** 30 * @ignore 31 */ 32 private $key_type; 33 /** 34 * @ignore 35 */ 36 private $value_type; 37 /** 38 * @ignore 39 */ 40 private $klass; 41 /** 42 * @ignore 43 */ 44 private $legacy_klass; 45 46 /** 47 * Constructs an instance of MapField. 48 * 49 * @param long $key_type Type of the stored key element. 50 * @param long $value_type Type of the stored value element. 51 * @param string $klass Message/Enum class name of value instance 52 * (message/enum fields only). 53 * @ignore 54 */ 55 public function __construct($key_type, $value_type, $klass = null) 56 { 57 $this->container = []; 58 $this->key_type = $key_type; 59 $this->value_type = $value_type; 60 $this->klass = $klass; 61 62 if ($this->value_type == GPBType::MESSAGE) { 63 $pool = DescriptorPool::getGeneratedPool(); 64 $desc = $pool->getDescriptorByClassName($klass); 65 if ($desc == NULL) { 66 new $klass; // No msg class instance has been created before. 67 $desc = $pool->getDescriptorByClassName($klass); 68 } 69 $this->klass = $desc->getClass(); 70 $this->legacy_klass = $desc->getLegacyClass(); 71 } 72 } 73 74 /** 75 * @ignore 76 */ 77 public function getKeyType() 78 { 79 return $this->key_type; 80 } 81 82 /** 83 * @ignore 84 */ 85 public function getValueType() 86 { 87 return $this->value_type; 88 } 89 90 /** 91 * @ignore 92 */ 93 public function getValueClass() 94 { 95 return $this->klass; 96 } 97 98 /** 99 * @ignore 100 */ 101 public function getLegacyValueClass() 102 { 103 return $this->legacy_klass; 104 } 105 106 /** 107 * Return the element at the given key. 108 * 109 * This will also be called for: $ele = $arr[$key] 110 * 111 * @param int|string $key The key of the element to be fetched. 112 * @return object The stored element at given key. 113 * @throws \ErrorException Invalid type for index. 114 * @throws \ErrorException Non-existing index. 115 * @todo need to add return type mixed (require update php version to 8.0) 116 */ 117 #[\ReturnTypeWillChange] 118 public function offsetGet($key) 119 { 120 return $this->container[$key]; 121 } 122 123 /** 124 * Assign the element at the given key. 125 * 126 * This will also be called for: $arr[$key] = $value 127 * 128 * @param int|string $key The key of the element to be fetched. 129 * @param object $value The element to be assigned. 130 * @return void 131 * @throws \ErrorException Invalid type for key. 132 * @throws \ErrorException Invalid type for value. 133 * @throws \ErrorException Non-existing key. 134 * @todo need to add return type void (require update php version to 7.1) 135 */ 136 #[\ReturnTypeWillChange] 137 public function offsetSet($key, $value) 138 { 139 $this->checkKey($this->key_type, $key); 140 141 switch ($this->value_type) { 142 case GPBType::SFIXED32: 143 case GPBType::SINT32: 144 case GPBType::INT32: 145 case GPBType::ENUM: 146 GPBUtil::checkInt32($value); 147 break; 148 case GPBType::FIXED32: 149 case GPBType::UINT32: 150 GPBUtil::checkUint32($value); 151 break; 152 case GPBType::SFIXED64: 153 case GPBType::SINT64: 154 case GPBType::INT64: 155 GPBUtil::checkInt64($value); 156 break; 157 case GPBType::FIXED64: 158 case GPBType::UINT64: 159 GPBUtil::checkUint64($value); 160 break; 161 case GPBType::FLOAT: 162 GPBUtil::checkFloat($value); 163 break; 164 case GPBType::DOUBLE: 165 GPBUtil::checkDouble($value); 166 break; 167 case GPBType::BOOL: 168 GPBUtil::checkBool($value); 169 break; 170 case GPBType::STRING: 171 GPBUtil::checkString($value, true); 172 break; 173 case GPBType::MESSAGE: 174 if (is_null($value)) { 175 trigger_error("Map element cannot be null.", E_USER_ERROR); 176 } 177 GPBUtil::checkMessage($value, $this->klass); 178 break; 179 default: 180 break; 181 } 182 183 $this->container[$key] = $value; 184 } 185 186 /** 187 * Remove the element at the given key. 188 * 189 * This will also be called for: unset($arr) 190 * 191 * @param int|string $key The key of the element to be removed. 192 * @return void 193 * @throws \ErrorException Invalid type for key. 194 * @todo need to add return type void (require update php version to 7.1) 195 */ 196 #[\ReturnTypeWillChange] 197 public function offsetUnset($key) 198 { 199 $this->checkKey($this->key_type, $key); 200 unset($this->container[$key]); 201 } 202 203 /** 204 * Check the existence of the element at the given key. 205 * 206 * This will also be called for: isset($arr) 207 * 208 * @param int|string $key The key of the element to be removed. 209 * @return bool True if the element at the given key exists. 210 * @throws \ErrorException Invalid type for key. 211 */ 212 public function offsetExists($key): bool 213 { 214 $this->checkKey($this->key_type, $key); 215 return isset($this->container[$key]); 216 } 217 218 /** 219 * @ignore 220 */ 221 public function getIterator(): Traversable 222 { 223 return new MapFieldIter($this->container, $this->key_type); 224 } 225 226 /** 227 * Return the number of stored elements. 228 * 229 * This will also be called for: count($arr) 230 * 231 * @return integer The number of stored elements. 232 */ 233 public function count(): int 234 { 235 return count($this->container); 236 } 237 238 /** 239 * @ignore 240 */ 241 private function checkKey($key_type, &$key) 242 { 243 switch ($key_type) { 244 case GPBType::SFIXED32: 245 case GPBType::SINT32: 246 case GPBType::INT32: 247 GPBUtil::checkInt32($key); 248 break; 249 case GPBType::FIXED32: 250 case GPBType::UINT32: 251 GPBUtil::checkUint32($key); 252 break; 253 case GPBType::SFIXED64: 254 case GPBType::SINT64: 255 case GPBType::INT64: 256 GPBUtil::checkInt64($key); 257 break; 258 case GPBType::FIXED64: 259 case GPBType::UINT64: 260 GPBUtil::checkUint64($key); 261 break; 262 case GPBType::BOOL: 263 GPBUtil::checkBool($key); 264 break; 265 case GPBType::STRING: 266 GPBUtil::checkString($key, true); 267 break; 268 default: 269 trigger_error( 270 "Given type cannot be map key.", 271 E_USER_ERROR); 272 break; 273 } 274 } 275} 276