Merge pull request #9370 from brettmc/bugfix/php-8.1-deprecations

fixing php 8.1 deprecation warnings
diff --git a/kokoro/linux/dockerfile/test/php80/Dockerfile b/kokoro/linux/dockerfile/test/php80/Dockerfile
index 8093eae..5b382d0 100644
--- a/kokoro/linux/dockerfile/test/php80/Dockerfile
+++ b/kokoro/linux/dockerfile/test/php80/Dockerfile
@@ -1,4 +1,4 @@
-FROM debian:jessie
+FROM debian:stretch
 
 # Install dependencies.  We start with the basic ones require to build protoc
 # and the C++ build
@@ -29,7 +29,7 @@
 
 # Install php dependencies
 RUN apt-get clean && apt-get update && apt-get install -y --force-yes \
-  php5 \
+  php \
   libcurl4-openssl-dev \
   libgmp-dev \
   libgmp3-dev \
@@ -90,6 +90,34 @@
   && cp phpunit /usr/local/php-8.0/bin \
   && mv phpunit /usr/local/php-8.0-zts/bin
 
+# php 8.1
+RUN cd php-src \
+  && git checkout php-8.1.2 \
+  && ./buildconf --force
+RUN cd php-src \
+  && ./configure \
+  --enable-bcmath \
+  --enable-mbstring \
+  --with-gmp \
+  --with-openssl \
+  --with-zlib \
+  --prefix=/usr/local/php-8.1 \
+  && make \
+  && make install \
+  && make clean
+RUN cd php-src \
+  && ./configure \
+  --enable-bcmath \
+  --enable-mbstring \
+  --enable-maintainer-zts \
+  --with-gmp \
+  --with-openssl \
+  --with-zlib \
+  --prefix=/usr/local/php-8.1-zts \
+  && make \
+  && make install \
+  && make clean
+
 # Install php dependencies
 RUN apt-get clean && apt-get update && apt-get install -y --force-yes \
   valgrind \
diff --git a/php/ext/google/protobuf/array.c b/php/ext/google/protobuf/array.c
index 2c9a710..9c290f7 100644
--- a/php/ext/google/protobuf/array.c
+++ b/php/ext/google/protobuf/array.c
@@ -287,7 +287,7 @@
 }
 
 /**
- * RepeatedField::offsetExists()
+ * RepeatedField::offsetExists(): bool
  *
  * Implements the ArrayAccess interface. Invoked when PHP code calls:
  *
@@ -309,7 +309,7 @@
 }
 
 /**
- * RepeatedField::offsetGet()
+ * RepeatedField::offsetGet(): mixed
  *
  * Implements the ArrayAccess interface. Invoked when PHP code calls:
  *
@@ -341,7 +341,7 @@
 }
 
 /**
- * RepeatedField::offsetSet()
+ * RepeatedField::offsetSet(): void
  *
  * Implements the ArrayAccess interface. Invoked when PHP code calls:
  *
@@ -386,7 +386,7 @@
 }
 
 /**
- * RepeatedField::offsetUnset()
+ * RepeatedField::offsetUnset(): void
  *
  * Implements the ArrayAccess interface. Invoked when PHP code calls:
  *
@@ -416,7 +416,7 @@
 }
 
 /**
- * RepeatedField::count()
+ * RepeatedField::count(): int
  *
  * Implements the Countable interface. Invoked when PHP code calls:
  *
@@ -436,7 +436,7 @@
 }
 
 /**
- * RepeatedField::getIterator()
+ * RepeatedField::getIterator(): Traversable
  *
  * Implements the IteratorAggregate interface. Invoked when PHP code calls:
  *
@@ -459,24 +459,38 @@
   ZEND_ARG_INFO(0, newval)
 ZEND_END_ARG_INFO()
 
-ZEND_BEGIN_ARG_INFO_EX(arginfo_offsetGet, 0, 0, 1)
+PROTOBUF_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_offsetExists, 0, 0, _IS_BOOL, 0)
   ZEND_ARG_INFO(0, index)
 ZEND_END_ARG_INFO()
 
-ZEND_BEGIN_ARG_INFO_EX(arginfo_offsetSet, 0, 0, 2)
+ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(arginfo_offsetGet, 0, 0, IS_MIXED, 1)
+  ZEND_ARG_INFO(0, index)
+ZEND_END_ARG_INFO()
+
+PROTOBUF_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_offsetSet, 0, 2, IS_VOID, 0)
   ZEND_ARG_INFO(0, index)
   ZEND_ARG_INFO(0, newval)
 ZEND_END_ARG_INFO()
 
+PROTOBUF_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_offsetUnset, 0, 0, IS_VOID, 0)
+  ZEND_ARG_INFO(0, index)
+ZEND_END_ARG_INFO()
+
+PROTOBUF_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_count, 0, 0, IS_LONG, 0)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_getIterator, 0, 0, Traversable, 0)
+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)
+  PHP_ME(RepeatedField, __construct,  arginfo_construct,    ZEND_ACC_PUBLIC)
+  PHP_ME(RepeatedField, append,       arginfo_append,       ZEND_ACC_PUBLIC)
+  PHP_ME(RepeatedField, offsetExists, arginfo_offsetExists, 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_offsetUnset,  ZEND_ACC_PUBLIC)
+  PHP_ME(RepeatedField, count,        arginfo_count,        ZEND_ACC_PUBLIC)
+  PHP_ME(RepeatedField, getIterator,  arginfo_getIterator,  ZEND_ACC_PUBLIC)
   ZEND_FE_END
 };
 
@@ -550,7 +564,7 @@
  */
 
 /**
- * RepeatedFieldIter::rewind()
+ * RepeatedFieldIter::rewind(): void
  *
  * Implements the Iterator interface. Sets the iterator to the first element.
  */
