| <?php | |
| // Protocol Buffers - Google's data interchange format | |
| // Copyright 2008 Google Inc. All rights reserved. | |
| // | |
| // Use of this source code is governed by a BSD-style | |
| // license that can be found in the LICENSE file or at | |
| // https://developers.google.com/open-source/licenses/bsd | |
| /** | |
| * RepeatedField and RepeatedFieldIter are used by generated protocol message | |
| * classes to manipulate repeated fields. | |
| */ | |
| namespace Google\Protobuf; | |
| use Google\Protobuf\Internal\DescriptorPool; | |
| use Google\Protobuf\Internal\GPBType; | |
| use Google\Protobuf\Internal\GPBUtil; | |
| use Google\Protobuf\Internal\Message; | |
| use Google\Protobuf\Internal\RepeatedFieldIter; | |
| use Traversable; | |
| /** | |
| * RepeatedField is used by generated protocol message classes to manipulate | |
| * repeated fields. It can be used like native PHP array. | |
| * | |
| * @template T | |
| * @implements \ArrayAccess<int, T> | |
| * @implements \IteratorAggregate<T> | |
| */ | |
| class RepeatedField implements \ArrayAccess, \IteratorAggregate, \Countable | |
| { | |
| /** | |
| * @ignore | |
| */ | |
| private $container; | |
| /** | |
| * @ignore | |
| */ | |
| private $type; | |
| /** | |
| * @ignore | |
| * @var string|class-string<T> | |
| */ | |
| private $klass; | |
| /** | |
| * Constructs an instance of RepeatedField. | |
| * | |
| * @param integer $type Type of the stored element. | |
| * @param string|class-string<T> $klass Message/Enum class name (message/enum fields only). | |
| * @ignore | |
| */ | |
| public function __construct($type, $klass = null) | |
| { | |
| $this->container = []; | |
| $this->type = $type; | |
| if ($this->type == GPBType::MESSAGE) { | |
| $pool = DescriptorPool::getGeneratedPool(); | |
| $desc = $pool->getDescriptorByClassName($klass); | |
| if ($desc == NULL) { | |
| new $klass; // No msg class instance has been created before. | |
| $desc = $pool->getDescriptorByClassName($klass); | |
| } | |
| $this->klass = $desc->getClass(); | |
| } | |
| } | |
| /** | |
| * @ignore | |
| */ | |
| public function getType() | |
| { | |
| return $this->type; | |
| } | |
| /** | |
| * @ignore | |
| * @return string|class-string<T> | |
| */ | |
| public function getClass() | |
| { | |
| return $this->klass; | |
| } | |
| /** | |
| * Return the element at the given index. | |
| * | |
| * This will also be called for: $ele = $arr[0] | |
| * | |
| * @param integer $offset The index of the element to be fetched. | |
| * @return T The stored element at given index. | |
| * @throws \ErrorException Invalid type for index. | |
| * @throws \ErrorException Non-existing index. | |
| * @todo need to add return type mixed (require update php version to 8.0) | |
| */ | |
| #[\ReturnTypeWillChange] | |
| public function offsetGet($offset) | |
| { | |
| return $this->container[$offset]; | |
| } | |
| /** | |
| * Assign the element at the given index. | |
| * | |
| * This will also be called for: $arr []= $ele and $arr[0] = ele | |
| * | |
| * @param int|null $offset The index of the element to be assigned. | |
| * @param T $value The element to be assigned. | |
| * @return void | |
| * @throws \ErrorException Invalid type for index. | |
| * @throws \ErrorException Non-existing index. | |
| * @throws \ErrorException Incorrect type of the element. | |
| * @todo need to add return type void (require update php version to 7.1) | |
| */ | |
| #[\ReturnTypeWillChange] | |
| public function offsetSet($offset, $value) | |
| { | |
| switch ($this->type) { | |
| case GPBType::SFIXED32: | |
| case GPBType::SINT32: | |
| case GPBType::INT32: | |
| case GPBType::ENUM: | |
| GPBUtil::checkInt32($value); | |
| break; | |
| case GPBType::FIXED32: | |
| case GPBType::UINT32: | |
| GPBUtil::checkUint32($value); | |
| break; | |
| case GPBType::SFIXED64: | |
| case GPBType::SINT64: | |
| case GPBType::INT64: | |
| GPBUtil::checkInt64($value); | |
| break; | |
| case GPBType::FIXED64: | |
| case GPBType::UINT64: | |
| GPBUtil::checkUint64($value); | |
| break; | |
| case GPBType::FLOAT: | |
| GPBUtil::checkFloat($value); | |
| break; | |
| case GPBType::DOUBLE: | |
| GPBUtil::checkDouble($value); | |
| break; | |
| case GPBType::BOOL: | |
| GPBUtil::checkBool($value); | |
| break; | |
| case GPBType::BYTES: | |
| GPBUtil::checkString($value, false); | |
| break; | |
| case GPBType::STRING: | |
| GPBUtil::checkString($value, true); | |
| break; | |
| case GPBType::MESSAGE: | |
| if (is_null($value)) { | |
| throw new \TypeError("RepeatedField element cannot be null."); | |
| } | |
| GPBUtil::checkMessage($value, $this->klass); | |
| break; | |
| default: | |
| break; | |
| } | |
| if (is_null($offset)) { | |
| $this->container[] = $value; | |
| } else { | |
| $count = count($this->container); | |
| if (!is_numeric($offset) || $offset < 0 || $offset >= $count) { | |
| trigger_error( | |
| "Cannot modify element at the given index", | |
| E_USER_ERROR); | |
| return; | |
| } | |
| $this->container[$offset] = $value; | |
| } | |
| } | |
| /** | |
| * Remove the element at the given index. | |
| * | |
| * This will also be called for: unset($arr) | |
| * | |
| * @param integer $offset The index of the element to be removed. | |
| * @return void | |
| * @throws \ErrorException Invalid type for index. | |
| * @throws \ErrorException The element to be removed is not at the end of the | |
| * RepeatedField. | |
| * @todo need to add return type void (require update php version to 7.1) | |
| */ | |
| #[\ReturnTypeWillChange] | |
| public function offsetUnset($offset) | |
| { | |
| $count = count($this->container); | |
| if (!is_numeric($offset) || $count === 0 || $offset < 0 || $offset >= $count) { | |
| trigger_error( | |
| "Cannot remove element at the given index", | |
| E_USER_ERROR); | |
| return; | |
| } | |
| array_splice($this->container, $offset, 1); | |
| } | |
| /** | |
| * Check the existence of the element at the given index. | |
| * | |
| * This will also be called for: isset($arr) | |
| * | |
| * @param integer $offset The index of the element to be removed. | |
| * @return bool True if the element at the given offset exists. | |
| * @throws \ErrorException Invalid type for index. | |
| */ | |
| public function offsetExists($offset): bool | |
| { | |
| return isset($this->container[$offset]); | |
| } | |
| /** | |
| * @ignore | |
| */ | |
| public function getIterator(): Traversable | |
| { | |
| return new RepeatedFieldIter($this->container); | |
| } | |
| /** | |
| * Return the number of stored elements. | |
| * | |
| * This will also be called for: count($arr) | |
| * | |
| * @return integer The number of stored elements. | |
| */ | |
| public function count(): int | |
| { | |
| return count($this->container); | |
| } | |
| public function __debugInfo() | |
| { | |
| return array_map( | |
| function ($item) { | |
| if ($item instanceof Message || $item instanceof RepeatedField) { | |
| return $item->__debugInfo(); | |
| } | |
| return $item; | |
| }, | |
| iterator_to_array($this) | |
| ); | |
| } | |
| } | |
| class_alias(RepeatedField::class, Internal\RepeatedField::class); |