| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656 | 
							- // Protocol Buffers - Google's data interchange format
 
- // Copyright 2008 Google Inc.  All rights reserved.
 
- // https://developers.google.com/protocol-buffers/
 
- //
 
- // Redistribution and use in source and binary forms, with or without
 
- // modification, are permitted provided that the following conditions are
 
- // met:
 
- //
 
- //     * Redistributions of source code must retain the above copyright
 
- // notice, this list of conditions and the following disclaimer.
 
- //     * Redistributions in binary form must reproduce the above
 
- // copyright notice, this list of conditions and the following disclaimer
 
- // in the documentation and/or other materials provided with the
 
- // distribution.
 
- //     * Neither the name of Google Inc. nor the names of its
 
- // contributors may be used to endorse or promote products derived from
 
- // this software without specific prior written permission.
 
- //
 
- // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 
- // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 
- // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 
- // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 
- // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 
- // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 
- // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 
- // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 
- // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 
- // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 
- // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
- #include "array.h"
 
- #include <Zend/zend_API.h>
 
- #include <Zend/zend_interfaces.h>
 
- #include <ext/spl/spl_iterators.h>
 
- // This is not self-contained: it must be after other Zend includes.
 
- #include <Zend/zend_exceptions.h>
 
- #include "arena.h"
 
- #include "convert.h"
 
- #include "def.h"
 
- #include "message.h"
 
- #include "php-upb.h"
 
- #include "protobuf.h"
 
- static void RepeatedFieldIter_make(zval *val, zval *repeated_field);
 
- // -----------------------------------------------------------------------------
 
- // RepeatedField
 
- // -----------------------------------------------------------------------------
 
- typedef struct {
 
-   zend_object std;
 
-   zval arena;
 
-   upb_array *array;
 
-   upb_fieldtype_t type;
 
-   const Descriptor* desc;  // When values are messages.
 
- } RepeatedField;
 
- zend_class_entry *RepeatedField_class_entry;
 
- static zend_object_handlers RepeatedField_object_handlers;
 
- // PHP Object Handlers /////////////////////////////////////////////////////////
 
- /**
 
-  * RepeatedField_create()
 
-  *
 
-  * PHP class entry function to allocate and initialize a new RepeatedField
 
-  * object.
 
-  */
 
- static zend_object* RepeatedField_create(zend_class_entry *class_type) {
 
-   RepeatedField *intern = emalloc(sizeof(RepeatedField));
 
-   zend_object_std_init(&intern->std, class_type);
 
-   intern->std.handlers = &RepeatedField_object_handlers;
 
-   Arena_Init(&intern->arena);
 
-   intern->array = NULL;
 
-   intern->desc = NULL;
 
-   // Skip object_properties_init(), we don't allow derived classes.
 
-   return &intern->std;
 
- }
 
- /**
 
-  * RepeatedField_dtor()
 
-  *
 
-  * Object handler to destroy a RepeatedField. This releases all resources
 
-  * associated with the message. Note that it is possible to access a destroyed
 
-  * object from PHP in rare cases.
 
-  */
 
- static void RepeatedField_destructor(zend_object* obj) {
 
-   RepeatedField* intern = (RepeatedField*)obj;
 
-   ObjCache_Delete(intern->array);
 
-   zval_ptr_dtor(&intern->arena);
 
-   zend_object_std_dtor(&intern->std);
 
- }
 
- /**
 
-  * RepeatedField_compare_objects()
 
-  *
 
-  * Object handler for comparing two repeated field objects. Called whenever PHP
 
-  * code does:
 
-  *
 
-  *   $rf1 == $rf2
 
-  */
 