@@ -560,7 +574,7 @@
 }
 
 /**
- * RepeatedFieldIter::current()
+ * RepeatedFieldIter::current(): mixed
  *
  * Implements the Iterator interface. Returns the current value.
  */
@@ -583,7 +597,7 @@
 }
 
 /**
- * RepeatedFieldIter::key()
+ * RepeatedFieldIter::key(): mixed
  *
  * Implements the Iterator interface. Returns the current key.
  */
@@ -593,7 +607,7 @@
 }
 
 /**
- * RepeatedFieldIter::next()
+ * RepeatedFieldIter::next(): void
  *
  * Implements the Iterator interface. Advances to the next element.
  */
@@ -603,7 +617,7 @@
 }
 
 /**
- * RepeatedFieldIter::valid()
+ * RepeatedFieldIter::valid(): bool
  *
  * Implements the Iterator interface. Returns true if this is a valid element.
  */
@@ -613,12 +627,27 @@
   RETURN_BOOL(intern->position < upb_array_size(field->array));
 }
 
+ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(arginfo_current, 0, 0, IS_MIXED, 0)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(arginfo_key, 0, 0, IS_MIXED, 0)
+ZEND_END_ARG_INFO()
+
+PROTOBUF_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_next, 0, 0, IS_VOID, 0)
+ZEND_END_ARG_INFO()
+
+PROTOBUF_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_valid, 0, 0, _IS_BOOL, 0)
+ZEND_END_ARG_INFO()
+
+PROTOBUF_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_rewind, 0, 0, IS_VOID, 0)
+ZEND_END_ARG_INFO()
+
 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)
+  PHP_ME(RepeatedFieldIter, rewind,      arginfo_rewind,  ZEND_ACC_PUBLIC)
+  PHP_ME(RepeatedFieldIter, current,     arginfo_current, ZEND_ACC_PUBLIC)
+  PHP_ME(RepeatedFieldIter, key,         arginfo_key,     ZEND_ACC_PUBLIC)
+  PHP_ME(RepeatedFieldIter, next,        arginfo_next,    ZEND_ACC_PUBLIC)
+  PHP_ME(RepeatedFieldIter, valid,       arginfo_valid,   ZEND_ACC_PUBLIC)
   ZEND_FE_END
 };
 
