diff --git a/php/ext/google/protobuf/message.c b/php/ext/google/protobuf/message.c index b00a11519d..277c8bf6fe 100644 --- a/php/ext/google/protobuf/message.c +++ b/php/ext/google/protobuf/message.c @@ -312,7 +312,13 @@ static zval* Message_read_property(zend_object* obj, zend_string* member, const upb_FieldDef* f = get_field(intern, member); if (!f) return &EG(uninitialized_zval); - Message_get(intern, f, rv); + + if (upb_FieldDef_IsOptional(f) && upb_FieldDef_HasPresence(f) && + Message_has_property(obj, member, 0, cache_slot) == false) { + ZVAL_NULL(rv); + } else { + Message_get(intern, f, rv); + } return rv; } diff --git a/php/tests/WellKnownTest.php b/php/tests/WellKnownTest.php index 486c65ffca..13c213919d 100644 --- a/php/tests/WellKnownTest.php +++ b/php/tests/WellKnownTest.php @@ -416,4 +416,44 @@ class WellKnownTest extends TestBase { ['\Google\Protobuf\Syntax'], ]; } + + /** + * @dataProvider optionalFieldsDataProvider + */ + public function testReflectionProperty($property, $default) + { + $testMessage = new TestMessage(); + + $functionName = implode('', array_map('ucwords', explode('_', $property))); + + $reflectionProperty = new \ReflectionProperty($testMessage, $property); + + self::assertFalse(call_user_func([$testMessage, 'has'.$functionName])); + self::assertEquals($default, call_user_func([$testMessage, 'get'.$functionName])); + self::assertNull($reflectionProperty->getValue($testMessage)); + } + + public function optionalFieldsDataProvider() + { + return [ + ['true_optional_int32', 0], + ['true_optional_int64', 0], + ['true_optional_uint32', 0], + ['true_optional_uint64', 0], + ['true_optional_sint32', 0], + ['true_optional_sint64', 0], + ['true_optional_fixed32', 0], + ['true_optional_fixed64', 0], + ['true_optional_sfixed32', 0], + ['true_optional_sfixed64', 0], + ['true_optional_float', 0.0], + ['true_optional_double', 0.0], + ['true_optional_bool', false], + ['true_optional_string', ''], + ['true_optional_bytes', ''], + ['true_optional_enum', null], + ['true_optional_message', null], + ['true_optional_included_message', null], + ]; + } }