Skip to content

Commit

Permalink
GH-8344 Fetch properties of enums in const expressions
Browse files Browse the repository at this point in the history
  • Loading branch information
iluuu1994 committed Jul 18, 2022
1 parent 922371f commit 7aadbcb
Show file tree
Hide file tree
Showing 26 changed files with 588 additions and 11 deletions.
2 changes: 2 additions & 0 deletions UPGRADING
Expand Up @@ -78,6 +78,8 @@ PHP 8.2 UPGRADE NOTES
RFC: https://wiki.php.net/rfc/dnf_types
. Added error_log_mode ini setting that allows setting of permissions for
error log file.
. Added support for fetching properties of enums in constant expressions.
RFC: https://wiki.php.net/rfc/fetch_property_in_const_expressions


- Curl:
Expand Down
44 changes: 44 additions & 0 deletions Zend/tests/prop_const_expr/attributes.phpt
@@ -0,0 +1,44 @@
--TEST--
Allow fetching properties in attributes
--EXTENSIONS--
reflection
--FILE--
<?php

enum A: string {
case B = 'C';
}

#[Attribute(Attribute::TARGET_CLASS | Attribute::IS_REPEATABLE)]
class Attr {
public function __construct(public $value) {}
}

#[Attr(A::B->name)]
#[Attr(A::B->value)]
#[Attr(A::B?->name)]
#[Attr(A::B?->value)]
class C {}

foreach ((new ReflectionClass(C::class))->getAttributes() as $reflectionAttribute) {
var_dump($reflectionAttribute->newInstance());
}

?>
--EXPECT--
object(Attr)#1 (1) {
["value"]=>
string(1) "B"
}
object(Attr)#1 (1) {
["value"]=>
string(1) "C"
}
object(Attr)#1 (1) {
["value"]=>
string(1) "B"
}
object(Attr)#1 (1) {
["value"]=>
string(1) "C"
}
27 changes: 27 additions & 0 deletions Zend/tests/prop_const_expr/basic.phpt
@@ -0,0 +1,27 @@
--TEST--
Allow fetching properties in constant expressions on enums
--FILE--
<?php

enum A: string {
case Case = 'A::Case';
}

const A_name = A::Case->name;
const A_value = A::Case->value;

var_dump(A_name);
var_dump(A_value);

const A_name_nullsafe = A::Case?->name;
const A_value_nullsafe = A::Case?->value;

var_dump(A_name_nullsafe);
var_dump(A_value_nullsafe);

?>
--EXPECT--
string(4) "Case"
string(7) "A::Case"
string(4) "Case"
string(7) "A::Case"
46 changes: 46 additions & 0 deletions Zend/tests/prop_const_expr/basic_nullsafe.phpt
@@ -0,0 +1,46 @@
--TEST--
Nullsafe property constant expression
--FILE--
<?php

class Printer {
public function __construct() {
echo "Printer\n";
}
}

const A = (null)?->test;
var_dump(A);

const B = (null)?->test->test;
var_dump(B);

const C = (null)->test?->test;
var_dump(C);

const D = (null)?->test['test'];
var_dump(D);

const E = (null)['test']?->test;
var_dump(E);

const F = (null)?->{new Printer};
var_dump(F);

const G = (null)?->test + (new Printer ? 1 : 0);
var_dump(G);

?>
--EXPECTF--
NULL
NULL

Warning: Attempt to read property "test" on null in %s on line %d
NULL
NULL

Warning: Trying to access array offset on value of type null in %s on line %d
NULL
NULL
Printer
int(1)
27 changes: 27 additions & 0 deletions Zend/tests/prop_const_expr/class_const.phpt
@@ -0,0 +1,27 @@
--TEST--
Allow fetching properties in class constants
--FILE--
<?php

enum A: string {
case Case = 'A::Case';
}

class C {
const A_name = A::Case->name;
const A_value = A::Case->value;
const A_name_nullsafe = A::Case?->name;
const A_value_nullsafe = A::Case?->value;
}

var_dump(C::A_name);
var_dump(C::A_value);
var_dump(C::A_name_nullsafe);
var_dump(C::A_value_nullsafe);

?>
--EXPECT--
string(4) "Case"
string(7) "A::Case"
string(4) "Case"
string(7) "A::Case"
34 changes: 34 additions & 0 deletions Zend/tests/prop_const_expr/default_args.phpt
@@ -0,0 +1,34 @@
--TEST--
Property fetch in default argument
--FILE--
<?php

enum A: string {
case B = 'C';
}

function test(
$name = A::B->name,
$value = A::B->value,
$nameNullsafe = A::B?->name,
$valueNullsafe = A::B?->value,
) {
var_dump($name);
var_dump($value);
var_dump($nameNullsafe);
var_dump($valueNullsafe);
}

test();
test('D', 'E', 'F', 'G');