- static int RepeatedField_compare_objects(zval *rf1, zval *rf2) {
 
-   RepeatedField* intern1 = (RepeatedField*)Z_OBJ_P(rf1);
 
-   RepeatedField* intern2 = (RepeatedField*)Z_OBJ_P(rf2);
 
-   upb_fieldtype_t type = intern1->type;
 
-   const upb_msgdef *m = intern1->desc ? intern1->desc->msgdef : NULL;
 
-   if (type != intern2->type) return 1;
 
-   if (intern1->desc != intern2->desc) return 1;
 
-   return ArrayEq(intern1->array, intern2->array, type, m) ? 0 : 1;
 
- }
 
- static HashTable *RepeatedField_GetProperties(PROTO_VAL *object) {
 
-   return NULL;  // We do not have a properties table.
 
- }
 
- static zval *RepeatedField_GetPropertyPtrPtr(PROTO_VAL *object,
 
-                                              PROTO_STR *member,
 
-                                              int type, void **cache_slot) {
 
-   return NULL;  // We don't offer direct references to our properties.
 
- }
 
- // C Functions from array.h ////////////////////////////////////////////////////
 
- // These are documented in the header file.
 
- void RepeatedField_GetPhpWrapper(zval *val, upb_array *arr,
 
-                                  const upb_fielddef *f, zval *arena) {
 
-   if (!arr) {
 
-     ZVAL_NULL(val);
 
-     return;
 
-   }
 
-   if (!ObjCache_Get(arr, val)) {
 
-     RepeatedField *intern = emalloc(sizeof(RepeatedField));
 
-     zend_object_std_init(&intern->std, RepeatedField_class_entry);
 
-     intern->std.handlers = &RepeatedField_object_handlers;
 
-     ZVAL_COPY(&intern->arena, arena);
 
-     intern->array = arr;
 
-     intern->type = upb_fielddef_type(f);
 
-     intern->desc = Descriptor_GetFromFieldDef(f);
 
-     // Skip object_properties_init(), we don't allow derived classes.
 
-     ObjCache_Add(intern->array, &intern->std);
 
-     ZVAL_OBJ(val, &intern->std);
 
-   }
 
- }
 
- upb_array *RepeatedField_GetUpbArray(zval *val, const upb_fielddef *f,
 
-                                      upb_arena *arena) {
 
-   if (Z_ISREF_P(val)) {
 
-     ZVAL_DEREF(val);
 
-   }
 
-   if (Z_TYPE_P(val) == IS_ARRAY) {
 
-     // Auto-construct, eg. [1, 2, 3] -> upb_array([1, 2, 3]).
 
-     upb_array *arr = upb_array_new(arena, upb_fielddef_type(f));
 
-     HashTable *table = HASH_OF(val);
 
-     HashPosition pos;
 
-     upb_fieldtype_t type = upb_fielddef_type(f);
 
-     const Descriptor *desc = Descriptor_GetFromFieldDef(f);
 
-     zend_hash_internal_pointer_reset_ex(table, &pos);
 
-     while (true) {
 
-       zval *zv = zend_hash_get_current_data_ex(table, &pos);
 
-       upb_msgval val;
 
-       if (!zv) return arr;
 
-       if (!Convert_PhpToUpbAutoWrap(zv, &val, type, desc, arena)) {
 
-         return NULL;
 
-       }
 
-       upb_array_append(arr, val, arena);
 
-       zend_hash_move_forward_ex(table, &pos);
 
-     }
 
-   } else if (Z_TYPE_P(val) == IS_OBJECT &&
 
-              Z_OBJCE_P(val) == RepeatedField_class_entry) {
 
-     // Unwrap existing RepeatedField object to get the upb_array* inside.
 
-     RepeatedField *intern = (RepeatedField*)Z_OBJ_P(val);
 
-     const Descriptor *desc = Descriptor_GetFromFieldDef(f);
 
-     if (intern->type != upb_fielddef_type(f) || intern->desc != desc) {
 
-       php_error_docref(NULL, E_USER_ERROR,
 
-                        "Wrong type for this repeated field.");
 
-     }
 
-     upb_arena_fuse(arena, Arena_Get(&intern->arena));
 
-     return intern->array;
 
-   } else {
 
-     php_error_docref(NULL, E_USER_ERROR, "Must be a repeated field");
 
-     return NULL;
 
-   }
 
- }
 
