Skip to content

Support new in initializers #6746

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 6 commits 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
17 changes: 8 additions & 9 deletions Zend/tests/array_unpack/classes.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -9,21 +9,21 @@ class C {
public static $bar = [...self::ARR];
}

class D {
public const A = [...self::B];
public const B = [...self::A];
try {
class D {
public const A = [...self::B];
public const B = [...self::A];
}
} catch (Error $e) {
echo $e->getMessage(), "\n";
}

var_dump(C::FOO);
var_dump(C::$bar);

try {
var_dump(D::A);
} catch (Error $ex) {
echo "Exception: " . $ex->getMessage() . "\n";
}
?>
--EXPECT--
Cannot declare self-referencing constant self::B
array(5) {
[0]=>
int(0)
Expand All @@ -44,4 +44,3 @@ array(3) {
[2]=>
int(3)
}
Exception: Cannot declare self-referencing constant self::B
2 changes: 1 addition & 1 deletion Zend/tests/bug41633_2.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,4 @@ echo Foo::A."\n";
Fatal error: Uncaught Error: Undefined constant self::B in %s:%d
Stack trace:
#0 {main}
thrown in %sbug41633_2.php on line 5
thrown in %sbug41633_2.php on line 2
13 changes: 6 additions & 7 deletions Zend/tests/bug69832.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,19 @@ Bug #69832 (Assertion failed in zend_compile_const_expr_magic_const)
--FILE--
<?php

if (true) {
class Bar {
const A = 1;
}
}

class Test {
public $foo = [Bar::A, __CLASS__][__CLASS__ != ""];
public $bar = Bar::A && __CLASS__;
public $baz = Bar::A ?: __CLASS__;
public $buzz = Bar::A ? __CLASS__ : 0;
}

eval(<<<'PHP'
class Bar {
const A = 1;
}
PHP
);

$t = new Test;
var_dump($t->foo);
var_dump($t->bar);
Expand Down
18 changes: 9 additions & 9 deletions Zend/tests/bug78868.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,15 @@
Bug #78868: Calling __autoload() with incorrect EG(fake_scope) value
--FILE--
<?php

function main_autoload($class_name) {
$c = new C;
$c->foo();
//doesn't affect the error
eval("class B {const foo = 1;}");
}
spl_autoload_register('main_autoload');

class C {
private $private = 1;

Expand All @@ -14,15 +23,6 @@ class A {
static $foo = B::foo; //not resolved on include()
}

function main_autoload($class_name) {
$c = new C;
$c->foo();
//doesn't affect the error
eval("class B {const foo = 1;}");
}

spl_autoload_register('main_autoload');

$classA = new ReflectionClass("A");
$props = $classA->getProperties();
$props[0]->setValue(2); //causes constant resolving, which runs autoload, all with EG(fake_scope) == "A"
Expand Down
43 changes: 43 additions & 0 deletions Zend/tests/constexpr/evaluation_error.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
--TEST--
Error during evaluation of static/constants
--FILE--
<?php

try {
class A {
public const C = 42;
public static $s1 = UNKNOWN;
public static $s2 = 42;
}
} catch (Error $e) {
echo $e->getMessage(), "\n";
}
try {
var_dump(A::$s2);
} catch (Error $e) {
echo $e->getMessage(), "\n";
}
try {
var_dump(new A);
} catch (Error $e) {
echo $e->getMessage(), "\n";
}
try {
var_dump(new A);
} catch (Error $e) {
echo $e->getMessage(), "\n";
}
try {
// TODO: Should this fail?
var_dump(A::C);
} catch (Error $e) {
echo $e->getMessage(), "\n";
}

?>
--EXPECT--
Undefined constant "UNKNOWN"
Trying to use class for which initializer evaluation has previously failed
Trying to use class for which initializer evaluation has previously failed
Trying to use class for which initializer evaluation has previously failed
int(42)
45 changes: 45 additions & 0 deletions Zend/tests/constexpr/evaluation_order.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
--TEST--
Evaluation order of initializers in class declaration
--FILE--
<?php

class Order {
public function __construct(int $i) {
echo "Creating $i\n";
}
}

class A {
const C1 = new Order(1);
public static $s1 = new Order(3);
public $p1 = new Order(10);
const C2 = new Order(2);
public static $s2 = new Order(4);
public $p2 = new Order(11);
}
class B extends A {
const C3 = new Order(5);
public static $s3 = new Order(6);
public $p3 = new Order(12);
}

echo "\n";
new A;
echo "\n";
new B;

?>
--EXPECT--
Creating 1
Creating 2
Creating 3
Creating 4
Creating 5
Creating 6

Creating 10
Creating 11

Creating 10
Creating 11
Creating 12
62 changes: 62 additions & 0 deletions Zend/tests/constexpr/new.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
--TEST--
new in constant expressions
--FILE--
<?php

try {
eval('const A = new DoesNotExist;');
} catch (Error $e) {
echo $e->getMessage(), "\n";
}

const B = new stdClass;
var_dump(B);

try {
eval('const C = new stdClass([] + 0);');
} catch (Error $e) {
echo $e->getMessage(), "\n";
}

class Test {
public function __construct(public $a, public $b) {}
}

try {
eval('const D = new Test(new stdClass, [] + 0);');
} catch (Error $e) {
echo $e->getMessage(), "\n";
}

const E = new Test(new stdClass, 42);
var_dump(E);

class Test2 {
public function __construct() {
echo "Side-effect\n";
throw new Exception("Failed to construct");
}
}

try {
eval('const F = new Test2();');
} catch (Exception $e) {
echo $e->getMessage(), "\n";
}

?>
--EXPECT--
Class "DoesNotExist" not found
object(stdClass)#2 (0) {
}
Unsupported operand types: array + int
Unsupported operand types: array + int
object(Test)#4 (2) {
["a"]=>
object(stdClass)#1 (0) {
}
["b"]=>
int(42)
}
Side-effect
Failed to construct
10 changes: 10 additions & 0 deletions Zend/tests/constexpr/new_anon_class.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
--TEST--
New with anonymous class is not supported in constant expressions
--FILE--
<?php

