Skip to content

Commit e7da2a1

Browse files
committed
[php][ext] - Fix isset behaviour
1 parent 6f4c49b commit e7da2a1

File tree

2 files changed

+50
-11
lines changed

2 files changed

+50
-11
lines changed

php/ext/google/protobuf/message.c

Lines changed: 25 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -85,11 +85,11 @@ static void Message_dtor(zend_object* obj) {
8585
}
8686

8787
/**
88-
* get_field()
88+
* lookup_field()
8989
*
9090
* Helper function to look up a field given a member name (as a string).
9191
*/
92-
static const upb_FieldDef* get_field(Message* msg, zend_string* member) {
92+
static const upb_FieldDef* lookup_field(Message* msg, zend_string* member) {
9393
if (!msg || !msg->desc || !msg->desc->msgdef) {
9494
zend_throw_exception_ex(NULL, 0,
9595
"Couldn't find descriptor. "
@@ -104,8 +104,26 @@ static const upb_FieldDef* get_field(Message* msg, zend_string* member) {
104104
m, ZSTR_VAL(member), ZSTR_LEN(member));
105105

106106
if (!f) {
107-
zend_throw_exception_ex(NULL, 0, "No such property %s.",
108-
ZSTR_VAL(msg->desc->class_entry->name));
107+
return NULL;
108+
}
109+
110+
return f;
111+
}
112+
113+
/**
114+
* get_field()
115+
*
116+
* Helper function to get up a field given a member name (as a string).
117+
* if the field is not found, a PHP warning is emitted and NULL is returned.
118+
*/
119+
static const upb_FieldDef* get_field(Message* msg, zend_string* member) {
120+
const upb_FieldDef* f = lookup_field(msg, member);
121+
122+
if (!f && msg && msg->desc) {
123+
// if the descriptor is undefined, an exception was already thrown.
124+
php_error(E_WARNING, "Undefined property: %s::$%s",
125+
ZSTR_VAL(msg->desc->class_entry->name),
126+
ZSTR_VAL(member));
109127
}
110128

111129
return f;
@@ -250,15 +268,11 @@ static int Message_compare_objects(zval* m1, zval* m2) {
250268
static int Message_has_property(zend_object* obj, zend_string* member,
251269
int has_set_exists, void** cache_slot) {
252270
Message* intern = (Message*)obj;
253-
const upb_FieldDef* f = get_field(intern, member);
271+
const upb_FieldDef* f = lookup_field(intern, member);
254272

255273
if (!f) return 0;
256274

257-
if (!upb_FieldDef_HasPresence(f)) {
258-
zend_throw_exception_ex(
259-
NULL, 0,
260-
"Cannot call isset() on field %s which does not have presence.",
261-
upb_FieldDef_Name(f));
275+
if (upb_FieldDef_IsOptional(f) && !upb_FieldDef_HasPresence(f)) {
262276
return 0;
263277
}
264278

@@ -284,7 +298,7 @@ static int Message_has_property(zend_object* obj, zend_string* member,
284298
static void Message_unset_property(zend_object* obj, zend_string* member,
285299
void** cache_slot) {
286300
Message* intern = (Message*)obj;
287-
const upb_FieldDef* f = get_field(intern, member);
301+
const upb_FieldDef* f = lookup_field(intern, member);
288302

289303
if (!f) return;
290304

php/tests/GeneratedClassTest.php

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,31 @@ public function testSetterGetter()
5656
$this->assertSame(1, $m->getOptionalInt32());
5757
}
5858

59+
#########################################################
60+
# Test isset / property_exists
61+
#########################################################
62+
63+
public function testIsset()
64+
{
65+
$message = new TestMessage();
66+
67+
$this->assertTrue(property_exists(TestMessage::class, 'optional_string'));
68+
$this->assertTrue(property_exists($message, 'optional_string'));
69+
$this->assertFalse(isset($message->optional_string));
70+
71+
$message->setOptionalString('bar');
72+
73+
$this->assertTrue(property_exists(TestMessage::class, 'optional_string'));
74+
$this->assertFalse(property_exists(TestMessage::class, 'foo'));
75+
76+
$this->assertTrue(property_exists($message, 'optional_string'));
77+
$this->assertFalse(property_exists($message, 'foo'));
78+
79+
// isset() should return false for attributes that are not public.
80+
$this->assertFalse(isset($message->optional_string));
81+
$this->assertFalse(isset($message->foo));
82+
}
83+
5984
#########################################################
6085
# Test int32 field.
6186
#########################################################

0 commit comments

Comments
 (0)