- bool ArrayEq(const upb_array *a1, const upb_array *a2, upb_fieldtype_t type,
 
-              const upb_msgdef *m) {
 
-   size_t i;
 
-   size_t n;
 
-   if ((a1 == NULL) != (a2 == NULL)) return false;
 
-   if (a1 == NULL) return true;
 
-   n = upb_array_size(a1);
 
-   if (n != upb_array_size(a2)) return false;
 
-   for (i = 0; i < n; i++) {
 
-     upb_msgval val1 = upb_array_get(a1, i);
 
-     upb_msgval val2 = upb_array_get(a2, i);
 
-     if (!ValueEq(val1, val2, type, m)) return false;
 
-   }
 
-   return true;
 
- }
 
- // RepeatedField PHP methods ///////////////////////////////////////////////////
 
- /**
 
-  * RepeatedField::__construct()
 
-  *
 
-  * Constructs an instance of RepeatedField.
 
-  * @param long Type of the stored element.
 
-  * @param string Message/Enum class.
 
-  */
 
- PHP_METHOD(RepeatedField, __construct) {
 
-   RepeatedField *intern = (RepeatedField*)Z_OBJ_P(getThis());
 
-   upb_arena *arena = Arena_Get(&intern->arena);
 
-   zend_long type;
 
-   zend_class_entry* klass = NULL;
 
-   if (zend_parse_parameters(ZEND_NUM_ARGS(), "l|C", &type, &klass) != SUCCESS) {
 
-     return;
 
-   }
 
-   intern->type = pbphp_dtype_to_type(type);
 
-   intern->desc = Descriptor_GetFromClassEntry(klass);
 
-   if (intern->type == UPB_TYPE_MESSAGE && klass == NULL) {
 
-     php_error_docref(NULL, E_USER_ERROR,
 
-                      "Message/enum type must have concrete class.");
 
-     return;
 
-   }
 
-   intern->array = upb_array_new(arena, intern->type);
 
-   ObjCache_Add(intern->array, &intern->std);
 
- }
 
- /**
 
-  * RepeatedField::append()
 
-  *
 
-  * Append element to the end of the repeated field.
 
-  * @param object The element to be added.
 
-  */
 
- PHP_METHOD(RepeatedField, append) {
 
-   RepeatedField *intern = (RepeatedField*)Z_OBJ_P(getThis());
 
-   upb_arena *arena = Arena_Get(&intern->arena);
 
-   zval *php_val;
 
-   upb_msgval msgval;
 
-   if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &php_val) != SUCCESS ||
 
-       !Convert_PhpToUpb(php_val, &msgval, intern->type, intern->desc, arena)) {
 
-     return;
 
-   }
 
-   upb_array_append(intern->array, msgval, arena);
 
- }
 
- /**
 
-  * RepeatedField::offsetExists()
 
-  *
 
-  * Implements the ArrayAccess interface. Invoked when PHP code calls:
 
-  *
 
-  *   isset($arr[$idx]);
 
-  *   empty($arr[$idx]);
 
-  *
 
-  * @param long The index to be checked.
 
-  * @return bool True if the element at the given index exists.
 
-  */
 
- PHP_METHOD(RepeatedField, offsetExists) {
 
-   RepeatedField *intern = (RepeatedField*)Z_OBJ_P(getThis());
 
-   zend_long index;
 
-   if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &index) == FAILURE) {
 
-     return;
 
-   }
 
-   RETURN_BOOL(index >= 0 && index < upb_array_size(intern->array));
 
- }
 
- /**
 
-  * RepeatedField::offsetGet()
 
-  *
 
-  * Implements the ArrayAccess interface. Invoked when PHP code calls:
 
-  *
 
-  *   $x = $arr[$idx];
 
-  *
 
-  * @param long The index of the element to be fetched.
 
-  * @return object The stored element at given index.
 
-  * @exception Invalid type for index.
 
-  * @exception Non-existing index.
 
-  */
 