diff --git a/php/ext/google/protobuf/map.c b/php/ext/google/protobuf/map.c
index bbdfe29..252b1f5 100644
--- a/php/ext/google/protobuf/map.c
+++ b/php/ext/google/protobuf/map.c
@@ -305,7 +305,7 @@
 }
 
 /**
- * MapField::offsetExists()
+ * MapField::offsetExists(): bool
  *
  * Implements the ArrayAccess interface. Invoked when PHP code calls:
  *
@@ -329,7 +329,7 @@
 }
 
 /**
- * MapField::offsetGet()
+ * MapField::offsetGet(): mixed
  *
  * Implements the ArrayAccess interface. Invoked when PHP code calls:
  *
@@ -361,7 +361,7 @@
 }
 
 /**
- * MapField::offsetSet()
+ * MapField::offsetSet(): void
  *
  * Implements the ArrayAccess interface. Invoked when PHP code calls:
  *
@@ -389,7 +389,7 @@
 }
 
 /**
- * MapField::offsetUnset()
+ * MapField::offsetUnset(): void
  *
  * Implements the ArrayAccess interface. Invoked when PHP code calls:
  *
@@ -413,7 +413,7 @@
 }
 
 /**
- * MapField::count()
+ * MapField::count(): int
  *
  * Implements the Countable interface. Invoked when PHP code calls:
  *
@@ -433,7 +433,7 @@
 }
 
 /**
- * MapField::getIterator()
+ * MapField::getIterator(): Traversable
  *
  * Implements the IteratorAggregate interface. Invoked when PHP code calls:
  *
@@ -453,23 +453,38 @@
   ZEND_ARG_INFO(0, value_class)
 ZEND_END_ARG_INFO()
 
-ZEND_BEGIN_ARG_INFO_EX(arginfo_offsetGet, 0, 0, 1)
+
+ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(arginfo_offsetGet, 0, 0, IS_MIXED, 1)
   ZEND_ARG_INFO(0, index)
 ZEND_END_ARG_INFO()
 
-ZEND_BEGIN_ARG_INFO_EX(arginfo_offsetSet, 0, 0, 2)
+PROTOBUF_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_offsetSet, 0, 2, IS_VOID, 0)
   ZEND_ARG_INFO(0, index)
   ZEND_ARG_INFO(0, newval)
 ZEND_END_ARG_INFO()
 
+PROTOBUF_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_offsetUnset, 0, 0, IS_VOID, 0)
+  ZEND_ARG_INFO(0, index)
+ZEND_END_ARG_INFO()
+
+PROTOBUF_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_offsetExists, 0, 0, _IS_BOOL, 0)
+  ZEND_ARG_INFO(0, index)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_getIterator, 0, 0, Traversable, 0)
+ZEND_END_ARG_INFO()
+
+PROTOBUF_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_count, 0, 0, IS_LONG, 0)
+ZEND_END_ARG_INFO()
+
 static zend_function_entry MapField_methods[] = {
-  PHP_ME(MapField, __construct,  arginfo_construct, ZEND_ACC_PUBLIC)
-  PHP_ME(MapField, offsetExists, arginfo_offsetGet, ZEND_ACC_PUBLIC)
-  PHP_ME(MapField, offsetGet,    arginfo_offsetGet, ZEND_ACC_PUBLIC)
-  PHP_ME(MapField, offsetSet,    arginfo_offsetSet, ZEND_ACC_PUBLIC)
-  PHP_ME(MapField, offsetUnset,  arginfo_offsetGet, ZEND_ACC_PUBLIC)
-  PHP_ME(MapField, count,        arginfo_void,      ZEND_ACC_PUBLIC)
-  PHP_ME(MapField, getIterator,  arginfo_void,      ZEND_ACC_PUBLIC)
+  PHP_ME(MapField, __construct,  arginfo_construct,    ZEND_ACC_PUBLIC)
+  PHP_ME(MapField, offsetExists, arginfo_offsetExists, ZEND_ACC_PUBLIC)
+  PHP_ME(MapField, offsetGet,    arginfo_offsetGet,    ZEND_ACC_PUBLIC)
+  PHP_ME(MapField, offsetSet,    arginfo_offsetSet,    ZEND_ACC_PUBLIC)
+  PHP_ME(MapField, offsetUnset,  arginfo_offsetUnset,  ZEND_ACC_PUBLIC)
+  PHP_ME(MapField, count,        arginfo_count,        ZEND_ACC_PUBLIC)
+  PHP_ME(MapField, getIterator,  arginfo_getIterator,  ZEND_ACC_PUBLIC)
   ZEND_FE_END
 };
 
@@ -547,7 +562,7 @@
  */
 
 /**
- * MapFieldIter::rewind()
+ * MapFieldIter::rewind(): void
  *
  * Implements the Iterator interface. Sets the iterator to the first element.
  */
