summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--NEWS3
-rw-r--r--Zend/tests/bug71731.phpt64
-rw-r--r--Zend/zend_object_handlers.c15
3 files changed, 81 insertions, 1 deletions
diff --git a/NEWS b/NEWS
index d97e7c5a80..0cccc6abe7 100644
--- a/NEWS
+++ b/NEWS
@@ -8,6 +8,9 @@ PHP NEWS
. Fixed Bug #71859 (zend_objects_store_call_destructors operates on realloced
memory, crashing). (Laruence)
. Fixed bug #71841 (EG(error_zval) is not handled well). (Laruence)
+ . Fixed bug #71731 (Null coalescing operator and ArrayAccess). (Nikita)
+ . Fixed bug #69659 (ArrayAccess, isset() and the offsetExists method).
+ (Nikita)
- ODBC:
. Fixed bug #63171 (Script hangs after max_execution_time). (Remi)
diff --git a/Zend/tests/bug71731.phpt b/Zend/tests/bug71731.phpt
new file mode 100644
index 0000000000..46a79f1a34
--- /dev/null
+++ b/Zend/tests/bug71731.phpt
@@ -0,0 +1,64 @@
+--TEST--
+Bug #71731: Null coalescing operator and ArrayAccess
+--FILE--
+<?php
+
+class AA implements ArrayAccess {
+ private $data = [];
+ public function offsetExists($name) {
+ echo "offsetExists($name)\n";
+ return array_key_exists($name, $this->data);
+ }
+ public function &offsetGet($name) {
+ echo "offsetGet($name)\n";
+ if (!array_key_exists($name, $this->data)) {
+ throw new Exception('Unknown offset');
+ }
+ return $this->data[$name];
+ }
+ public function offsetSet($name, $value) {
+ echo "offsetSet($name)\n";
+ $this->data[$name] = $value;
+ }
+ public function offsetUnset($name) {
+ echo "offsetUnset($name)\n";
+ unset($this->data[$name]);
+ }
+}
+
+$aa = new AA;
+var_dump(isset($aa[0][1][2]));
+var_dump(isset($aa[0]->foo));
+var_dump($aa[0] ?? 42);
+var_dump($aa[0][1][2] ?? 42);
+
+$aa[0] = new AA;
+$aa[0][1] = new AA;
+var_dump(isset($aa[0][1][2]));
+var_dump($aa[0][1][2] ?? 42);
+
+?>
+--EXPECT--
+offsetExists(0)
+bool(false)
+offsetExists(0)
+bool(false)
+offsetExists(0)
+int(42)
+offsetExists(0)
+int(42)
+offsetSet(0)
+offsetGet(0)
+offsetSet(1)
+offsetExists(0)
+offsetGet(0)
+offsetExists(1)
+offsetGet(1)
+offsetExists(2)
+bool(false)
+offsetExists(0)
+offsetGet(0)
+offsetExists(1)
+offsetGet(1)
+offsetExists(2)
+int(42)
diff --git a/Zend/zend_object_handlers.c b/Zend/zend_object_handlers.c
index 091a0a0d53..7b31fdc524 100644
--- a/Zend/zend_object_handlers.c
+++ b/Zend/zend_object_handlers.c
@@ -710,13 +710,26 @@ zval *zend_std_read_dimension(zval *object, zval *offset, int type, zval *rv) /*
zval tmp;
if (EXPECTED(instanceof_function_ex(ce, zend_ce_arrayaccess, 1) != 0)) {
- if(offset == NULL) {
+ if (offset == NULL) {
/* [] construct */
ZVAL_NULL(&tmp);
offset = &tmp;
} else {
SEPARATE_ARG_IF_REF(offset);
}
+
+ if (type == BP_VAR_IS) {
+ zend_call_method_with_1_params(object, ce, NULL, "offsetexists", rv, offset);
+ if (UNEXPECTED(Z_ISUNDEF_P(rv))) {
+ return NULL;
+ }
+ if (!i_zend_is_true(rv)) {
+ zval_ptr_dtor(rv);
+ return &EG(uninitialized_zval);
+ }
+ zval_ptr_dtor(rv);
+ }
+
zend_call_method_with_1_params(object, ce, NULL, "offsetget", rv, offset);
zval_ptr_dtor(offset);