- PHP_METHOD(RepeatedField, offsetGet) {
 
-   RepeatedField *intern = (RepeatedField*)Z_OBJ_P(getThis());
 
-   zend_long index;
 
-   upb_msgval msgval;
 
-   zval ret;
 
-   if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &index) == FAILURE) {
 
-     return;
 
-   }
 
-   if (index < 0 || index >= upb_array_size(intern->array)) {
 
-     zend_error(E_USER_ERROR, "Element at %ld doesn't exist.\n", index);
 
-     return;
 
-   }
 
-   msgval = upb_array_get(intern->array, index);
 
-   Convert_UpbToPhp(msgval, &ret, intern->type, intern->desc, &intern->arena);
 
-   RETURN_ZVAL(&ret, 0, 1);
 
- }
 
- /**
 
-  * RepeatedField::offsetSet()
 
-  *
 
-  * Implements the ArrayAccess interface. Invoked when PHP code calls:
 
-  *
 
-  *   $arr[$idx] = $x;
 
-  *   $arr []= $x;  // Append
 
-  *
 
-  * @param long The index of the element to be assigned.
 
-  * @param object The element to be assigned.
 
-  * @exception Invalid type for index.
 
-  * @exception Non-existing index.
 
-  * @exception Incorrect type of the element.
 
-  */
 
- PHP_METHOD(RepeatedField, offsetSet) {
 
-   RepeatedField *intern = (RepeatedField*)Z_OBJ_P(getThis());
 
-   upb_arena *arena = Arena_Get(&intern->arena);
 
-   size_t size = upb_array_size(intern->array);
 
-   zval *offset, *val;
 
-   int64_t index;
 
-   upb_msgval msgval;
 
-   if (zend_parse_parameters(ZEND_NUM_ARGS(), "zz", &offset, &val) != SUCCESS) {
 
-     return;
 
-   }
 
-   if (Z_TYPE_P(offset) == IS_NULL) {
 
-     index = size;
 
-   } else if (!Convert_PhpToInt64(offset, &index)) {
 
-     return;
 
-   }
 
-   if (!Convert_PhpToUpb(val, &msgval, intern->type, intern->desc, arena)) {
 
-     return;
 
-   }
 
-   if (index > size) {
 
-     zend_error(E_USER_ERROR, "Element at index %ld doesn't exist.\n", index);
 
-   } else if (index == size) {
 
-     upb_array_append(intern->array, msgval, Arena_Get(&intern->arena));
 
-   } else {
 
-     upb_array_set(intern->array, index, msgval);
 
-   }
 
- }
 
- /**
 
-  * RepeatedField::offsetUnset()
 
-  *
 
-  * Implements the ArrayAccess interface. Invoked when PHP code calls:
 
-  *
 
-  *   unset($arr[$idx]);
 
-  *
 
-  * @param long The index of the element to be removed.
 
-  * @exception Invalid type for index.
 
-  * @exception The element to be removed is not at the end of the RepeatedField.
 
-  */
 
- PHP_METHOD(RepeatedField, offsetUnset) {
 
-   RepeatedField *intern = (RepeatedField*)Z_OBJ_P(getThis());
 
-   zend_long index;
 
-   zend_long size = upb_array_size(intern->array);
 
-   // Only the element at the end of the array can be removed.
 
-   if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &index) != SUCCESS) {
 
-     return;
 
-   }
 
-   if (size == 0 || index != size - 1) {
 
-     php_error_docref(NULL, E_USER_ERROR, "Cannot remove element at %ld.\n",
 
-                      index);
 
-     return;
 
-   }
 
-   upb_array_resize(intern->array, size - 1, Arena_Get(&intern->arena));
 
- }
 
- /**
 
-  * RepeatedField::count()
 
-  *
 
-  * Implements the Countable interface. Invoked when PHP code calls:
 
-  *
 
-  *   $len = count($arr);
 
-  * Return the number of stored elements.
 
-  * This will also be called for: count($arr)
 
-  * @return long The number of stored elements.
 
-  */
 
