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 * RepeatedField and RepeatedFieldIter are used by generated protocol message 35 * classes to manipulate repeated fields. 36 */ 37 38namespace Google\Protobuf\Internal; 39 40use Google\Protobuf\Internal\GPBType; 41use Google\Protobuf\Internal\GPBUtil; 42 43/** 44 * RepeatedField is used by generated protocol message classes to manipulate 45 * repeated fields. It can be used like native PHP array. 46 */ 47class RepeatedField implements \ArrayAccess, \IteratorAggregate, \Countable 48{ 49 50 /** 51 * @ignore 52 */ 53 private $container; 54 /** 55 * @ignore 56 */ 57 private $type; 58 /** 59 * @ignore 60 */ 61 private $klass; 62 /** 63 * @ignore 64 */ 65 private $legacy_klass; 66 67 /** 68 * Constructs an instance of RepeatedField. 69 * 70 * @param long $type Type of the stored element. 71 * @param string $klass Message/Enum class name (message/enum fields only). 72 * @ignore 73 */ 74 public function __construct($type, $klass = null) 75 { 76 $this->container = []; 77 $this->type = $type; 78 if ($this->type == GPBType::MESSAGE) { 79 $pool = DescriptorPool::getGeneratedPool(); 80 $desc = $pool->getDescriptorByClassName($klass); 81 if ($desc == NULL) { 82 new $klass; // No msg class instance has been created before. 83 $desc = $pool->getDescriptorByClassName($klass); 84 } 85 $this->klass = $desc->getClass(); 86 $this->legacy_klass = $desc->getLegacyClass(); 87 } 88 } 89 90 /** 91 * @ignore 92 */ 93 public function getType() 94 { 95 return $this->type; 96 } 97 98 /** 99 * @ignore 100 */ 101 public function getClass() 102 { 103 return $this->klass; 104 } 105 106 /** 107 * @ignore 108 */ 109 public function getLegacyClass() 110 { 111 return $this->legacy_klass; 112 } 113 114 /** 115 * Return the element at the given index. 116 * 117 * This will also be called for: $ele = $arr[0] 118 * 119 * @param long $offset The index of the element to be fetched. 120 * @return object The stored element at given index. 121 * @throws \ErrorException Invalid type for index. 122 * @throws \ErrorException Non-existing index. 123 */ 124 public function offsetGet($offset) 125 { 126 return $this->container[$offset]; 127 } 128 129 /** 130 * Assign the element at the given index. 131 * 132 * This will also be called for: $arr []= $ele and $arr[0] = ele 133 * 134 * @param long $offset The index of the element to be assigned. 135 * @param object $value The element to be assigned. 136 * @return void 137 * @throws \ErrorException Invalid type for index. 138 * @throws \ErrorException Non-existing index. 139 * @throws \ErrorException Incorrect type of the element. 140 */ 141 public function offsetSet($offset, $value) 142 { 143 switch ($this->type) { 144 case GPBType::SFIXED32: 145 case GPBType::SINT32: 146 case GPBType::INT32: 147 case GPBType::ENUM: 148 GPBUtil::checkInt32($value); 149 break; 150 case GPBType::FIXED32: 151 case GPBType::UINT32: 152 GPBUtil::checkUint32($value); 153 break; 154 case GPBType::SFIXED64: 155 case GPBType::SINT64: 156 case GPBType::INT64: 157 GPBUtil::checkInt64($value); 158 break; 159 case GPBType::FIXED64: 160 case GPBType::UINT64: 161 GPBUtil::checkUint64($value); 162 break; 163 case GPBType::FLOAT: 164 GPBUtil::checkFloat($value); 165 break; 166 case GPBType::DOUBLE: 167 GPBUtil::checkDouble($value); 168 break; 169 case GPBType::BOOL: 170 GPBUtil::checkBool($value); 171 break; 172 case GPBType::BYTES: 173 GPBUtil::checkString($value, false); 174 break; 175 case GPBType::STRING: 176 GPBUtil::checkString($value, true); 177 break; 178 case GPBType::MESSAGE: 179 if (is_null($value)) { 180 trigger_error("RepeatedField element cannot be null.", 181 E_USER_ERROR); 182 } 183 GPBUtil::checkMessage($value, $this->klass); 184 break; 185 default: 186 break; 187 } 188 if (is_null($offset)) { 189 $this->container[] = $value; 190 } else { 191 $count = count($this->container); 192 if (!is_numeric($offset) || $offset < 0 || $offset >= $count) { 193 trigger_error( 194 "Cannot modify element at the given index", 195 E_USER_ERROR); 196 return; 197 } 198 $this->container[$offset] = $value; 199 } 200 } 201 202 /** 203 * Remove the element at the given index. 204 * 205 * This will also be called for: unset($arr) 206 * 207 * @param long $offset The index of the element to be removed. 208 * @return void 209 * @throws \ErrorException Invalid type for index. 210 * @throws \ErrorException The element to be removed is not at the end of the 211 * RepeatedField. 212 */ 213 public function offsetUnset($offset) 214 { 215 $count = count($this->container); 216 if (!is_numeric($offset) || $count === 0 || $offset !== $count - 1) { 217 trigger_error( 218 "Cannot remove element at the given index", 219 E_USER_ERROR); 220 return; 221 } 222 array_pop($this->container); 223 } 224 225 /** 226 * Check the existence of the element at the given index. 227 * 228 * This will also be called for: isset($arr) 229 * 230 * @param long $offset The index of the element to be removed. 231 * @return bool True if the element at the given offset exists. 232 * @throws \ErrorException Invalid type for index. 233 */ 234 public function offsetExists($offset) 235 { 236 return isset($this->container[$offset]); 237 } 238 239 /** 240 * @ignore 241 */ 242 public function getIterator() 243 { 244 return new RepeatedFieldIter($this->container); 245 } 246 247 /** 248 * Return the number of stored elements. 249 * 250 * This will also be called for: count($arr) 251 * 252 * @return integer The number of stored elements. 253 */ 254 public function count() 255 { 256 return count($this->container); 257 } 258} 259