@@ -559,7 +574,7 @@
 }
 
 /**
- * MapFieldIter::current()
+ * MapFieldIter::current(): mixed
  *
  * Implements the Iterator interface. Returns the current value.
  */
@@ -587,7 +602,7 @@
 }
 
 /**
- * MapFieldIter::next()
+ * MapFieldIter::next(): void
  *
  * Implements the Iterator interface. Advances to the next element.
  */
@@ -598,7 +613,7 @@
 }
 
 /**
- * MapFieldIter::valid()
+ * MapFieldIter::valid(): bool
  *
  * Implements the Iterator interface. Returns true if this is a valid element.
  */
@@ -609,12 +624,27 @@
   RETURN_BOOL(!done);
 }
 
+PROTOBUF_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_rewind, 0, 0, IS_VOID, 0)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(arginfo_current, 0, 0, IS_MIXED, 0)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(arginfo_key, 0, 0, IS_MIXED, 0)
+ZEND_END_ARG_INFO()
+
+PROTOBUF_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_next, 0, 0, IS_VOID, 0)
+ZEND_END_ARG_INFO()
+
+PROTOBUF_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_valid, 0, 0, _IS_BOOL, 0)
+ZEND_END_ARG_INFO()
+
 static zend_function_entry map_field_iter_methods[] = {
-  PHP_ME(MapFieldIter, rewind,      arginfo_void, ZEND_ACC_PUBLIC)
-  PHP_ME(MapFieldIter, current,     arginfo_void, ZEND_ACC_PUBLIC)
-  PHP_ME(MapFieldIter, key,         arginfo_void, ZEND_ACC_PUBLIC)
-  PHP_ME(MapFieldIter, next,        arginfo_void, ZEND_ACC_PUBLIC)
-  PHP_ME(MapFieldIter, valid,       arginfo_void, ZEND_ACC_PUBLIC)
+  PHP_ME(MapFieldIter, rewind,      arginfo_rewind,  ZEND_ACC_PUBLIC)
+  PHP_ME(MapFieldIter, current,     arginfo_current, ZEND_ACC_PUBLIC)
+  PHP_ME(MapFieldIter, key,         arginfo_key,     ZEND_ACC_PUBLIC)
+  PHP_ME(MapFieldIter, next,        arginfo_next,    ZEND_ACC_PUBLIC)
+  PHP_ME(MapFieldIter, valid,       arginfo_valid,   ZEND_ACC_PUBLIC)
   ZEND_FE_END
 };
 
diff --git a/php/ext/google/protobuf/protobuf.h b/php/ext/google/protobuf/protobuf.h
index 41ae271..fdee117 100644
--- a/php/ext/google/protobuf/protobuf.h
+++ b/php/ext/google/protobuf/protobuf.h
@@ -82,6 +82,42 @@
 // PHP 7.2.0.
 #if PHP_VERSION_ID < 70200
 #define zend_ce_countable spl_ce_Countable
+#define ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(name, return_reference, required_num_args, class_name, allow_null) \
+        ZEND_BEGIN_ARG_INFO_EX(name, return_reference, required_num_args, allow_null)
+#endif
+
+// polyfill for ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX, which changes between 7.1 and 7.2
+#if PHP_VERSION_ID < 70200
+#define PROTOBUF_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(name, return_reference, required_num_args, type, allow_null) \
+        ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(name, return_reference, required_num_args, type, /*class_name*/ 0, allow_null)
+#else
+#define PROTOBUF_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(name, return_reference, required_num_args, type, allow_null) \
+        ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(name, return_reference, required_num_args, type, allow_null)
+#endif
+
+// In PHP 8.1, mismatched tentative return types emit a deprecation notice.
+// https://wiki.php.net/rfc/internal_method_return_types
+//
+// When compiling for earlier php versions, the return type is dropped.
+#if PHP_VERSION_ID < 80100
+#define ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(name, return_reference, required_num_args, type, allow_null) \
+        ZEND_BEGIN_ARG_INFO_EX(name, return_reference, required_num_args, allow_null)
+#endif
+
+#ifndef IS_VOID
+#define IS_VOID 99
+#endif
+
+#ifndef IS_MIXED
+#define IS_MIXED 99
+#endif
+
+#ifndef _IS_BOOL
+#define _IS_BOOL 99
+#endif
+
+#ifndef IS_LONG
+#define IS_LONG 99
 #endif
 
 ZEND_BEGIN_ARG_INFO(arginfo_void, 0)