const X = new class {};

?>
--EXPECTF--
Fatal error: Cannot use anonymous class in constant expression in %s on line %d
44 changes: 44 additions & 0 deletions Zend/tests/constexpr/new_arg_eval.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
--TEST--
Check that const exprs are pre-evaluated in new arguments
--FILE--
<?php

class C {
public function __construct(public $x) {}
}
function test(
$a = new C(__CLASS__),
$b = new C(__FUNCTION__),
$c = new C(x: __FILE__),
) {
var_dump($a, $b, $c);
}
test();

// Check that nested new works as well.
function test2($p = new C(new C(__FUNCTION__))) {
var_dump($p);
}
test2();

?>
--EXPECTF--
object(C)#1 (1) {
["x"]=>
string(0) ""
}
object(C)#2 (1) {
["x"]=>
string(4) "test"
}
object(C)#3 (1) {
["x"]=>
string(%d) "%snew_arg_eval.php"
}
object(C)#3 (1) {
["x"]=>
object(C)#2 (1) {
["x"]=>
string(5) "test2"
}
}
10 changes: 10 additions & 0 deletions Zend/tests/constexpr/new_arg_unpack.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
--TEST--
Argument unpacking in new arguments in const expr (not yet supported)
--FILE--
<?php

const X = new stdClass(...[0]);

?>
--EXPECTF--
Fatal error: Argument unpacking in constant expressions is not supported in %s on line %d
10 changes: 10 additions & 0 deletions Zend/tests/constexpr/new_dynamic_class_name.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
--TEST--
Dynamic class name in new is not supported
--FILE--
<?php

const FOO = new (BAR);

?>
--EXPECTF--
Fatal error: Cannot use dynamic class name in constant expression in %s on line %d
Loading