- PHP_METHOD(RepeatedField, count) {
 
-   RepeatedField *intern = (RepeatedField*)Z_OBJ_P(getThis());
 
-   if (zend_parse_parameters_none() == FAILURE) {
 
-     return;
 
-   }
 
-   RETURN_LONG(upb_array_size(intern->array));
 
- }
 
- /**
 
-  * RepeatedField::getIterator()
 
-  *
 
-  * Implements the IteratorAggregate interface. Invoked when PHP code calls:
 
-  *
 
-  *   foreach ($arr) {}
 
-  *
 
-  * @return object Beginning iterator.
 
-  */
 
- PHP_METHOD(RepeatedField, getIterator) {
 
-   zval ret;
 
-   RepeatedFieldIter_make(&ret, getThis());
 
-   RETURN_ZVAL(&ret, 0, 1);
 
- }
 
- ZEND_BEGIN_ARG_INFO_EX(arginfo_construct, 0, 0, 1)
 
-   ZEND_ARG_INFO(0, type)
 
-   ZEND_ARG_INFO(0, class)
 
- ZEND_END_ARG_INFO()
 
- ZEND_BEGIN_ARG_INFO_EX(arginfo_append, 0, 0, 1)
 
-   ZEND_ARG_INFO(0, newval)
 
- ZEND_END_ARG_INFO()
 
- ZEND_BEGIN_ARG_INFO_EX(arginfo_offsetGet, 0, 0, 1)
 
-   ZEND_ARG_INFO(0, index)
 
- ZEND_END_ARG_INFO()
 
- ZEND_BEGIN_ARG_INFO_EX(arginfo_offsetSet, 0, 0, 2)
 
-   ZEND_ARG_INFO(0, index)
 
-   ZEND_ARG_INFO(0, newval)
 
- ZEND_END_ARG_INFO()
 
- static zend_function_entry repeated_field_methods[] = {
 
-   PHP_ME(RepeatedField, __construct,  arginfo_construct, ZEND_ACC_PUBLIC)
 
-   PHP_ME(RepeatedField, append,       arginfo_append,    ZEND_ACC_PUBLIC)
 
-   PHP_ME(RepeatedField, offsetExists, arginfo_offsetGet, ZEND_ACC_PUBLIC)
 
-   PHP_ME(RepeatedField, offsetGet,    arginfo_offsetGet, ZEND_ACC_PUBLIC)
 
-   PHP_ME(RepeatedField, offsetSet,    arginfo_offsetSet, ZEND_ACC_PUBLIC)
 
-   PHP_ME(RepeatedField, offsetUnset,  arginfo_offsetGet, ZEND_ACC_PUBLIC)
 
-   PHP_ME(RepeatedField, count,        arginfo_void,      ZEND_ACC_PUBLIC)
 
-   PHP_ME(RepeatedField, getIterator,  arginfo_void,      ZEND_ACC_PUBLIC)
 
-   ZEND_FE_END
 
- };
 
- // -----------------------------------------------------------------------------
 
- // PHP RepeatedFieldIter
 
- // -----------------------------------------------------------------------------
 
- typedef struct {
 
-   zend_object std;
 
-   zval repeated_field;
 
-   zend_long position;
 
- } RepeatedFieldIter;
 
- zend_class_entry *RepeatedFieldIter_class_entry;
 
- static zend_object_handlers repeated_field_iter_object_handlers;
 
- /**
 
-  * RepeatedFieldIter_create()
 
-  *
 
-  * PHP class entry function to allocate and initialize a new RepeatedFieldIter
 
-  * object.
 
-  */
 