diff --git a/php/src/Google/Protobuf/Internal/GPBUtil.php b/php/src/Google/Protobuf/Internal/GPBUtil.php
index 1dd6645..b71246e 100644
--- a/php/src/Google/Protobuf/Internal/GPBUtil.php
+++ b/php/src/Google/Protobuf/Internal/GPBUtil.php
@@ -37,6 +37,7 @@
 use Google\Protobuf\Internal\GPBType;
 use Google\Protobuf\Internal\RepeatedField;
 use Google\Protobuf\Internal\MapField;
+use function bccomp;
 
 function camel2underscore($input) {
     preg_match_all(
diff --git a/php/src/Google/Protobuf/Internal/GPBWire.php b/php/src/Google/Protobuf/Internal/GPBWire.php
index 2956953..034f5df 100644
--- a/php/src/Google/Protobuf/Internal/GPBWire.php
+++ b/php/src/Google/Protobuf/Internal/GPBWire.php
@@ -146,7 +146,7 @@
                 return bcsub(bcmul(bcsub(0, $int64), 2), 1);
             }
         } else {
-            return ($int64 << 1) ^ ($int64 >> 63);
+            return ((int)$int64 << 1) ^ ((int)$int64 >> 63);
         }
     }
 
diff --git a/php/src/Google/Protobuf/Internal/MapField.php b/php/src/Google/Protobuf/Internal/MapField.php
index 719fb35..86463a9 100644
--- a/php/src/Google/Protobuf/Internal/MapField.php
+++ b/php/src/Google/Protobuf/Internal/MapField.php
@@ -37,6 +37,8 @@
 
 namespace Google\Protobuf\Internal;
 
+use Traversable;
+
 /**
  * MapField is used by generated protocol message classes to manipulate map
  * fields. It can be used like native PHP array.
@@ -134,6 +136,7 @@
      * @throws \ErrorException Invalid type for index.
      * @throws \ErrorException Non-existing index.
      */
