Skip to content

Commit 4b4cd0c

Browse files
committed
Try to make unsetting array items work + add tests for pass by ref
1 parent 075f2cb commit 4b4cd0c

11 files changed

+154
-50
lines changed

Zend/tests/final_properties/access/property_assignment_combined1.phpt

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,12 @@
11
--TEST--
22
Test that final properties can't be mutated by combined assignment operators
3-
--XFAIL--
4-
??= doesn't work
53
--FILE--
64
<?php
75

86
class Foo
97
{
108
final public int $property1 = 1;
11-
final public string $property2 = "";
9+
final public ?string $property2;
1210
}
1311

1412
$foo = new Foo();
@@ -73,14 +71,16 @@ try {
7371
echo $exception->getMessage() . "\n";
7472
}
7573

74+
$foo->property2 ??= null;
75+
7676
try {
77-
$foo->property2 .= "foo";
77+
$foo->property2 ??= "foo";
7878
} catch (Error $exception) {
7979
echo $exception->getMessage() . "\n";
8080
}
8181

8282
try {
83-
$foo->property2 ??= "foo";
83+
$foo->property2 .= "foo";
8484
} catch (Error $exception) {
8585
echo $exception->getMessage() . "\n";
8686
}
@@ -103,4 +103,4 @@ Cannot modify final property Foo::$property1 after initialization
103103
Cannot modify final property Foo::$property2 after initialization
104104
Cannot modify final property Foo::$property2 after initialization
105105
int(1)
106-
string(0) ""
106+
NULL

Zend/tests/final_properties/access/property_assignment_combined2.phpt

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,12 @@
11
--TEST--
22
Test that final static properties can't be mutated by combined assignment operators
3-
--XFAIL--
4-
??= doesn't work
53
--FILE--
64
<?php
75

86
class Foo
97
{
108
final public static int $property1 = 1;
11-
final public static string $property2 = "";
9+
final public static ?string $property2;
1210
}
1311

1412
$foo = new Foo();
@@ -73,14 +71,16 @@ try {
7371
echo $exception->getMessage() . "\n";
7472
}
7573

74+
Foo::$property2 ??= null;
75+
7676
try {
77-
Foo::$property2 .= "foo";
77+
Foo::$property2 ??= "foo";
7878
} catch (Error $exception) {
7979
echo $exception->getMessage() . "\n";
8080
}
8181

8282
try {
83-
Foo::$property2 ??= "foo";
83+
Foo::$property2 .= "foo";
8484
} catch (Error $exception) {
8585
echo $exception->getMessage() . "\n";
8686
}
@@ -103,4 +103,4 @@ Cannot modify final static property Foo::$property1 after initialization
103103
Cannot modify final static property Foo::$property2 after initialization
104104
Cannot modify final static property Foo::$property2 after initialization
105105
int(1)
106-
string(0) ""
106+
NULL

Zend/tests/final_properties/access/property_mutation.phpt

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
--TEST--
22
Test that final properties can't be mutated
3-
--XFAIL--
4-
Unsetting array items doesn't work yet
53
--FILE--
64
<?php
75

@@ -10,12 +8,12 @@ class Foo
108
final public int $property1;
119
final protected string $property2 = "Foo";
1210
final public array $property3;
13-
final public stdclass $property4;
11+
final public stdClass $property4;
1412

1513
public function __construct()
1614
{
1715
$this->property1 = 1;
18-
$this->property4 = new stdclass();
16+
$this->property4 = new stdClass();
1917
}
2018