?>
--EXPECT--
string(1) "B"
string(1) "C"
string(1) "B"
string(1) "C"
string(1) "D"
string(1) "E"
string(1) "F"
string(1) "G"
30 changes: 30 additions & 0 deletions Zend/tests/prop_const_expr/enum_initializer.phpt
@@ -0,0 +1,30 @@
--TEST--
Property fetch in enum initializers
--FILE--
<?php

enum A: string {
case B = 'C';
}

enum D: string {
case E = A::B->name;
case F = A::B->value;
}

enum G: string {
case H = A::B?->name;
case I = A::B?->value;
}

var_dump(D::E->value);
var_dump(D::F->value);
var_dump(G::H->value);
var_dump(G::I->value);

?>
--EXPECT--
string(1) "B"
string(1) "C"
string(1) "B"
string(1) "C"
13 changes: 13 additions & 0 deletions Zend/tests/prop_const_expr/lhs_class_not_found.phpt
@@ -0,0 +1,13 @@
--TEST--
Property constant expression lhs error
--FILE--
<?php

const A_prop = (new A)->prop;

?>
--EXPECTF--
Fatal error: Uncaught Error: Class "A" not found in %s:%d
Stack trace:
#0 {main}
thrown in %s on line %d
13 changes: 13 additions & 0 deletions Zend/tests/prop_const_expr/lhs_class_not_found_nullsafe.phpt
@@ -0,0 +1,13 @@
--TEST--
Nullsafe property constant expression lhs error
--FILE--
<?php

const A_prop = (new A)?->prop;

?>
--EXPECTF--
Fatal error: Uncaught Error: Class "A" not found in %s:%d
Stack trace:
#0 {main}
thrown in %s on line %d
18 changes: 18 additions & 0 deletions Zend/tests/prop_const_expr/lhs_non_object.phpt
@@ -0,0 +1,18 @@
--TEST--
Property constant expression lhs wrong type
--FILE--
<?php

const A_prop = (42)->prop;
var_dump(A_prop);

const A_prop_nullsafe = (42)?->prop;
var_dump(A_prop_nullsafe);

?>
--EXPECTF--
Warning: Attempt to read property "prop" on int in %s on line %d
NULL

Warning: Attempt to read property "prop" on int in %s on line %d
NULL
17 changes: 17 additions & 0 deletions Zend/tests/prop_const_expr/non_enums.phpt
@@ -0,0 +1,17 @@
--TEST--
Disallow fetching properties in constant expressions on non-enums
--FILE--
<?php

class A {
public $prop = 42;
}

const A_prop = (new A)->prop;

?>
--EXPECTF--
Fatal error: Uncaught Error: Fetching properties on non-enums in constant expressions is not allowed in %s:%d
Stack trace:
#0 {main}
thrown in %s on line %d
26 changes: 26 additions & 0 deletions Zend/tests/prop_const_expr/non_enums_catchable.phpt
@@ -0,0 +1,26 @@
--TEST--
RHS gets evaluated before throwing error when accessing properties on non-enums in constant expressions
--FILE--
<?php

class A {
public $prop = 42;
}

class Printer {
public function __construct() {
echo "Printer\n";
return 'printer';
}
}

const A_prop = (new A)->{new Printer ? 'printer' : null};

?>
--EXPECTF--
Printer

Fatal error: Uncaught Error: Fetching properties on non-enums in constant expressions is not allowed in %s:%d
Stack trace:
#0 {main}
thrown in %s on line %d
18 changes: 18 additions & 0 deletions Zend/tests/prop_const_expr/non_enums_cost.phpt
@@ -0,0 +1,18 @@
--TEST--
Disallow fetching properties in constant expressions on non-enums even if lhs is other const
--FILE--
<?php

class A {
public $prop = 42;
}

const A = new A();
const A_prop = A->prop;

?>
--EXPECTF--
Fatal error: Uncaught Error: Fetching properties on non-enums in constant expressions is not allowed in %s:%d
Stack trace:
#0 {main}
thrown in %s on line %d
17 changes: 17 additions & 0 deletions Zend/tests/prop_const_expr/non_enums_nullsafe.phpt
@@ -0,0 +1,17 @@
--TEST--
Disallow nullsafe fetching properties in constant expressions on non-enums
--FILE--
<?php

class A {
public $prop = 42;
}

const A_prop = (new A)?->prop;

?>
--EXPECTF--
Fatal error: Uncaught Error: Fetching properties on non-enums in constant expressions is not allowed in %s:%d
Stack trace:
#0 {main}
thrown in %s on line %d
26 changes: 26 additions & 0 deletions Zend/tests/prop_const_expr/non_enums_rhs.phpt
@@ -0,0 +1,26 @@
--TEST--
Error when fetching properties on non-enums in constant expressions is catchable
--FILE--
<?php

class A {
public $prop = 42;
}

function foo($prop = (new A)->prop) {}

function test() {
try {
foo();
} catch (Error $e) {
echo $e->getMessage(), "\n";
}
}

test();
test();

?>
--EXPECT--
Fetching properties on non-enums in constant expressions is not allowed
Fetching properties on non-enums in constant expressions is not allowed

0 comments on commit 7aadbcb

Please sign in to comment.