+    #[\ReturnTypeWillChange]
     public function offsetGet($key)
     {
         return $this->container[$key];
@@ -151,6 +154,7 @@
      * @throws \ErrorException Invalid type for value.
      * @throws \ErrorException Non-existing key.
      */
+    #[\ReturnTypeWillChange]
     public function offsetSet($key, $value)
     {
         $this->checkKey($this->key_type, $key);
@@ -209,6 +213,7 @@
      * @return void
      * @throws \ErrorException Invalid type for key.
      */
+    #[\ReturnTypeWillChange]
     public function offsetUnset($key)
     {
         $this->checkKey($this->key_type, $key);
@@ -224,7 +229,7 @@
      * @return bool True if the element at the given key exists.
      * @throws \ErrorException Invalid type for key.
      */
-    public function offsetExists($key)
+    public function offsetExists($key): bool
     {
         $this->checkKey($this->key_type, $key);
         return isset($this->container[$key]);
@@ -233,7 +238,7 @@
     /**
      * @ignore
      */
-    public function getIterator()
+    public function getIterator(): Traversable
     {
         return new MapFieldIter($this->container, $this->key_type);
     }
@@ -245,7 +250,7 @@
      *
      * @return integer The number of stored elements.
      */
-    public function count()
+    public function count(): int
     {
         return count($this->container);
     }
diff --git a/php/src/Google/Protobuf/Internal/MapFieldIter.php b/php/src/Google/Protobuf/Internal/MapFieldIter.php
index 4e18005..a3c834b 100644
--- a/php/src/Google/Protobuf/Internal/MapFieldIter.php
+++ b/php/src/Google/Protobuf/Internal/MapFieldIter.php
@@ -68,9 +68,10 @@
      *
      * @return void
      */
+    #[\ReturnTypeWillChange]
     public function rewind()
     {
-        return reset($this->container);
+        reset($this->container);
     }
 
     /**
@@ -78,6 +79,7 @@
      *
      * @return object The element at the current position.
      */
+    #[\ReturnTypeWillChange]
     public function current()
     {
         return current($this->container);
@@ -88,6 +90,7 @@
      *
      * @return object The current key.
      */
+    #[\ReturnTypeWillChange]
     public function key()
     {
         $key = key($this->container);
@@ -117,9 +120,10 @@
      *
      * @return void
      */
+    #[\ReturnTypeWillChange]
     public function next()
     {
-        return next($this->container);
+        next($this->container);
     }
 
     /**
@@ -127,7 +131,7 @@
      *
      * @return bool True if there are more elements to iterate.
      */
-    public function valid()
+    public function valid(): bool
     {
         return key($this->container) !== null;
     }
diff --git a/php/src/Google/Protobuf/Internal/RepeatedField.php b/php/src/Google/Protobuf/Internal/RepeatedField.php
index c0331ff..704123a 100644
--- a/php/src/Google/Protobuf/Internal/RepeatedField.php
+++ b/php/src/Google/Protobuf/Internal/RepeatedField.php
@@ -39,6 +39,7 @@
 
 use Google\Protobuf\Internal\GPBType;
 use Google\Protobuf\Internal\GPBUtil;
+use Traversable;
 
 /**
  * RepeatedField is used by generated protocol message classes to manipulate
@@ -121,6 +122,7 @@
      * @throws \ErrorException Invalid type for index.
      * @throws \ErrorException Non-existing index.
      */
+    #[\ReturnTypeWillChange]
     public function offsetGet($offset)
     {
         return $this->container[$offset];
@@ -138,6 +140,7 @@
      * @throws \ErrorException Non-existing index.
      * @throws \ErrorException Incorrect type of the element.
      */
+    #[\ReturnTypeWillChange]
     public function offsetSet($offset, $value)
     {
         switch ($this->type) {
@@ -209,6 +212,7 @@
      * @throws \ErrorException The element to be removed is not at the end of the
      * RepeatedField.
      */
+    #[\ReturnTypeWillChange]
     public function offsetUnset($offset)
     {
         $count = count($this->container);
@@ -230,7 +234,7 @@
      * @return bool True if the element at the given offset exists.
      * @throws \ErrorException Invalid type for index.
      */
-    public function offsetExists($offset)
+    public function offsetExists($offset): bool
     {
         return isset($this->container[$offset]);
     }
@@ -238,7 +242,7 @@
     /**
      * @ignore
      */
-    public function getIterator()
+    public function getIterator(): Traversable
     {
         return new RepeatedFieldIter($this->container);
     }
@@ -250,7 +254,7 @@
      *
      * @return integer The number of stored elements.
      */
-    public function count()
+    public function count(): int
     {
         return count($this->container);
     }
diff --git a/php/src/Google/Protobuf/Internal/RepeatedFieldIter.php b/php/src/Google/Protobuf/Internal/RepeatedFieldIter.php
index 2b6f823..3c85869 100644
--- a/php/src/Google/Protobuf/Internal/RepeatedFieldIter.php
+++ b/php/src/Google/Protobuf/Internal/RepeatedFieldIter.php
@@ -71,6 +71,7 @@
      *
      * @return void
      */
+    #[\ReturnTypeWillChange]
     public function rewind()
     {
         $this->position = 0;
@@ -81,6 +82,7 @@
      *
      * @return object The element at the current position.
      */
+    #[\ReturnTypeWillChange]
     public function current()
     {
         return $this->container[$this->position];
@@ -91,6 +93,7 @@
      *
      * @return integer The current position.
      */
+    #[\ReturnTypeWillChange]
     public function key()
     {
         return $this->position;
@@ -101,6 +104,7 @@
      *
      * @return void
      */
+    #[\ReturnTypeWillChange]
     public function next()
     {
         ++$this->position;
@@ -111,7 +115,7 @@
      *
      * @return bool True if there are more elements to iterate.
      */
-    public function valid()
+    public function valid(): bool
     {
         return isset($this->container[$this->position]);
     }
diff --git a/tests.sh b/tests.sh
index 290f110..13bf034 100755
--- a/tests.sh
+++ b/tests.sh
@@ -496,6 +496,8 @@
   use_php $1
   pushd php
   rm -rf vendor
+  php -v
+  php -m
   composer update
   composer test
   popd
@@ -505,6 +507,8 @@
 test_php_c() {
   pushd php
   rm -rf vendor
+  php -v
+  php -m
   composer update
   composer test_c
   popd
@@ -572,7 +576,9 @@
 
 build_php8.0_all() {
   build_php 8.0
+  build_php 8.1
   build_php_c 8.0
+  build_php_c 8.1
 }
 
 build_php_all_32() {