Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions php/ext/google/protobuf/convert.c
Original file line number Diff line number Diff line change
Expand Up @@ -69,11 +69,30 @@ PHP_METHOD(Util, checkRepeatedField) {
RETURN_COPY(val);
}

PHP_METHOD(Util, compatibleInt64) {
zend_long int_val;
char *str_val;
size_t str_len;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "ls", &int_val, &str_val, &str_len) == FAILURE) {
return;
}
#if SIZEOF_ZEND_LONG == 8
RETURN_LONG(int_val);
#else
RETURN_STRINGL(str_val, str_len);
#endif
}

// clang-format off
ZEND_BEGIN_ARG_INFO_EX(arginfo_checkPrimitive, 0, 0, 1)
ZEND_ARG_INFO(0, value)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO_EX(arginfo_compatibleInt64, 0, 0, 2)
ZEND_ARG_INFO(0, int_val)
ZEND_ARG_INFO(0, str_val)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO_EX(arginfo_checkString, 0, 0, 1)
ZEND_ARG_INFO(0, value)
ZEND_ARG_INFO(0, check_utf8)
Expand Down Expand Up @@ -124,6 +143,8 @@ static zend_function_entry util_methods[] = {
ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
PHP_ME(Util, checkRepeatedField, arginfo_checkRepeatedField,
ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
PHP_ME(Util, compatibleInt64, arginfo_compatibleInt64,
ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
ZEND_FE_END
};
// clang-format on
Expand Down
5 changes: 5 additions & 0 deletions php/src/Google/Protobuf/Internal/GPBUtil.php
Original file line number Diff line number Diff line change
Expand Up @@ -641,4 +641,9 @@ public static function hasJsonValue($msg)
is_a($msg, "Google\Protobuf\StringValue") ||
is_a($msg, "Google\Protobuf\BytesValue");
}

public static function compatibleInt64($int64, $stringInt64)
{
return PHP_INT_SIZE === 4 ? $stringInt64 : $int64;
}
}
3 changes: 2 additions & 1 deletion php/src/Google/Protobuf/Internal/Message.php
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ private function initWithGeneratedPool()
}
foreach ($this->desc->getField() as $field) {
$setter = $field->getSetter();
$getter = $field->getGetter();
if ($field->isMap()) {
$message_type = $field->getMessageType();
$key_field = $message_type->getFieldByNumber(1);
Expand Down Expand Up @@ -129,7 +130,7 @@ private function initWithGeneratedPool()
$oneof_name = $oneof->getName();
$this->$oneof_name = new OneofField($oneof);
} else if (!$field->isRequired() && !$field->isRepeated() &&
PHP_INT_SIZE == 4) {
PHP_INT_SIZE == 4 && $this->$getter() === 0) {
switch ($field->getType()) {
case GPBType::INT64:
case GPBType::UINT64:
Expand Down
33 changes: 33 additions & 0 deletions php/tests/DefaultValueTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?php

require_once('test_base.php');

use Default_value\TestDefaultValue;
use Default_value\TestEnum;

class DefaultValueTest extends TestBase
{
public function testDefaultValues()
{
$message = new TestDefaultValue();

$this->assertSame(1, $message->getOptionalInt32());
if (PHP_INT_SIZE == 4) {
$this->assertSame('2', $message->getOptionalInt64());
} else {
$this->assertSame(2, $message->getOptionalInt64());
}
$this->assertSame(3, $message->getOptionalUint32());
if (PHP_INT_SIZE == 4) {
$this->assertSame('4', $message->getOptionalUint64());
} else {
$this->assertSame(4, $message->getOptionalUint64());
}
$this->assertSame(5.5, $message->getOptionalFloat());
$this->assertSame(6.6, $message->getOptionalDouble());
$this->assertSame(true, $message->getOptionalBool());
$this->assertSame("hello", $message->getOptionalString());
$this->assertSame("world", $message->getOptionalBytes());
$this->assertSame(TestEnum::HELLO, $message->getOptionalEnum());
}
}
22 changes: 22 additions & 0 deletions php/tests/proto/test_default_value.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
edition = "2023";

package default_value;

message TestDefaultValue {
int32 optional_int32 = 1 [default = 1];
int64 optional_int64 = 2 [default = 2];
uint32 optional_uint32 = 3 [default = 3];
uint64 optional_uint64 = 4 [default = 4];
float optional_float = 5 [default = 5.5];
double optional_double = 6 [default = 6.6];
bool optional_bool = 7 [default = true];
string optional_string = 8 [default = "hello"];
bytes optional_bytes = 9 [default = "world"];
TestEnum optional_enum = 10 [default = HELLO];
}

enum TestEnum {
DEFAULT = 0;
HELLO = 1;
WORLD = 2;
}
61 changes: 60 additions & 1 deletion src/google/protobuf/compiler/php/php_generator.cc
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,65 @@ std::string DefaultForField(const FieldDescriptor* field) {
}
}

std::string DefaultForFieldWithPresence(const FieldDescriptor* field) {
if (field->has_default_value()) {
switch (field->cpp_type()) {
case FieldDescriptor::CPPTYPE_INT32:
return absl::StrCat(field->default_value_int32());
case FieldDescriptor::CPPTYPE_INT64:
return "GPBUtil::compatibleInt64(" + absl::StrCat(field->default_value_int64())
+ ", '" + absl::StrCat(field->default_value_int64()) + "')";
case FieldDescriptor::CPPTYPE_UINT32:
return absl::StrCat(field->default_value_uint32());
case FieldDescriptor::CPPTYPE_UINT64:
return "GPBUtil::compatibleInt64(" + absl::StrCat(field->default_value_uint64())
+ ", '" + absl::StrCat(field->default_value_uint64()) + "')";
case FieldDescriptor::CPPTYPE_FLOAT:
return absl::StrCat(field->default_value_float());
case FieldDescriptor::CPPTYPE_DOUBLE:
return absl::StrCat(field->default_value_double());
case FieldDescriptor::CPPTYPE_BOOL:
return field->default_value_bool() ? "true" : "false";
case FieldDescriptor::CPPTYPE_ENUM:
return absl::StrCat(field->default_value_enum()->number());
case FieldDescriptor::CPPTYPE_STRING:
return "'" + absl::CEscape(field->default_value_string()) + "'";
case FieldDescriptor::CPPTYPE_MESSAGE:
return "null";
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be unreachable, might as well ABSL_CHECK

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Something like this?

Suggested change
return "null";
ABSL_CHECK(false) << "Message fields cannot have default values.";
return "null";

}
}

switch (field->type()) {
case FieldDescriptor::TYPE_INT64:
case FieldDescriptor::TYPE_UINT64:
case FieldDescriptor::TYPE_SINT64:
case FieldDescriptor::TYPE_FIXED64:
case FieldDescriptor::TYPE_SFIXED64:
return "GPBUtil::compatibleInt64(0, '0')";
case FieldDescriptor::TYPE_INT32:
case FieldDescriptor::TYPE_UINT32:
case FieldDescriptor::TYPE_SINT32:
case FieldDescriptor::TYPE_FIXED32:
case FieldDescriptor::TYPE_SFIXED32:
case FieldDescriptor::TYPE_ENUM:
return "0";
case FieldDescriptor::TYPE_DOUBLE:
case FieldDescriptor::TYPE_FLOAT:
return "0.0";
case FieldDescriptor::TYPE_BOOL:
return "false";
case FieldDescriptor::TYPE_STRING:
case FieldDescriptor::TYPE_BYTES:
return "''";
case FieldDescriptor::TYPE_MESSAGE:
case FieldDescriptor::TYPE_GROUP:
return "null";
default:
assert(false);
return "";
}
}

std::string DeprecatedConditionalForField(const FieldDescriptor* field) {
if (field->is_repeated()) {
return absl::StrCat("count($this->", field->name(), ") !== 0");
Expand Down Expand Up @@ -623,7 +682,7 @@ void GenerateFieldAccessor(const FieldDescriptor* field, const Options& options,
": ^default_value^;\n"
"}\n\n",
"camel_name", UnderscoresToCamelCase(field->name(), true), "name",
field->name(), "default_value", DefaultForField(field),
field->name(), "default_value", DefaultForFieldWithPresence(field),
"deprecation_trigger", deprecation_trigger_with_conditional);
} else {
printer->Print(
Expand Down
3 changes: 2 additions & 1 deletion src/google/protobuf/compiler/php/php_generator.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,8 @@ class PROTOC_EXPORT Generator : public CodeGenerator {
std::string* error) const override;

uint64_t GetSupportedFeatures() const override {
return Feature::FEATURE_PROTO3_OPTIONAL;
return Feature::FEATURE_PROTO3_OPTIONAL |
Feature::FEATURE_SUPPORTS_EDITIONS;
}

Edition GetMinimumEdition() const override { return Edition::EDITION_PROTO2; }
Expand Down
Loading