2119
public function getProperty1(): int
@@ -59,6 +57,12 @@ try {
5957

6058
$foo->property3[] = 1;
6159

60+
try {
61+
$foo->property3[] = 1;
62+
} catch (Error $exception) {
63+
echo $exception->getMessage() . "\n";
64+
}
65+
6266
try {
6367
$foo->property3["foo"] = 1;
6468
} catch (Error $exception) {
@@ -71,6 +75,14 @@ try {
7175
echo $exception->getMessage() . "\n";
7276
}
7377

78+
try {
79+
unset($foo->property3["foo"]);
80+
} catch (Error $exception) {
81+
echo $exception->getMessage() . "\n";
82+
}
83+
84+
var_dump($foo->property3);
85+
7486
$foo->property4->foo = "foo";
7587

7688
?>
@@ -79,3 +91,9 @@ Cannot modify final property Foo::$property1 after initialization
7991
Cannot modify final property Foo::$property2 after initialization
8092
Cannot modify final property Foo::$property3 after initialization
8193
Cannot modify final property Foo::$property3 after initialization
94+
Cannot modify final property Foo::$property3 after initialization
95+
Cannot modify final property Foo::$property3 after initialization
96+
array(1) {
97+
[0]=>
98+
int(1)
99+
}

Zend/tests/final_properties/access/property_mutation_static.phpt

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
--TEST--
22
Test that final static properties can't be mutated
33
--XFAIL--
4-
Unsetting array items and accessing objects aren't prevented
4+
Object properties are fetched with incorrect access mode
55
--FILE--
66
<?php
77

@@ -10,12 +10,12 @@ class Foo
1010
final public static int $property1;
1111
final public static string $property2 = "Foo";
1212
final public static array $property3;
13-
final public static stdclass $property4;
13+
final public static stdClass $property4;
1414

1515
public function __construct()
1616
{
1717
Foo::$property1 = 1;
18-
Foo::$property4 = new stdclass();
18+
Foo::$property4 = new stdClass();
1919
}
2020
}
2121

@@ -35,8 +35,6 @@ try {
3535

3636
Foo::$property3[] = 1;
3737

38-
var_dump(Foo::$property3);
39-
4038
try {
4139
Foo::$property3[] = 1;
4240
} catch (Error $exception) {
@@ -55,6 +53,12 @@ try {
5553
echo $exception->getMessage() . "\n";
5654
}
5755

56+
try {
57+
unset(Foo::$property3["foo"]);
58+
} catch (Error $exception) {
59+
echo $exception->getMessage() . "\n";
60+
}
61+
5862
var_dump(Foo::$property3);
5963

6064
Foo::$property4->foo = "foo";
@@ -63,10 +67,8 @@ Foo::$property4->foo = "foo";
6367
--EXPECT--
6468
Cannot modify final static property Foo::$property1 after initialization
6569
Cannot modify final static property Foo::$property2 after initialization
66-
array(1) {
67-
[0]=>
68-
int(1)
69-
}
70+
Cannot modify final static property Foo::$property3 after initialization
71+
Cannot modify final static property Foo::$property3 after initialization
7072
Cannot modify final static property Foo::$property3 after initialization
7173
Cannot modify final static property Foo::$property3 after initialization
7274
array(1) {
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
--TEST--
2+
Test that final properties can't be passed by ref
3+
--XFAIL--
4+
Incorrect error message in case of static properties ("Cannot modify final static property ...")
5+
--FILE--
6+
<?php
7+
8+
class Foo
9+
{
10+
final public array $property1;
11+
final public array $property2 = [1, 2, 3];
12+
final public static array $property3;
13+
final public static array $property4 = [1, 2, 3];
14+
}
15+
16+
$foo = new Foo();
17+
18+
try {
19+
preg_match("/a/", "a", $foo->property1);
20+
} catch (Error $exception) {
21+
echo $exception->getMessage() . "\n";
22+
}
23+
24+
try {
25+
sort($foo->property2);
26+
} catch (Error $exception) {
27+
echo $exception->getMessage() . "\n";
28+
}
29+
30+
try {
31+
preg_match("/a/", "a", Foo::$property3);
32+
} catch (Error $exception) {
33+
echo $exception->getMessage() . "\n";
34+
}
35+
36+
try {
37+
sort(Foo::$property4);
38+
} catch (Error $exception) {
39+
echo $exception->getMessage() . "\n";
40+
}
41+
42+
?>
43+
--EXPECT--
44+
Cannot acquire reference to final property Foo::$property1
45+
Cannot acquire reference to final property Foo::$property2
46+
Cannot acquire reference to final property Foo::$property3
47+
Cannot acquire reference to final property Foo::$property4

Zend/tests/final_properties/unset/magic_unset_error2.phpt

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
--TEST--
22
Test that the __unset() magic method results in an exception
3-
--XFAIL--
4-
Unsetting array items is not prevented
53
--FILE--
64
<?php
75

@@ -40,7 +38,11 @@ try {
4038
echo $exception->getMessage() . "\n";
4139
}
4240

43-
unset($foo->property2);
41+
try {
42+
unset($foo->property2);
43+
} catch (Error $exception) {
44+
echo $exception->getMessage() . "\n";
45+
}
4446

4547
try {
4648
unset($foo->properties);
@@ -55,5 +57,7 @@ var_dump($foo->properties);
5557
Cannot modify final property Foo::$properties after initialization
5658
Cannot modify final property Foo::$properties after initialization
5759
Cannot unset final property Foo::$properties
58-
array(0) {
60+
array(1) {
61+
["property1"]=>
62+
NULL
5963
}

Zend/zend_compile.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2643,6 +2643,8 @@ static zend_op *zend_delayed_compile_dim(znode *result, zend_ast *ast, uint32_t
26432643
opline = zend_delayed_compile_var(&var_node, var_ast, type, 0);
26442644
if (opline && type == BP_VAR_W && (opline->opcode == ZEND_FETCH_STATIC_PROP_W || opline->opcode == ZEND_FETCH_OBJ_W)) {
26452645
opline->extended_value |= ZEND_FETCH_DIM_WRITE;
2646+
} else if (opline && type == BP_VAR_UNSET && (opline->opcode == ZEND_FETCH_STATIC_PROP_UNSET || opline->opcode == ZEND_FETCH_OBJ_UNSET)) {
2647+
opline->extended_value |= ZEND_FETCH_DIM_UNSET_FLAG;
26462648
}
26472649

26482650
zend_separate_if_call_and_write(&var_node, var_ast, type);

Zend/zend_compile.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -907,9 +907,10 @@ ZEND_API zend_string *zend_type_to_string(zend_type type);
907907
#define ZEND_FETCH_TYPE_MASK 0xe
908908

909909
/* Only one of these can ever be in use */
910-
#define ZEND_FETCH_REF 1
911-
#define ZEND_FETCH_DIM_WRITE 2
912-
#define ZEND_FETCH_OBJ_FLAGS 3
910+
#define ZEND_FETCH_REF 1
911+
#define ZEND_FETCH_DIM_WRITE 2
912+
#define ZEND_FETCH_DIM_UNSET_FLAG 3
913+
#define ZEND_FETCH_OBJ_FLAGS 3
913914

914915
#define ZEND_ISEMPTY (1<<0)
915916

Zend/zend_execute.c

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -955,14 +955,15 @@ static zend_never_inline zval* zend_assign_to_typed_prop(zend_property_info *inf
955955
{
956956
zval tmp;
957957

958-
if (UNEXPECTED(info->flags & ZEND_ACC_FINAL && Z_PROP_FLAG_P(property_val) != IS_PROP_UNINIT)) {
958+
ZVAL_DEREF(value);
959+
ZVAL_COPY(&tmp, value);
960+
961+
if (UNEXPECTED(info->flags & ZEND_ACC_FINAL && Z_PROP_FLAG_P(&tmp) != IS_PROP_UNINIT)) {
959962
zend_final_property_assignment_error(info->ce, zend_get_unmangled_property_name(info->name));
963+
zval_ptr_dtor(&tmp);
960964
return &EG(uninitialized_zval);
961965
}
962966

963-
ZVAL_DEREF(value);
964-
ZVAL_COPY(&tmp, value);
965-
966967
if (UNEXPECTED(!i_zend_verify_property_type(info, &tmp, EX_USES_STRICT_TYPES()))) {
967968
zval_ptr_dtor(&tmp);
968969
return &EG(uninitialized_zval);
@@ -2723,8 +2724,7 @@ static zend_never_inline zend_bool zend_handle_fetch_obj_flags(
27232724
ZEND_REF_ADD_TYPE_SOURCE(Z_REF_P(ptr), prop_info);
27242725
}
27252726
break;
2726-
case ZEND_FETCH_DIM_UNSET:
2727-
case ZEND_FETCH_DIM_RW:
2727+
case ZEND_FETCH_DIM_UNSET_FLAG:
27282728
if (!prop_info) {
27292729
prop_info = zend_object_fetch_property_type_info(obj, ptr);
27302730
if (!prop_info) {

Zend/zend_vm_def.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1804,7 +1804,7 @@ ZEND_VM_HELPER(zend_fetch_static_prop_helper, ANY, ANY, int type)
18041804

18051805
SAVE_OPLINE();
18061806

1807-
if (UNEXPECTED(zend_fetch_static_property_address(&prop, NULL, opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS, type, opline->extended_value & ZEND_FETCH_OBJ_FLAGS OPLINE_CC EXECUTE_DATA_CC) != SUCCESS)) {
1807+
if (UNEXPECTED(zend_fetch_static_property_address(&prop, NULL, opline->extended_value & ~(type == BP_VAR_UNSET ? ZEND_FETCH_DIM_UNSET_FLAG : ZEND_FETCH_OBJ_FLAGS), type, opline->extended_value & (type == BP_VAR_UNSET ? ZEND_FETCH_DIM_UNSET_FLAG : ZEND_FETCH_OBJ_FLAGS) OPLINE_CC EXECUTE_DATA_CC) != SUCCESS)) {
18081808
ZEND_ASSERT(EG(exception) || (type == BP_VAR_IS));
18091809
prop = &EG(uninitialized_zval);
18101810
}
@@ -2288,7 +2288,10 @@ ZEND_VM_HANDLER(97, ZEND_FETCH_OBJ_UNSET, VAR|UNUSED|THIS|CV, CONST|TMPVAR|CV, C
22882288
container = GET_OP1_OBJ_ZVAL_PTR_PTR_UNDEF(BP_VAR_UNSET);
22892289
property = GET_OP2_ZVAL_PTR(BP_VAR_R);
22902290
result = EX_VAR(opline->result.var);
2291-
zend_fetch_property_address(result, container, OP1_TYPE, property, OP2_TYPE, ((OP2_TYPE == IS_CONST) ? CACHE_ADDR(opline->extended_value) : NULL), BP_VAR_UNSET, 0, 1 OPLINE_CC EXECUTE_DATA_CC);
2291+
zend_fetch_property_address(result, container, OP1_TYPE, property, OP2_TYPE,
2292+
((OP2_TYPE == IS_CONST) ? CACHE_ADDR(opline->extended_value) : NULL), BP_VAR_UNSET,
2293+
opline->extended_value & ZEND_FETCH_DIM_UNSET_FLAG, 1 OPLINE_CC EXECUTE_DATA_CC
2294+
);
22922295
FREE_OP2();
22932296
if (OP1_TYPE == IS_VAR) {
22942297
FREE_VAR_PTR_AND_EXTRACT_RESULT_IF_NECESSARY(opline->op1.var);

0 commit comments

Comments
 (0)