Skip to content

Commit 6d8bc74

Browse files
SpencerMalonesmalone1
authored andcommitted
Add option for PHP to emit default values.
1 parent 6643af3 commit 6d8bc74

File tree

6 files changed

+303
-38
lines changed

6 files changed

+303
-38
lines changed

php/ext/google/protobuf/message.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -773,6 +773,9 @@ PHP_METHOD(Message, serializeToJsonString) {
773773
if (Z_LVAL_P(flags) & PRESERVE_PROTO_FIELD_NAMES) {
774774
options |= upb_JsonEncode_UseProtoNames;
775775
}
776+
if (Z_LVAL_P(flags) & EMIT_DEFAULTS) {
777+
options |= upb_JsonEncode_EmitDefaults;
778+
}
776779
}
777780

778781
upb_Status_Clear(&status);

php/ext/google/protobuf/print_options.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,4 +24,7 @@ void PrintOptions_ModuleInit() {
2424
zend_declare_class_constant_long(options_ce, "ALWAYS_PRINT_ENUMS_AS_INTS",
2525
sizeof("ALWAYS_PRINT_ENUMS_AS_INTS") - 1,
2626
ALWAYS_PRINT_ENUMS_AS_INTS);
27+
zend_declare_class_constant_long(options_ce, "EMIT_DEFAULTS",
28+
sizeof("EMIT_DEFAULTS") - 1,
29+
EMIT_DEFAULTS);
2730
}

php/ext/google/protobuf/print_options.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
#define PRESERVE_PROTO_FIELD_NAMES (1 << 0)
1212
#define ALWAYS_PRINT_ENUMS_AS_INTS (1 << 1)
13+
#define EMIT_DEFAULTS (1 << 2)
1314

1415
// Registers the PHP PrintOptions class.
1516
void PrintOptions_ModuleInit();

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

Lines changed: 59 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,14 @@ protected function whichOneof($oneof_name)
239239
return $field->getName();
240240
}
241241