- zend_object* RepeatedFieldIter_create(zend_class_entry *class_type) {
 
-   RepeatedFieldIter *intern = emalloc(sizeof(RepeatedFieldIter));
 
-   zend_object_std_init(&intern->std, class_type);
 
-   intern->std.handlers = &repeated_field_iter_object_handlers;
 
-   ZVAL_NULL(&intern->repeated_field);
 
-   intern->position = 0;
 
-   // Skip object_properties_init(), we don't allow derived classes.
 
-   return &intern->std;
 
- }
 
- /**
 
-  * RepeatedFieldIter_dtor()
 
-  *
 
-  * Object handler to destroy a RepeatedFieldIter. This releases all resources
 
-  * associated with the message. Note that it is possible to access a destroyed
 
-  * object from PHP in rare cases.
 
-  */
 
- static void RepeatedFieldIter_dtor(zend_object* obj) {
 
-   RepeatedFieldIter* intern = (RepeatedFieldIter*)obj;
 
-   zval_ptr_dtor(&intern->repeated_field);
 
-   zend_object_std_dtor(&intern->std);
 
- }
 
- /**
 
-  * RepeatedFieldIter_make()
 
-  *
 
-  * C function to create a RepeatedFieldIter.
 
-  */
 
- static void RepeatedFieldIter_make(zval *val, zval *repeated_field) {
 
-   RepeatedFieldIter *iter;
 
-   ZVAL_OBJ(val, RepeatedFieldIter_class_entry->create_object(
 
-                     RepeatedFieldIter_class_entry));
 
-   iter = (RepeatedFieldIter*)Z_OBJ_P(val);
 
-   ZVAL_COPY(&iter->repeated_field, repeated_field);
 
- }
 
- /*
 
-  * When a user writes:
 
-  *
 
-  *   foreach($arr as $key => $val) {}
 
-  *
 
-  * PHP's iterator protocol is:
 
-  *
 
-  *   $iter = $arr->getIterator();
 
-  *   for ($iter->rewind(); $iter->valid(); $iter->next()) {
 
-  *     $key = $iter->key();
 
-  *     $val = $iter->current();
 
-  *   }
 
-  */
 
- /**
 
-  * RepeatedFieldIter::rewind()
 
-  *
 
-  * Implements the Iterator interface. Sets the iterator to the first element.
 
-  */
 
- PHP_METHOD(RepeatedFieldIter, rewind) {
 
-   RepeatedFieldIter *intern = (RepeatedFieldIter*)Z_OBJ_P(getThis());
 
-   intern->position = 0;
 
- }
 
- /**
 
-  * RepeatedFieldIter::current()
 
-  *
 
-  * Implements the Iterator interface. Returns the current value.
 
-  */
 
- PHP_METHOD(RepeatedFieldIter, current) {
 
-   RepeatedFieldIter *intern = (RepeatedFieldIter*)Z_OBJ_P(getThis());
 
-   RepeatedField *field = (RepeatedField*)Z_OBJ_P(&intern->repeated_field);
 
-   upb_array *array = field->array;
 
-   zend_long index = intern->position;
 
-   upb_msgval msgval;
 
-   zval ret;
 
-   if (index < 0 || index >= upb_array_size(array)) {
 
-     zend_error(E_USER_ERROR, "Element at %ld doesn't exist.\n", index);
 
-   }
 
-   msgval = upb_array_get(array, index);
 
-   Convert_UpbToPhp(msgval, &ret, field->type, field->desc, &field->arena);
 
-   RETURN_ZVAL(&ret, 0, 1);
 
- }
 
- /**
 
-  * RepeatedFieldIter::key()
 
-  *
 
-  * Implements the Iterator interface. Returns the current key.
 
-  */
 
- PHP_METHOD(RepeatedFieldIter, key) {
 
-   RepeatedFieldIter *intern = (RepeatedFieldIter*)Z_OBJ_P(getThis());
 
-   RETURN_LONG(intern->position);
 
- }
 
- /**
 
-  * RepeatedFieldIter::next()
 
-  *
 
-  * Implements the Iterator interface. Advances to the next element.
 
-  */
 
