Skip to content

Also don't call other magic for uninitialized typed properties #4974

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
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
5 changes: 3 additions & 2 deletions Zend/tests/type_declarations/typed_properties_040.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,13 @@ class Foo {

$foo = new Foo();

unset($foo->bar);
var_dump($foo->bar);
?>
--EXPECTF--
string(3) "bar"

Fatal error: Uncaught TypeError: Typed property Foo::$bar must be int, null used in %s:14
Fatal error: Uncaught TypeError: Typed property Foo::$bar must be int, null used in %s:%d
Stack trace:
#0 {main}
thrown in %s on line 14
thrown in %s on line %d
1 change: 1 addition & 0 deletions Zend/tests/type_declarations/typed_properties_072.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ class Test {
}

$test = new Test;
unset($test->val);
var_dump($test);
var_dump($test->val);

Expand Down
1 change: 1 addition & 0 deletions Zend/tests/type_declarations/typed_properties_073.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ class Test {
}

$test = new Test;
unset($test->val);
var_dump($test);
var_dump($val = &$test->val);
var_dump($test);
Expand Down
1 change: 1 addition & 0 deletions Zend/tests/type_declarations/typed_properties_074.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ class Test {

$test = new Test;
$dummyRef = &$test->prop;
unset($test->val);
var_dump($test);
try {
var_dump($test->val);
Expand Down
19 changes: 19 additions & 0 deletions Zend/tests/type_declarations/typed_properties_magic_set.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,29 @@ __set() should not be invoked when setting an uninitialized typed property

class Test {
public int $foo;
public function __get($name) {
echo "__get ", $name, "\n";
return null;
}
public function __set($name, $value) {
echo "__set ", $name, " = ", $value, "\n";
}
public function __isset($name) {
echo "__isset ", $name, "\n";
return true;
}
public function __unset($name) {
echo "__unset ", $name, "\n";
}
}

$test = new Test;
try {
var_dump($test->foo);
} catch (Error $e) {
echo $e->getMessage(), "\n";
}
var_dump(isset($test->foo));
$test->foo = 42;
var_dump($test->foo);

Expand Down Expand Up @@ -44,6 +61,8 @@ $test->foo = 42;

?>
--EXPECT--
Typed property Test::$foo must not be accessed before initialization
bool(false)
int(42)
__set foo = 42
__set foo = 42
Expand Down
17 changes: 15 additions & 2 deletions Zend/zend_object_handlers.c
Original file line number Diff line number Diff line change
Expand Up @@ -679,6 +679,10 @@ ZEND_API zval *zend_std_read_property(zval *object, zval *member, int type, void
if (EXPECTED(Z_TYPE_P(retval) != IS_UNDEF)) {
goto exit;
}
if (UNEXPECTED(Z_PROP_FLAG_P(retval) == IS_PROP_UNINIT)) {
/* Skip __get() for uninitialized typed properties */
goto uninit_error;
}
} else if (EXPECTED(IS_DYNAMIC_PROPERTY_OFFSET(property_offset))) {
if (EXPECTED(zobj->properties != NULL)) {
if (!IS_UNKNOWN_DYNAMIC_PROPERTY_OFFSET(property_offset)) {
Expand Down Expand Up @@ -782,6 +786,7 @@ ZEND_API zval *zend_std_read_property(zval *object, zval *member, int type, void
}
}

uninit_error:
if (type != BP_VAR_IS) {
if (UNEXPECTED(prop_info)) {
zend_throw_error(NULL, "Typed property %s::$%s must not be accessed before initialization",
Expand Down Expand Up @@ -1126,8 +1131,11 @@ ZEND_API void zend_std_unset_property(zval *object, zval *member, void **cache_s
}
goto exit;
}
/* Reset the IS_PROP_UNINIT flag, if it exists. */
Z_PROP_FLAG_P(slot) = 0;
if (UNEXPECTED(Z_PROP_FLAG_P(slot) == IS_PROP_UNINIT)) {
/* Reset the IS_PROP_UNINIT flag, if it exists and bypass __unset(). */
Z_PROP_FLAG_P(slot) = 0;
goto exit;
}
} else if (EXPECTED(IS_DYNAMIC_PROPERTY_OFFSET(property_offset))
&& EXPECTED(zobj->properties != NULL)) {
if (UNEXPECTED(GC_REFCOUNT(zobj->properties) > 1)) {
Expand Down Expand Up @@ -1686,6 +1694,11 @@ ZEND_API int zend_std_has_property(zval *object, zval *member, int has_set_exist
if (Z_TYPE_P(value) != IS_UNDEF) {
goto found;
}
if (UNEXPECTED(Z_PROP_FLAG_P(value) == IS_PROP_UNINIT)) {
/* Skip __isset() for uninitialized typed properties */
result = 0;
goto exit;
}
} else if (EXPECTED(IS_DYNAMIC_PROPERTY_OFFSET(property_offset))) {
if (EXPECTED(zobj->properties != NULL)) {
if (!IS_UNKNOWN_DYNAMIC_PROPERTY_OFFSET(property_offset)) {
Expand Down