242+
/**
243+
* @ignore
244+
*/
245+
private function shouldEmitDefaults($options): bool
246+
{
247+
return ($options & \Google\Protobuf\PrintOptions::EMIT_DEFAULTS) !== 0;
248+
}
249+
242250
/**
243251
* @ignore
244252
*/
@@ -1469,6 +1477,7 @@ public function serializeToStream(&$output)
14691477
*/
14701478
public function serializeToJsonStream(&$output)
14711479
{
1480+
$options = $output->getOptions();
14721481
if (is_a($this, 'Google\Protobuf\Any')) {
14731482
$output->writeRaw("{", 1);
14741483
$type_field = $this->desc->getFieldByNumber(1);
@@ -1487,7 +1496,7 @@ public function serializeToJsonStream(&$output)
14871496
} else {
14881497
$value_fields = $value_msg->desc->getField();
14891498
foreach ($value_fields as $field) {
1490-
if ($value_msg->existField($field)) {
1499+
if ($value_msg->existField($field, $options)) {
14911500
$output->writeRaw(",", 1);
14921501
if (!$value_msg->serializeFieldToJsonStream($output, $field)) {
14931502
return false;
@@ -1513,7 +1522,7 @@ public function serializeToJsonStream(&$output)
15131522
$output->writeRaw($timestamp, strlen($timestamp));
15141523
} elseif (get_class($this) === 'Google\Protobuf\ListValue') {
15151524
$field = $this->desc->getField()[1];
1516-
if (!$this->existField($field)) {
1525+
if (!$this->existField($field, $options)) {
15171526
$output->writeRaw("[]", 2);
15181527
} else {
15191528
if (!$this->serializeFieldToJsonStream($output, $field)) {
@@ -1522,7 +1531,7 @@ public function serializeToJsonStream(&$output)
15221531
}
15231532
} elseif (get_class($this) === 'Google\Protobuf\Struct') {
15241533
$field = $this->desc->getField()[1];
1525-
if (!$this->existField($field)) {
1534+
if (!$this->existField($field, $options)) {
15261535
$output->writeRaw("{}", 2);
15271536
} else {
15281537
if (!$this->serializeFieldToJsonStream($output, $field)) {
@@ -1536,7 +1545,7 @@ public function serializeToJsonStream(&$output)
15361545
$fields = $this->desc->getField();
15371546
$first = true;
15381547
foreach ($fields as $field) {
1539-
if ($this->existField($field) ||
1548+
if ($this->existField($field, $options) ||
15401549
GPBUtil::hasJsonValue($this)) {
15411550
if ($first) {
15421551
$first = false;
@@ -1580,7 +1589,7 @@ public function serializeToJsonString($options = 0)
15801589
/**
15811590
* @ignore
15821591
*/
1583-
private function existField($field)
1592+
private function existField($field, $options = 0)
15841593
{
15851594
$getter = $field->getGetter();
15861595
$hazzer = "has" . substr($getter, 3);
@@ -1597,10 +1606,19 @@ private function existField($field)
15971606

15981607
$values = $this->$getter();
15991608
if ($field->isMap()) {
1609+
if ($this->shouldEmitDefaults($options)) {
1610+
return true;
1611+
}
16001612
return count($values) !== 0;
16011613
} elseif ($field->isRepeated()) {
1614+
if ($this->shouldEmitDefaults($options)) {
1615+
return true;
1616+
}
16021617
return count($values) !== 0;
16031618
} else {
1619+
if ($this->shouldEmitDefaults($options)) {
1620+
return true;
1621+
}
16041622
return $values !== $this->defaultValue($field);
16051623
}
16061624
}
@@ -1863,7 +1881,7 @@ private function fieldJsonByteSize($field, $options = 0)
18631881
$getter = $field->getGetter();
18641882
$values = $this->$getter();
18651883
$count = count($values);
1866-
if ($count !== 0) {
1884+
if ($count !== 0 || $this->shouldEmitDefaults($options)) {
18671885
if (!GPBUtil::hasSpecialJsonMapping($this)) {
18681886
$size += 3; // size for "\"\":".
18691887
if ($options & PrintOptions::PRESERVE_PROTO_FIELD_NAMES) {
@@ -1873,37 +1891,39 @@ private function fieldJsonByteSize($field, $options = 0)
18731891
} // size for field name
18741892
}
18751893
$size += 2; // size for "{}".
1876-
$size += $count - 1; // size for commas
1877-
$getter = $field->getGetter();
1878-
$map_entry = $field->getMessageType();
1879-
$key_field = $map_entry->getFieldByNumber(1);
1880-
$value_field = $map_entry->getFieldByNumber(2);
1881-
switch ($key_field->getType()) {
1882-
case GPBType::STRING:
1883-
case GPBType::SFIXED64:
1884-
case GPBType::INT64:
1885-
case GPBType::SINT64:
1886-
case GPBType::FIXED64:
1887-
case GPBType::UINT64:
1888-
$additional_quote = false;
1889-
break;
1890-
default:
1891-
$additional_quote = true;
1892-
}
1893-
foreach ($values as $key => $value) {
1894-
if ($additional_quote) {
1895-
$size += 2; // size for ""
1894+
if ($count > 0) {
1895+
$size += $count - 1; // size for commas
1896+
$getter = $field->getGetter();
1897+
$map_entry = $field->getMessageType();
1898+
$key_field = $map_entry->getFieldByNumber(1);
1899+
$value_field = $map_entry->getFieldByNumber(2);
1900+
switch ($key_field->getType()) {
1901+
case GPBType::STRING:
1902+
case GPBType::SFIXED64:
1903+
case GPBType::INT64:
1904+
case GPBType::SINT64:
1905+
case GPBType::FIXED64:
1906+
case GPBType::UINT64:
1907+
$additional_quote = false;
1908+
break;
1909+
default:
1910+
$additional_quote = true;
1911+
}
1912+
foreach ($values as $key => $value) {
1913+
if ($additional_quote) {
1914+
$size += 2; // size for ""
1915+
}
1916+
$size += $this->fieldDataOnlyJsonByteSize($key_field, $key, $options);
1917+
$size += $this->fieldDataOnlyJsonByteSize($value_field, $value, $options);
1918+
$size += 1; // size for :
18961919
}
1897-
$size += $this->fieldDataOnlyJsonByteSize($key_field, $key, $options);
1898-
$size += $this->fieldDataOnlyJsonByteSize($value_field, $value, $options);
1899-
$size += 1; // size for :
19001920
}
19011921
}
19021922
} elseif ($field->isRepeated()) {
19031923
$getter = $field->getGetter();
19041924
$values = $this->$getter();
19051925
$count = count($values);
1906-
if ($count !== 0) {
1926+
if ($count !== 0 || $this->shouldEmitDefaults($options)) {
19071927
if (!GPBUtil::hasSpecialJsonMapping($this)) {
19081928
$size += 3; // size for "\"\":".
19091929
if ($options & PrintOptions::PRESERVE_PROTO_FIELD_NAMES) {
@@ -1913,13 +1933,15 @@ private function fieldJsonByteSize($field, $options = 0)
19131933
} // size for field name
19141934
}
19151935
$size += 2; // size for "[]".
1916-
$size += $count - 1; // size for commas
1917-
$getter = $field->getGetter();
1918-
foreach ($values as $value) {
1919-
$size += $this->fieldDataOnlyJsonByteSize($field, $value, $options);
1936+
if ($count > 0) {
1937+
$size += $count - 1; // size for commas
1938+
$getter = $field->getGetter();
1939+
foreach ($values as $value) {
1940+
$size += $this->fieldDataOnlyJsonByteSize($field, $value, $options);
1941+
}
19201942
}
19211943
}
1922-
} elseif ($this->existField($field) || GPBUtil::hasJsonValue($this)) {
1944+
} elseif ($this->existField($field, $options) || GPBUtil::hasJsonValue($this)) {
19231945
if (!GPBUtil::hasSpecialJsonMapping($this)) {
19241946
$size += 3; // size for "\"\":".
19251947
if ($options & PrintOptions::PRESERVE_PROTO_FIELD_NAMES) {
@@ -2017,7 +2039,7 @@ public function jsonByteSize($options = 0)
20172039
$size += strlen($timestamp);
20182040
} elseif (get_class($this) === 'Google\Protobuf\ListValue') {
20192041
$field = $this->desc->getField()[1];
2020-
if ($this->existField($field)) {
2042+
if ($this->existField($field, $options)) {
20212043
$field_size = $this->fieldJsonByteSize($field, $options);
20222044
$size += $field_size;
20232045
} else {
@@ -2026,7 +2048,7 @@ public function jsonByteSize($options = 0)
20262048
}
20272049
} elseif (get_class($this) === 'Google\Protobuf\Struct') {
20282050
$field = $this->desc->getField()[1];
2029-
if ($this->existField($field)) {
2051+
if ($this->existField($field, $options)) {
20302052
$field_size = $this->fieldJsonByteSize($field, $options);
20312053
$size += $field_size;
20322054
} else {

php/src/Google/Protobuf/PrintOptions.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,5 @@ class PrintOptions
1313
{
1414
const PRESERVE_PROTO_FIELD_NAMES = 1 << 0;
1515
const ALWAYS_PRINT_ENUMS_AS_INTS = 1 << 1;
16-
}
16+
const EMIT_DEFAULTS = 1 << 2;
17+
}

0 commit comments

Comments
 (0)