Skip to content

Commit b01099d

Browse files
bshaffercopybara-github
authored andcommitted
feat(php): support default values for editions/proto2 (#25161)
b/435022198 Closes #25161 COPYBARA_INTEGRATE_REVIEW=#25161 from bshaffer:php-fix-ignored-default-fields 16706c0 PiperOrigin-RevId: 853479507
1 parent 71cc97c commit b01099d

File tree

7 files changed

+148
-3
lines changed

7 files changed

+148
-3
lines changed

php/ext/google/protobuf/convert.c

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,11 +69,31 @@ PHP_METHOD(Util, checkRepeatedField) {
6969
RETURN_COPY(val);
7070
}
7171

72+
PHP_METHOD(Util, compatibleInt64) {
73+
zend_long int_val;
74+
char* str_val;
75+
size_t str_len;
76+
if (zend_parse_parameters(ZEND_NUM_ARGS(), "ls", &int_val, &str_val,
77+
&str_len) == FAILURE) {
78+
return;
79+
}
80+
#if SIZEOF_ZEND_LONG == 8
81+
RETURN_LONG(int_val);
82+
#else
83+
RETURN_STRINGL(str_val, str_len);
84+
#endif
85+
}
86+
7287
// clang-format off
7388
ZEND_BEGIN_ARG_INFO_EX(arginfo_checkPrimitive, 0, 0, 1)
7489
ZEND_ARG_INFO(0, value)
7590
ZEND_END_ARG_INFO()
7691

92+
ZEND_BEGIN_ARG_INFO_EX(arginfo_compatibleInt64, 0, 0, 2)
93+
ZEND_ARG_INFO(0, int_val)
94+
ZEND_ARG_INFO(0, str_val)
95+
ZEND_END_ARG_INFO()
96+
7797
ZEND_BEGIN_ARG_INFO_EX(arginfo_checkString, 0, 0, 1)
7898
ZEND_ARG_INFO(0, value)
7999
ZEND_ARG_INFO(0, check_utf8)
@@ -124,6 +144,8 @@ static zend_function_entry util_methods[] = {
124144
ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
125145
PHP_ME(Util, checkRepeatedField, arginfo_checkRepeatedField,
126146
ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
147+
PHP_ME(Util, compatibleInt64, arginfo_compatibleInt64,
148+
ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
127149
ZEND_FE_END
128150
};
129151
// clang-format on

php/src/Google/Protobuf/Internal/GPBUtil.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -641,4 +641,9 @@ public static function hasJsonValue($msg)
641641
is_a($msg, "Google\Protobuf\StringValue") ||
642642
is_a($msg, "Google\Protobuf\BytesValue");
643643
}
644+
645+
public static function compatibleInt64($int64, $stringInt64)
646+
{
647+
return PHP_INT_SIZE === 4 ? $stringInt64 : $int64;
648+
}
644649
}

php/src/Google/Protobuf/Internal/Message.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ private function initWithGeneratedPool()
7777
}
7878
foreach ($this->desc->getField() as $field) {
7979
$setter = $field->getSetter();
80+
$getter = $field->getGetter();
8081
if ($field->isMap()) {
8182
$message_type = $field->getMessageType();
8283
$key_field = $message_type->getFieldByNumber(1);
@@ -129,7 +130,7 @@ private function initWithGeneratedPool()
129130
$oneof_name = $oneof->getName();
130131
$this->$oneof_name = new OneofField($oneof);
131132
} else if (!$field->isRequired() && !$field->isRepeated() &&
132-
PHP_INT_SIZE == 4) {
133+
PHP_INT_SIZE == 4 && $this->$getter() === 0) {
133134
switch ($field->getType()) {
134135
case GPBType::INT64:
135136
case GPBType::UINT64:

php/tests/DefaultValueTest.php

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
<?php
2+
3+
require_once('test_base.php');
4+
5+
use Default_value\TestDefaultValue;
6+
use Default_value\TestEnum;
7+
8+
class DefaultValueTest extends TestBase
9+
{
10+
public function testDefaultValues()
11+
{
12+
$message = new TestDefaultValue();
13+
14+
$this->assertSame(1, $message->getOptionalInt32());
15+
if (PHP_INT_SIZE == 4) {
16+
$this->assertSame('2', $message->getOptionalInt64());
17+
} else {
18+
$this->assertSame(2, $message->getOptionalInt64());
19+
}
20+
$this->assertSame(3, $message->getOptionalUint32());
21+
if (PHP_INT_SIZE == 4) {
22+
$this->assertSame('4', $message->getOptionalUint64());
23+
} else {
24+
$this->assertSame(4, $message->getOptionalUint64());
25+
}
26+
$this->assertSame(5.5, $message->getOptionalFloat());
27+
$this->assertSame(6.6, $message->getOptionalDouble());
28+
$this->assertSame(true, $message->getOptionalBool());
29+
$this->assertSame("hello", $message->getOptionalString());
30+
$this->assertSame("world", $message->getOptionalBytes());
31+
$this->assertSame(TestEnum::HELLO, $message->getOptionalEnum());
32+
}
33+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
edition = "2023";
2+
3+
package default_value;
4+
5+
message TestDefaultValue {
6+
int32 optional_int32 = 1 [default = 1];
7+
int64 optional_int64 = 2 [default = 2];
8+
uint32 optional_uint32 = 3 [default = 3];
9+
uint64 optional_uint64 = 4 [default = 4];
10+
float optional_float = 5 [default = 5.5];
11+
double optional_double = 6 [default = 6.6];
12+
bool optional_bool = 7 [default = true];
13+
string optional_string = 8 [default = "hello"];
14+
bytes optional_bytes = 9 [default = "world"];
15+
TestEnum optional_enum = 10 [default = HELLO];
16+
}
17+
18+
enum TestEnum {
19+
DEFAULT = 0;
20+
HELLO = 1;
21+
WORLD = 2;
22+
}

src/google/protobuf/compiler/php/php_generator.cc

Lines changed: 62 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,67 @@ std::string DefaultForField(const FieldDescriptor* field) {
219219
}
220220
}
221221

222+
std::string DefaultForFieldWithPresence(const FieldDescriptor* field) {
223+
if (field->has_default_value()) {
224+
switch (field->cpp_type()) {
225+
case FieldDescriptor::CPPTYPE_INT32:
226+
return absl::StrCat(field->default_value_int32());
227+
case FieldDescriptor::CPPTYPE_INT64:
228+
return "GPBUtil::compatibleInt64(" +
229+
absl::StrCat(field->default_value_int64()) + ", '" +
230+
absl::StrCat(field->default_value_int64()) + "')";
231+
case FieldDescriptor::CPPTYPE_UINT32:
232+
return absl::StrCat(field->default_value_uint32());
233+
case FieldDescriptor::CPPTYPE_UINT64:
234+
return "GPBUtil::compatibleInt64(" +
235+
absl::StrCat(field->default_value_uint64()) + ", '" +
236+
absl::StrCat(field->default_value_uint64()) + "')";
237+
case FieldDescriptor::CPPTYPE_FLOAT:
238+
return absl::StrCat(field->default_value_float());
239+
case FieldDescriptor::CPPTYPE_DOUBLE:
240+
return absl::StrCat(field->default_value_double());
241+
case FieldDescriptor::CPPTYPE_BOOL:
242+
return field->default_value_bool() ? "true" : "false";
243+
case FieldDescriptor::CPPTYPE_ENUM:
244+
return absl::StrCat(field->default_value_enum()->number());
245+
case FieldDescriptor::CPPTYPE_STRING:
246+
return "'" + absl::CEscape(field->default_value_string()) + "'";
247+
case FieldDescriptor::CPPTYPE_MESSAGE:
248+
return "null";
249+
}
250+
}
251+
252+
switch (field->type()) {
253+
case FieldDescriptor::TYPE_INT64:
254+
case FieldDescriptor::TYPE_UINT64:
255+
case FieldDescriptor::TYPE_SINT64:
256+
case FieldDescriptor::TYPE_FIXED64:
257+
case FieldDescriptor::TYPE_SFIXED64:
258+
return "GPBUtil::compatibleInt64(0, '0')";
259+
case FieldDescriptor::TYPE_INT32:
260+
case FieldDescriptor::TYPE_UINT32:
261+
case FieldDescriptor::TYPE_SINT32:
262+
case FieldDescriptor::TYPE_FIXED32:
263+
case FieldDescriptor::TYPE_SFIXED32:
264+
case FieldDescriptor::TYPE_ENUM:
265+
return "0";
266+
case FieldDescriptor::TYPE_DOUBLE:
267+
case FieldDescriptor::TYPE_FLOAT:
268+
return "0.0";
269+
case FieldDescriptor::TYPE_BOOL:
270+
return "false";
271+
case FieldDescriptor::TYPE_STRING:
272+
case FieldDescriptor::TYPE_BYTES:
273+
return "''";
274+
case FieldDescriptor::TYPE_MESSAGE:
275+
case FieldDescriptor::TYPE_GROUP:
276+
return "null";
277+
default:
278+
assert(false);
279+
return "";
280+
}
281+
}
282+
222283
std::string DeprecatedConditionalForField(const FieldDescriptor* field) {
223284
if (field->is_repeated()) {
224285
return absl::StrCat("count($this->", field->name(), ") !== 0");
@@ -623,7 +684,7 @@ void GenerateFieldAccessor(const FieldDescriptor* field, const Options& options,
623684
": ^default_value^;\n"
624685
"}\n\n",
625686
"camel_name", UnderscoresToCamelCase(field->name(), true), "name",
626-
field->name(), "default_value", DefaultForField(field),
687+
field->name(), "default_value", DefaultForFieldWithPresence(field),
627688
"deprecation_trigger", deprecation_trigger_with_conditional);
628689
} else {
629690
printer->Print(

src/google/protobuf/compiler/php/php_generator.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,8 @@ class PROTOC_EXPORT Generator : public CodeGenerator {
3535
std::string* error) const override;
3636

3737
uint64_t GetSupportedFeatures() const override {
38-
return Feature::FEATURE_PROTO3_OPTIONAL;
38+
return Feature::FEATURE_PROTO3_OPTIONAL |
39+
Feature::FEATURE_SUPPORTS_EDITIONS;
3940
}
4041

4142
Edition GetMinimumEdition() const override { return Edition::EDITION_PROTO2; }

0 commit comments

Comments
 (0)