From 707a9fd24a0d3bca3f2a81dd5331c230543fb3d3 Mon Sep 17 00:00:00 2001 From: Brent Shaffer Date: Tue, 6 Oct 2026 21:29:20 +0000 Subject: [PATCH 1/5] fix: resolve dynamic property deprecations --- src/Ast/HasAccess.php | 2 ++ src/Generation/MethodDetails.php | 5 ++++- src/Utils/ProtoAugmenter.php | 6 ------ src/Utils/ProtoHelpers.php | 25 ++++++------------------- tests/Unit/Collections/MapTest.php | 3 +-- 5 files changed, 13 insertions(+), 28 deletions(-) diff --git a/src/Ast/HasAccess.php b/src/Ast/HasAccess.php index 13c109b04..61cd5d1ae 100644 --- a/src/Ast/HasAccess.php +++ b/src/Ast/HasAccess.php @@ -29,6 +29,8 @@ class Access trait HasAccess { + private Vector $access; + /** * Create a version of this ast element with access modifiers. * diff --git a/src/Generation/MethodDetails.php b/src/Generation/MethodDetails.php index 828ac534e..4b74f66ac 100644 --- a/src/Generation/MethodDetails.php +++ b/src/Generation/MethodDetails.php @@ -243,7 +243,10 @@ public function __construct($svc, $desc, $outputMsg, $pageSize, $pageToken, $nex $this->resourcesSetter = AST::method($resources->getSetter()); $this->resourceType = Type::fromField($svc->catalog, $resources, false); $this->resourcesFieldName = Helpers::toCamelCase($resources->getName()); - $this->resourcesField = new FieldDetails($svc->catalog, $outputMsg, $resources->underlyingProto); + $resourcesProto = Vector::new($outputMsg->getField()) + ->filter(fn ($f) => $f->desc === $resources) + ->firstOrNull(); + $this->resourcesField = new FieldDetails($svc->catalog, $outputMsg, $resourcesProto); $this->methodReturnType = Type::fromName(PagedListResponse::class); // Override docs for page_size and page_token fields. $this->requiredFields = $this->overrideFieldDocs($svc->catalog, $outputMsg, $this->requiredFields); diff --git a/src/Utils/ProtoAugmenter.php b/src/Utils/ProtoAugmenter.php index 63f7fc278..aac76cdc8 100644 --- a/src/Utils/ProtoAugmenter.php +++ b/src/Utils/ProtoAugmenter.php @@ -76,9 +76,7 @@ private static function augmentFile(FileDescriptorProto $fileProto) $fnMergeEnums = function (Vector $path, int $pathId, $proto, $desc) use ($locsByPath, $fnLeadingComments) { $enums = Vector::zip(Vector::new($proto->getEnumType()), Vector::new($desc->getEnumType())); foreach ($enums as $enumIndex => [$enumProto, $enumDesc]) { - // Link proto and desc in both directions. $enumProto->desc = $enumDesc; - $enumDesc->underlyingProto = $enumProto; // Link proto comments. $enumPath = $path->concat(Vector::new([$pathId, $enumIndex])); $enumLocations = $locsByPath->get($enumPath, null); @@ -88,9 +86,7 @@ private static function augmentFile(FileDescriptorProto $fileProto) $fnMergeMsgs = null; $fnMergeMsgs = function (Vector $msgPath, DescriptorProto $msgProto, Descriptor $msgDesc) use (&$fnMergeMsgs, $locsByPath, $fnLeadingComments, $fnTrailingComments, $fnMergeEnums) { - // Link proto and desc in both directions. $msgProto->desc = $msgDesc; - $msgDesc->underlyingProto = $msgProto; // Link proto comments. $msgLocations = $locsByPath->get($msgPath, null); $msgProto->leadingComments = static::getComments($msgLocations, $fnLeadingComments); @@ -103,9 +99,7 @@ private static function augmentFile(FileDescriptorProto $fileProto) // Handle fields: $fields = Vector::zip(Vector::new($msgProto->getField()), Vector::new($msgDesc->getField())); foreach ($fields as $fieldIndex => [$fieldProto, $fieldDesc]) { - // Link proto and desc in both directions. $fieldProto->desc = $fieldDesc; - $fieldDesc->underlyingProto = $fieldProto; // Link proto comments. $fieldPath = $msgPath->concat(Vector::new([static::MESSAGE_FIELD, $fieldIndex])); $fieldLocations = $locsByPath->get($fieldPath, null); diff --git a/src/Utils/ProtoHelpers.php b/src/Utils/ProtoHelpers.php index 1dc815c68..556f460d2 100644 --- a/src/Utils/ProtoHelpers.php +++ b/src/Utils/ProtoHelpers.php @@ -388,30 +388,18 @@ private static function getCustomOptionRaw(Message $message, int $optionId, bool return $repeated ? Vector::new($values) : null; } - private static function conformMessage($message): Message - { - if (isset($message->underlyingProto)) { - $message = $message->underlyingProto; - } - if (!($message instanceof Message)) { - throw new Exception('Can only get custom option of Message or HasPublicDescriptorTrait'); - } - return $message; - } - /** * Get a non-repeated custom option. The option can be of any type, which determines the return type. * - * @param mixed $message The message containing the custom option. Must be of type Message, or - * a descriptor with an `underlyingProto` property. + * @param Message $message The message containing the custom option. * @param int $optionId The option-id of the option to get. * @param ?string $msgClass Optional; to return a proto msg, set this to the PHP class of the msg. * * @return mixed Will be null if the option does not exist. */ - public static function getCustomOption($message, int $optionId, ?string $msgClass = null) + public static function getCustomOption(Message $message, int $optionId, ?string $msgClass = null) { - $result = static::getCustomOptionRaw(static::conformMessage($message), $optionId, false); + $result = static::getCustomOptionRaw($message, $optionId, false); if (!is_null($msgClass) && !is_null($result)) { $msg = new $msgClass(); $msg->mergeFromString($result); @@ -423,15 +411,14 @@ public static function getCustomOption($message, int $optionId, ?string $msgClas /** * Get a repeated custom option. The option can be of any type, which determines to content of the returned Vector. * - * @param mixed $message The message containing the custom option. Must be of type Message, or - * a descriptor with an `underlyingProto` property. + * @param Message $message The message containing the custom option. * @param int $optionId The option-id of the option to get. * * @return Vector Will be an empty Vector if the option does not exist. */ - public static function getCustomOptionRepeated($message, int $optionId, ?string $msgClass = null): Vector + public static function getCustomOptionRepeated(Message $message, int $optionId, ?string $msgClass = null): Vector { - $result = static::getCustomOptionRaw(static::conformMessage($message), $optionId, true); + $result = static::getCustomOptionRaw($message, $optionId, true); if (!is_null($msgClass)) { $result = $result->map(function ($x) use ($msgClass) { $msg = new $msgClass(); diff --git a/tests/Unit/Collections/MapTest.php b/tests/Unit/Collections/MapTest.php index 0d3292c49..5443b2242 100644 --- a/tests/Unit/Collections/MapTest.php +++ b/tests/Unit/Collections/MapTest.php @@ -28,9 +28,8 @@ class Obj class ObjEq implements Equality { - public function __construct($id) + public function __construct(private $id) { - $this->id = $id; } public function getHash(): int From 28fecad8c129985bdfe1a4283981601c79bf9223 Mon Sep 17 00:00:00 2001 From: Brent Shaffer Date: Tue, 6 Oct 2026 22:19:26 +0000 Subject: [PATCH 2/5] test: fail PHPUnit on deprecation warnings --- phpunit.xml.dist | 2 ++ tests/Unit/PostProcessor/FragmentInjectionProcessorTest.php | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/phpunit.xml.dist b/phpunit.xml.dist index cd920d048..3ad398ded 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -3,6 +3,7 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" bootstrap="tests/Unit/autoload.php" colors="true" + convertDeprecationsToExceptions="true" xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.3/phpunit.xsd" > @@ -17,6 +18,7 @@ + diff --git a/tests/Unit/PostProcessor/FragmentInjectionProcessorTest.php b/tests/Unit/PostProcessor/FragmentInjectionProcessorTest.php index dc26aec97..24480519f 100644 --- a/tests/Unit/PostProcessor/FragmentInjectionProcessorTest.php +++ b/tests/Unit/PostProcessor/FragmentInjectionProcessorTest.php @@ -66,7 +66,7 @@ class Bar * @runInSeparateProcess * @dataProvider provideAstMethodReplacer */ - public function testAstMethodReplacer(string $classContents, string $insertBeforeMethod = null) + public function testAstMethodReplacer(string $classContents, ?string $insertBeforeMethod = null) { // the class / method to insert into // if no method is defined, the first method is used ("__construct" in this case) From 1ee31a57bc5243cd2cf3d830505693451dd85c9e Mon Sep 17 00:00:00 2001 From: Brent Shaffer Date: Tue, 6 Oct 2026 23:18:07 +0000 Subject: [PATCH 3/5] test: drop error_reporting override from phpunit.xml.dist --- phpunit.xml.dist | 1 - 1 file changed, 1 deletion(-) diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 3ad398ded..a9b9ceb01 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -18,7 +18,6 @@ - From 27373b1323ab09eed01a67e8f641d4ae8577aa52 Mon Sep 17 00:00:00 2001 From: Brent Shaffer Date: Mon, 12 Oct 2026 21:27:04 +0000 Subject: [PATCH 4/5] fix: resolve PHP 8.5 float-to-int cast warning and ReflectionProperty::setAccessible deprecation --- src/Collections/Vector.php | 3 +-- src/Utils/ProtoHelpers.php | 1 - 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Collections/Vector.php b/src/Collections/Vector.php index 70f7d7006..3c9706e99 100644 --- a/src/Collections/Vector.php +++ b/src/Collections/Vector.php @@ -145,8 +145,7 @@ public function getHash(): int { $hash = 1; foreach ($this->data as $item) { - $hash = (int) ($hash * 13); - $hash ^= static::hash($item); + $hash = (($hash & 0x07ffffff) * 13) ^ static::hash($item); } return $hash; } diff --git a/src/Utils/ProtoHelpers.php b/src/Utils/ProtoHelpers.php index 556f460d2..4119f9d7f 100644 --- a/src/Utils/ProtoHelpers.php +++ b/src/Utils/ProtoHelpers.php @@ -348,7 +348,6 @@ private static function getCustomOptionRaw(Message $message, int $optionId, bool if (!$messageUnknown) { $ref = new \ReflectionClass('Google\Protobuf\Internal\Message'); $messageUnknown = $ref->getProperty('unknown'); - $messageUnknown->setAccessible(true); } $values = []; From 1005a16ef8a441ae71b29b205702dc0dd2aed2c9 Mon Sep 17 00:00:00 2001 From: Brent Shaffer Date: Mon, 12 Oct 2026 21:38:11 +0000 Subject: [PATCH 5/5] chore: use intdiv(PHP_INT_MAX, 13) in Vector::getHash() --- src/Collections/Vector.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Collections/Vector.php b/src/Collections/Vector.php index 3c9706e99..f3efaeb63 100644 --- a/src/Collections/Vector.php +++ b/src/Collections/Vector.php @@ -145,7 +145,8 @@ public function getHash(): int { $hash = 1; foreach ($this->data as $item) { - $hash = (($hash & 0x07ffffff) * 13) ^ static::hash($item); + // Modulo before multiplying so $hash * 13 never overflows PHP_INT_MAX into a float. + $hash = (($hash % intdiv(PHP_INT_MAX, 13)) * 13) ^ static::hash($item); } return $hash; }