253 lines
7.3 KiB
PHP
253 lines
7.3 KiB
PHP
<?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);
|