- PHP_METHOD(RepeatedFieldIter, next) {
 
-   RepeatedFieldIter *intern = (RepeatedFieldIter*)Z_OBJ_P(getThis());
 
-   ++intern->position;
 
- }
 
- /**
 
-  * RepeatedFieldIter::valid()
 
-  *
 
-  * Implements the Iterator interface. Returns true if this is a valid element.
 
-  */
 
- PHP_METHOD(RepeatedFieldIter, valid) {
 
-   RepeatedFieldIter *intern = (RepeatedFieldIter*)Z_OBJ_P(getThis());
 
-   RepeatedField *field = (RepeatedField*)Z_OBJ_P(&intern->repeated_field);
 
-   RETURN_BOOL(intern->position < upb_array_size(field->array));
 
- }
 
- static zend_function_entry repeated_field_iter_methods[] = {
 
-   PHP_ME(RepeatedFieldIter, rewind,      arginfo_void, ZEND_ACC_PUBLIC)
 
-   PHP_ME(RepeatedFieldIter, current,     arginfo_void, ZEND_ACC_PUBLIC)
 
-   PHP_ME(RepeatedFieldIter, key,         arginfo_void, ZEND_ACC_PUBLIC)
 
-   PHP_ME(RepeatedFieldIter, next,        arginfo_void, ZEND_ACC_PUBLIC)
 
-   PHP_ME(RepeatedFieldIter, valid,       arginfo_void, ZEND_ACC_PUBLIC)
 
-   ZEND_FE_END
 
- };
 
- // -----------------------------------------------------------------------------
 
- // Module init.
 
- // -----------------------------------------------------------------------------
 
- /**
 
-  * Array_ModuleInit()
 
-  *
 
-  * Called when the C extension is loaded to register all types.
 
-  */
 
- void Array_ModuleInit() {
 
-   zend_class_entry tmp_ce;
 
-   zend_object_handlers *h;
 
-   // RepeatedField.
 
-   INIT_CLASS_ENTRY(tmp_ce, "Google\\Protobuf\\Internal\\RepeatedField",
 
-                    repeated_field_methods);
 
-   RepeatedField_class_entry = zend_register_internal_class(&tmp_ce);
 
-   zend_class_implements(RepeatedField_class_entry, 3, spl_ce_ArrayAccess,
 
-                         zend_ce_aggregate, spl_ce_Countable);
 
-   RepeatedField_class_entry->ce_flags |= ZEND_ACC_FINAL;
 
-   RepeatedField_class_entry->create_object = RepeatedField_create;
 
-   h = &RepeatedField_object_handlers;
 
-   memcpy(h, &std_object_handlers, sizeof(zend_object_handlers));
 
-   h->dtor_obj = RepeatedField_destructor;
 
- #if PHP_VERSION_ID < 80000
 
-   h->compare_objects = RepeatedField_compare_objects;
 
- #else
 
-   h->compare = RepeatedField_compare_objects;
 
- #endif
 
-   h->get_properties = RepeatedField_GetProperties;
 
-   h->get_property_ptr_ptr = RepeatedField_GetPropertyPtrPtr;
 
-   // RepeatedFieldIter
 
-   INIT_CLASS_ENTRY(tmp_ce, "Google\\Protobuf\\Internal\\RepeatedFieldIter",
 
-                    repeated_field_iter_methods);
 
-   RepeatedFieldIter_class_entry = zend_register_internal_class(&tmp_ce);
 
-   zend_class_implements(RepeatedFieldIter_class_entry, 1, zend_ce_iterator);
 
-   RepeatedFieldIter_class_entry->ce_flags |= ZEND_ACC_FINAL;
 
-   RepeatedFieldIter_class_entry->create_object = RepeatedFieldIter_create;
 
-   h = &repeated_field_iter_object_handlers;
 
-   memcpy(h, &std_object_handlers, sizeof(zend_object_handlers));
 
-   h->dtor_obj = RepeatedFieldIter_dtor;
 
- }
 
 
  |