diff options
Diffstat (limited to 'Zend/tests')
294 files changed, 6803 insertions, 286 deletions
diff --git a/Zend/tests/001.phpt b/Zend/tests/001.phpt index bec7d8adbc..bbd4ea3ece 100644 --- a/Zend/tests/001.phpt +++ b/Zend/tests/001.phpt @@ -17,11 +17,20 @@ function test3($a, $b) { test1(); test2(1); -test2(); +try { + test2(); +} catch (Throwable $e) { + echo "Exception: " . $e->getMessage() . "\n"; +} + test3(1,2); call_user_func("test1"); -call_user_func("test3", 1); +try { + call_user_func("test3", 1); +} catch (Throwable $e) { + echo "Exception: " . $e->getMessage() . "\n"; +} call_user_func("test3", 1, 2); class test { @@ -38,14 +47,10 @@ echo "Done\n"; --EXPECTF-- int(0) int(1) - -Warning: Missing argument 1 for test2(), called in %s on line %d -int(0) +Exception: Too few arguments to function test2(), 0 passed in %s001.php on line 18 and exactly 1 expected int(2) int(0) - -Warning: Missing argument 2 for test3()%s -int(1) +Exception: Too few arguments to function test3(), 1 passed in %s001.php on line 27 and exactly 2 expected int(2) int(1) diff --git a/Zend/tests/002.phpt b/Zend/tests/002.phpt index b01c7fa329..1728330c08 100644 --- a/Zend/tests/002.phpt +++ b/Zend/tests/002.phpt @@ -23,11 +23,19 @@ function test3($a, $b) { test1(); test1(10); test2(1); -test2(); +try { + test2(); +} catch (Throwable $e) { + echo "Exception: " . $e->getMessage() . "\n"; +} test3(1,2); call_user_func("test1"); -call_user_func("test3", 1); +try { + call_user_func("test3", 1); +} catch (Throwable $e) { + echo "Exception: " . $e->getMessage() . "\n"; +} call_user_func("test3", 1, 2); class test { @@ -62,14 +70,7 @@ int(1) Warning: func_get_arg(): Argument 1 not passed to function in %s on line %d bool(false) - -Warning: Missing argument 1 for test2(), called in %s on line %d and defined in %s on line %d - -Warning: func_get_arg(): Argument 0 not passed to function in %s on line %d -bool(false) - -Warning: func_get_arg(): Argument 1 not passed to function in %s on line %d -bool(false) +Exception: Too few arguments to function test2(), 0 passed in %s002.php on line %d and exactly 1 expected int(1) int(2) @@ -84,15 +85,7 @@ bool(false) Warning: func_get_arg(): Argument 1 not passed to function in %s on line %d bool(false) - -Warning: Missing argument 2 for test3()%s -int(1) - -Warning: func_get_arg(): Argument 1 not passed to function in %s on line %d -bool(false) - -Warning: func_get_arg(): Argument 2 not passed to function in %s on line %d -bool(false) +Exception: Too few arguments to function test3(), 1 passed in %s002.php on line %d and exactly 2 expected int(1) int(2) diff --git a/Zend/tests/003.phpt b/Zend/tests/003.phpt index 5c3b83d25e..91daa705d3 100644 --- a/Zend/tests/003.phpt +++ b/Zend/tests/003.phpt @@ -18,11 +18,19 @@ function test3($a, $b) { test1(); test1(10); test2(1); -test2(); +try { + test2(); +} catch (Throwable $e) { + echo "Exception: " . $e->getMessage() . "\n"; +} test3(1,2); call_user_func("test1"); -call_user_func("test3", 1); +try { + call_user_func("test3", 1); +} catch (Throwable $e) { + echo "Exception: " . $e->getMessage() . "\n"; +} call_user_func("test3", 1, 2); class test { @@ -47,10 +55,7 @@ array(1) { [0]=> int(1) } - -Warning: Missing argument 1 for test2(), called in %s on line %d and defined in %s on line %d -array(0) { -} +Exception: Too few arguments to function test2(), 0 passed in %s003.php on line %d and exactly 1 expected array(2) { [0]=> int(1) @@ -59,12 +64,7 @@ array(2) { } array(0) { } - -Warning: Missing argument 2 for test3()%s -array(1) { - [0]=> - int(1) -} +Exception: Too few arguments to function test3(), 1 passed in %s003.php on line %d and exactly 2 expected array(2) { [0]=> int(1) diff --git a/Zend/tests/030.phpt b/Zend/tests/030.phpt index 8afcb66bd8..2318420319 100644 --- a/Zend/tests/030.phpt +++ b/Zend/tests/030.phpt @@ -31,40 +31,4 @@ $test->bar(); ?> --EXPECTF-- -object(Exception)#%d (7) { - ["message":protected]=> - string(3) "foo" - ["string":"Exception":private]=> - string(0) "" - ["code":protected]=> - int(0) - ["file":protected]=> - string(%d) "%s030.php" - ["line":protected]=> - int(%d) - ["trace":"Exception":private]=> - array(1) { - [0]=> - array(6) { - ["file"]=> - string(%d) "%s030.php" - ["line"]=> - int(%d) - ["function"]=> - string(3) "bar" - ["class"]=> - string(3) "foo" - ["type"]=> - string(2) "->" - ["args"]=> - array(0) { - } - } - } - ["previous":"Exception":private]=> - NULL -} -'test' => '0' -'test_2' => '1' -'test_3' => '2' -ok +Fatal error: Cannot re-assign $this in %s030.php on line 11 diff --git a/Zend/tests/add_006.phpt b/Zend/tests/add_006.phpt index d56df2f329..fe1c0830e2 100644 --- a/Zend/tests/add_006.phpt +++ b/Zend/tests/add_006.phpt @@ -38,11 +38,19 @@ var_dump($c); echo "Done\n"; ?> --EXPECTF-- + +Warning: A non-numeric value encountered in %s on line %d int(75636) + +Notice: A non well formed numeric value encountered in %s on line %d int(951858) int(48550510) float(75661.68) + +Warning: A non-numeric value encountered in %s on line %d int(75636) + +Notice: A non well formed numeric value encountered in %s on line %d int(951858) int(48550510) float(75661.68) diff --git a/Zend/tests/add_007.phpt b/Zend/tests/add_007.phpt index 66f5405706..089b24ae0b 100644 --- a/Zend/tests/add_007.phpt +++ b/Zend/tests/add_007.phpt @@ -19,8 +19,13 @@ var_dump($c); echo "Done\n"; ?> --EXPECTF-- + +Warning: A non-numeric value encountered in %s on line %d + Exception: Unsupported operand types +Warning: A non-numeric value encountered in %s on line %d + Fatal error: Uncaught Error: Unsupported operand types in %s:%d Stack trace: #0 {main} diff --git a/Zend/tests/anon/013.phpt b/Zend/tests/anon/013.phpt new file mode 100644 index 0000000000..72ba3d61b7 --- /dev/null +++ b/Zend/tests/anon/013.phpt @@ -0,0 +1,15 @@ +--TEST-- +closure binding to anonymous class +--FILE-- +<?php +$class = new class {}; +$foo = function() { + return $this; +}; + +$closure = Closure::bind($foo, $class, $class); +var_dump($closure()); +?> +--EXPECTF-- +object(class@anonymous)#1 (0) { +} diff --git a/Zend/tests/anon/014.phpt b/Zend/tests/anon/014.phpt new file mode 100644 index 0000000000..cacac47857 --- /dev/null +++ b/Zend/tests/anon/014.phpt @@ -0,0 +1,16 @@ +--TEST-- +anonymous class trait binding +--FILE-- +<?php +trait TaskTrait { + function run() { + return 'Running...'; + } +} +$class = new class() { + use TaskTrait; +}; +var_dump($class->run()); +?> +--EXPECTF-- +string(10) "Running..." diff --git a/Zend/tests/assert/expect_015.phpt b/Zend/tests/assert/expect_015.phpt index 030913f7f9..1679640851 100644 --- a/Zend/tests/assert/expect_015.phpt +++ b/Zend/tests/assert/expect_015.phpt @@ -20,7 +20,7 @@ assert(0 && ($a = function () { yield from $x; })); -assert(0 && ($a = function &(array &$a, X $b = null) use ($c,&$d) : X { +assert(0 && ($a = function &(array &$a, ?X $b = null) use ($c,&$d) : ?X { abstract class A extends B implements C, D { const X = 12; const Y = self::X, Z = "aaa"; @@ -154,14 +154,14 @@ Warning: assert(): assert(0 && ($a = function () { $x = $a ? $b : $c; $x = $a ?: $c; $x = $a ?? $b; - list($a, $b, $c) = [1, 2 => 'x', 'z' => 'c']; + [$a, $b, $c] = [1, 2 => 'x', 'z' => 'c']; @foo(); $y = clone $x; yield 1 => 2; yield from $x; })) failed in %sexpect_015.php on line %d -Warning: assert(): assert(0 && ($a = function &(array &$a, X $b = null) use($c, &$d): X { +Warning: assert(): assert(0 && ($a = function &(array &$a, ?X $b = null) use($c, &$d): ?X { abstract class A extends B implements C, D { const X = 12; const Y = self::X, Z = 'aaa'; diff --git a/Zend/tests/assert/indirect_var_access_misoptimization.phpt b/Zend/tests/assert/indirect_var_access_misoptimization.phpt new file mode 100644 index 0000000000..61c193ab60 --- /dev/null +++ b/Zend/tests/assert/indirect_var_access_misoptimization.phpt @@ -0,0 +1,19 @@ +--TEST-- +Misoptimization when variable is modified by assert() +--INI-- +zend.assertions=1 +--FILE-- +<?php + +function test() { + $i = 0; + assert('$i = new stdClass'); + $i += 1; + var_dump($i); +} +test(); + +?> +--EXPECTF-- +Notice: Object of class stdClass could not be converted to int in %s on line %d +int(2) diff --git a/Zend/tests/assign_dim_obj_null_return.phpt b/Zend/tests/assign_dim_obj_null_return.phpt new file mode 100644 index 0000000000..e833ef3591 --- /dev/null +++ b/Zend/tests/assign_dim_obj_null_return.phpt @@ -0,0 +1,56 @@ +--TEST-- +Various null return conditions of dim/obj assignments +--FILE-- +<?php + +function test() { + $array = [PHP_INT_MAX => 42]; + $true = true; + + var_dump($array[] = 123); + var_dump($array[[]] = 123); + var_dump($array[new stdClass] = 123); + var_dump($true[123] = 456); + + var_dump($array[] += 123); + var_dump($array[[]] += 123); + var_dump($array[new stdClass] += 123); + var_dump($true[123] += 456); + + var_dump($true->foo = 123); + var_dump($true->foo += 123); +} + +test(); + +?> +--EXPECTF-- +Warning: Cannot add element to the array as the next element is already occupied in %s on line %d +NULL + +Warning: Illegal offset type in %s on line %d +NULL + +Warning: Illegal offset type in %s on line %d +NULL + +Warning: Cannot use a scalar value as an array in %s on line %d +NULL + +Warning: Cannot add element to the array as the next element is already occupied in %s on line %d +NULL + +Warning: Illegal offset type in %s on line %d +NULL + +Warning: Illegal offset type in %s on line %d +NULL + +Warning: Cannot use a scalar value as an array in %s on line %d +NULL + +Warning: Attempt to assign property of non-object in %s on line %d +NULL + +Warning: Attempt to assign property of non-object in %s on line %d +NULL diff --git a/Zend/tests/bug29015.phpt b/Zend/tests/bug29015.phpt index a36ed923f3..d4231d10b1 100644 --- a/Zend/tests/bug29015.phpt +++ b/Zend/tests/bug29015.phpt @@ -6,9 +6,16 @@ $a = new stdClass(); $x = ""; $a->$x = "string('')"; var_dump($a); +$a->{"\0"} = 42; +var_dump($a); ?> --EXPECTF-- -Fatal error: Uncaught Error: Cannot access empty property in %sbug29015.php:4 +object(stdClass)#1 (1) { + [""]=> + string(10) "string('')" +} + +Fatal error: Uncaught Error: Cannot access property started with '\0' in %s:%d Stack trace: #0 {main} - thrown in %sbug29015.php on line 4 + thrown in %s on line %d diff --git a/Zend/tests/bug29368_1.phpt b/Zend/tests/bug29368_1.phpt new file mode 100644 index 0000000000..09cf334384 --- /dev/null +++ b/Zend/tests/bug29368_1.phpt @@ -0,0 +1,29 @@ +--TEST-- +Bug #29368.1 (The destructor is called when an exception is thrown from the constructor). +--FILE-- +<?php +function throwme($arg) +{ + throw new Exception; +} + +class foo { + function __construct() { + echo "Inside constructor\n"; + throwme($this); + } + + function __destruct() { + echo "Inside destructor\n"; + } +} + +try { + $bar = new foo; +} catch(Exception $exc) { + echo "Caught exception!\n"; +} +?> +--EXPECT-- +Inside constructor +Caught exception! diff --git a/Zend/tests/bug29883.phpt b/Zend/tests/bug29883.phpt index c92f147ff7..b6ad99aeaf 100644 --- a/Zend/tests/bug29883.phpt +++ b/Zend/tests/bug29883.phpt @@ -3,7 +3,7 @@ Bug #29883 (isset gives invalid values on strings) --FILE-- <?php $x = "bug"; -var_dump(isset($x[-1])); +var_dump(isset($x[-10])); var_dump(isset($x["1"])); echo $x["1"]."\n"; ?> diff --git a/Zend/tests/bug31098.phpt b/Zend/tests/bug31098.phpt index 23cec9bbf4..31823a1aa5 100644 --- a/Zend/tests/bug31098.phpt +++ b/Zend/tests/bug31098.phpt @@ -18,7 +18,7 @@ var_dump(isset($a['b'])); $simpleString = "Bogus String Text"; echo isset($simpleString->wrong)?"bug\n":"ok\n"; echo isset($simpleString["wrong"])?"bug\n":"ok\n"; -echo isset($simpleString[-1])?"bug\n":"ok\n"; +echo isset($simpleString[-20])?"bug\n":"ok\n"; echo isset($simpleString[0])?"ok\n":"bug\n"; echo isset($simpleString["0"])?"ok\n":"bug\n"; echo isset($simpleString["16"])?"ok\n":"bug\n"; diff --git a/Zend/tests/bug33996.phpt b/Zend/tests/bug33996.phpt index c399ee9975..3936eb8845 100644 --- a/Zend/tests/bug33996.phpt +++ b/Zend/tests/bug33996.phpt @@ -19,15 +19,19 @@ function NormalTest($a) echo "Hi!"; } -NormalTest(); -FooTest(); +try { + NormalTest(); +} catch (Throwable $e) { + echo "Exception: " . $e->getMessage() . "\n"; +} +try { + FooTest(); +} catch (Throwable $e) { + echo "Exception: " . $e->getMessage() . "\n"; +} FooTest(new Foo()); ?> --EXPECTF-- -Warning: Missing argument 1 for NormalTest(), called in %sbug33996.php on line %d and defined in %sbug33996.php on line %d -Hi! -Fatal error: Uncaught TypeError: Argument 1 passed to FooTest() must be an instance of Foo, none given, called in %sbug33996.php on line %d and defined in %sbug33996.php:%d -Stack trace: -#0 %s(%d): FooTest() -#1 {main} - thrown in %sbug33996.php on line %d +Exception: Too few arguments to function NormalTest(), 0 passed in %sbug33996.php on line 18 and exactly 1 expected +Exception: Too few arguments to function FooTest(), 0 passed in %sbug33996.php on line 23 and exactly 1 expected +Hello! diff --git a/Zend/tests/bug38047.phpt b/Zend/tests/bug38047.phpt index 5e7b3efc94..e6eeb6631d 100644 --- a/Zend/tests/bug38047.phpt +++ b/Zend/tests/bug38047.phpt @@ -43,7 +43,9 @@ Non-static method A::A_ftk() should not be called statically 1 %sbug38047.php:13 get_error_context() 2 %sbug38047.php:36 kalus_error_handler() -Missing argument 1 for A::A_ftk(), called in %sbug38047.php on line 36 and defined -1 %sbug38047.php:13 get_error_context() -2 %sbug38047.php:7 kalus_error_handler() -3 %sbug38047.php:36 A_ftk() + +Fatal error: Uncaught ArgumentCountError: Too few arguments to function A::A_ftk(), 0 passed in %sbug38047.php on line 36 and exactly 1 expected in %sbug38047.php:7 +Stack trace: +#0 %sbug38047.php(36): A::A_ftk() +#1 {main} + thrown in %sbug38047.php on line 7 diff --git a/Zend/tests/bug41813.phpt b/Zend/tests/bug41813.phpt index 0bb693075a..9a609d09c8 100644 --- a/Zend/tests/bug41813.phpt +++ b/Zend/tests/bug41813.phpt @@ -9,7 +9,7 @@ $foo[0]->bar = "xyz"; echo "Done\n"; ?> --EXPECTF-- -Fatal error: Uncaught Error: Cannot use string offset as an array in %s:%d +Fatal error: Uncaught Error: Cannot use string offset as an object in %s:%d Stack trace: #0 {main} thrown in %s on line %d diff --git a/Zend/tests/bug49866.phpt b/Zend/tests/bug49866.phpt index 3d96a59cd5..0b7c224c01 100644 --- a/Zend/tests/bug49866.phpt +++ b/Zend/tests/bug49866.phpt @@ -7,7 +7,7 @@ $b = &$a[1]; $b = "f"; echo $a; --EXPECTF-- -Fatal error: Uncaught Error: Cannot create references to/from string offsets nor overloaded objects in %sbug49866.php:3 +Fatal error: Uncaught Error: Cannot create references to/from string offsets in %sbug49866.php:3 Stack trace: #0 {main} thrown in %sbug49866.php on line 3 diff --git a/Zend/tests/bug52484.phpt b/Zend/tests/bug52484.phpt index 053529614d..1d2c2d7cdc 100644 --- a/Zend/tests/bug52484.phpt +++ b/Zend/tests/bug52484.phpt @@ -10,14 +10,14 @@ class A { } $a = new A(); -$prop = null; +$prop = "\0"; unset($a->$prop); ?> --EXPECTF-- -Fatal error: Uncaught Error: Cannot access empty property in %s:%d +Fatal error: Uncaught Error: Cannot access property started with '\0' in %s:%d Stack trace: -#0 %s(%d): A->__unset('') +#0 %s(%d): A->__unset('\x00') #1 {main} thrown in %s on line %d diff --git a/Zend/tests/bug52484_2.phpt b/Zend/tests/bug52484_2.phpt index 6bb927535c..3b12950c66 100644 --- a/Zend/tests/bug52484_2.phpt +++ b/Zend/tests/bug52484_2.phpt @@ -10,14 +10,14 @@ class A { } $a = new A(); -$prop = null; +$prop = "\0"; $a->$prop = 2; ?> --EXPECTF-- -Fatal error: Uncaught Error: Cannot access empty property in %s:%d +Fatal error: Uncaught Error: Cannot access property started with '\0' in %s:%d Stack trace: -#0 %s(%d): A->__set('', 2) +#0 %s(%d): A->__set('\x00', 2) #1 {main} thrown in %s on line %d diff --git a/Zend/tests/bug52484_3.phpt b/Zend/tests/bug52484_3.phpt index af32bc9be7..408dd453fd 100644 --- a/Zend/tests/bug52484_3.phpt +++ b/Zend/tests/bug52484_3.phpt @@ -10,14 +10,14 @@ class A { } $a = new A(); -$prop = null; +$prop = "\0"; var_dump($a->$prop); ?> --EXPECTF-- -Fatal error: Uncaught Error: Cannot access empty property in %s:%d +Fatal error: Uncaught Error: Cannot access property started with '\0' in %s:%d Stack trace: -#0 %s(%d): A->__get('') +#0 %s(%d): A->__get('\x00') #1 {main} thrown in %s on line %d diff --git a/Zend/tests/bug52879.phpt b/Zend/tests/bug52879.phpt index 0193be4b45..6c3232f32d 100644 --- a/Zend/tests/bug52879.phpt +++ b/Zend/tests/bug52879.phpt @@ -8,7 +8,7 @@ class MyClass { $this->myRef = $value; } } -$myGlobal=new MyClass($myGlobal); +$myGlobal=new MyClass(); $myGlobal->myRef=&$myGlobal; $myGlobal->myNonExistentProperty="ok\n"; echo $myGlobal; diff --git a/Zend/tests/bug53432.phpt b/Zend/tests/bug53432.phpt new file mode 100644 index 0000000000..83df599313 --- /dev/null +++ b/Zend/tests/bug53432.phpt @@ -0,0 +1,65 @@ +--TEST-- +Bug #53432: Assignment via string index access on an empty string converts to array +--FILE-- +<?php + +$str = ''; +var_dump($str[0] = 'a'); +var_dump($str); + +$str = ''; +var_dump($str[5] = 'a'); +var_dump($str); + +$str = ''; +var_dump($str[-1] = 'a'); +var_dump($str); + +$str = ''; +var_dump($str['foo'] = 'a'); +var_dump($str); + +$str = ''; +try { + var_dump($str[] = 'a'); +} catch (Error $e) { + echo "Error: {$e->getMessage()}\n"; +} +var_dump($str); + +$str = ''; +try { + var_dump($str[0] += 1); +} catch (Error $e) { + echo "Error: {$e->getMessage()}\n"; +} +var_dump($str); + +$str = ''; +try { + var_dump($str[0][0] = 'a'); +} catch (Error $e) { + echo "Error: {$e->getMessage()}\n"; +} +var_dump($str); + +?> +--EXPECTF-- +string(1) "a" +string(1) "a" +string(1) "a" +string(6) " a" + +Warning: Illegal string offset: -1 in %s on line %d +NULL +string(0) "" + +Warning: Illegal string offset 'foo' in %s on line %d +string(1) "a" +string(1) "a" +Error: [] operator not supported for strings +string(0) "" +Error: Cannot use assign-op operators with string offsets +string(0) "" +Error: Cannot use string offset as an array +string(0) "" diff --git a/Zend/tests/bug55705.phpt b/Zend/tests/bug55705.phpt index f051bca6dc..06811bbc1b 100644 --- a/Zend/tests/bug55705.phpt +++ b/Zend/tests/bug55705.phpt @@ -6,7 +6,7 @@ function f(callable $c) {} f(); ?> --EXPECTF-- -Fatal error: Uncaught TypeError: Argument 1 passed to f() must be callable, none given, called in %s on line 3 and defined in %s:%d +Fatal error: Uncaught ArgumentCountError: Too few arguments to function f(), 0 passed in %s on line 3 and exactly 1 expected in %s:2 Stack trace: #0 %s(%d): f() #1 {main} diff --git a/Zend/tests/bug62814.phpt b/Zend/tests/bug62814.phpt new file mode 100644 index 0000000000..6646aa283f --- /dev/null +++ b/Zend/tests/bug62814.phpt @@ -0,0 +1,20 @@ +--TEST-- +Bug #62814: It is possible to stiffen child class members visibility +--FILE-- +<?php + +class A { + private function test() { } +} + +class B extends A { + protected function test() { } +} + +class C extends B { + private function test() { } +} + +?> +--EXPECTF-- +Fatal error: Access level to C::test() must be protected (as in class B) or weaker in %s on line %d diff --git a/Zend/tests/bug63734.phpt b/Zend/tests/bug63734.phpt index 8e5ee6d4ac..b68577d494 100644 --- a/Zend/tests/bug63734.phpt +++ b/Zend/tests/bug63734.phpt @@ -1,5 +1,7 @@ --TEST-- Bug #63734 (Garbage collector can free zvals that are still referenced) +--INI-- +zend.enable_gc = 1 --FILE-- <?php class C { diff --git a/Zend/tests/bug65784.phpt b/Zend/tests/bug65784.phpt index c079b3d282..663ea95761 100644 --- a/Zend/tests/bug65784.phpt +++ b/Zend/tests/bug65784.phpt @@ -57,8 +57,13 @@ $bar = foo3(); string(9) "not catch" NULL -Fatal error: Uncaught Error: Class 'NotExists' not found in %sbug65784.php:%d +Fatal error: Uncaught Exception: not catched in %sbug65784.php:42 Stack trace: -#0 %s(%d): foo3() +#0 %sbug65784.php(52): foo3() #1 {main} - thrown in %sbug65784.php on line %d + +Next Error: Class 'NotExists' not found in %sbug65784.php:46 +Stack trace: +#0 %sbug65784.php(52): foo3() +#1 {main} + thrown in %sbug65784.php on line 46 diff --git a/Zend/tests/bug68370.phpt b/Zend/tests/bug68370.phpt index 25589bf455..73411ca9b9 100644 --- a/Zend/tests/bug68370.phpt +++ b/Zend/tests/bug68370.phpt @@ -13,6 +13,4 @@ $x = $c->test(); print_r($x); unset($c, $x); --EXPECTF-- -Array -( -) +Fatal error: Cannot unset $this in %sbug68370.php on line 4 diff --git a/Zend/tests/bug68652.phpt b/Zend/tests/bug68652.phpt index e86312ba63..8e54af2e34 100644 --- a/Zend/tests/bug68652.phpt +++ b/Zend/tests/bug68652.phpt @@ -28,6 +28,7 @@ class Bar { } public function __destruct() { + if (!isset(self::$instance)) return; Foo::getInstance(); } } diff --git a/Zend/tests/bug69446.phpt b/Zend/tests/bug69446.phpt index b448a2be7d..66595c170c 100644 --- a/Zend/tests/bug69446.phpt +++ b/Zend/tests/bug69446.phpt @@ -1,5 +1,7 @@ --TEST-- Bug #69446 (GC leak relating to removal of nested data after dtors run) +--INI-- +zend.enable_gc = 1 --FILE-- <?php $bar = NULL; diff --git a/Zend/tests/bug69446_2.phpt b/Zend/tests/bug69446_2.phpt index 520bd1fe30..b7c6e0e329 100644 --- a/Zend/tests/bug69446_2.phpt +++ b/Zend/tests/bug69446_2.phpt @@ -1,5 +1,7 @@ --TEST-- Bug #69446 (GC leak relating to removal of nested data after dtors run) +--INI-- +zend.enable_gc = 1 --FILE-- <?php $bar = NULL; diff --git a/Zend/tests/bug69534.phpt b/Zend/tests/bug69534.phpt index 1f0275485e..adf7b06617 100644 --- a/Zend/tests/bug69534.phpt +++ b/Zend/tests/bug69534.phpt @@ -1,5 +1,7 @@ --TEST-- Bug #69534 (Cycle leaks through declared properties on internal classes) +--INI-- +zend.enable_gc = 1 --FILE-- <?php class Node extends SplObjectStorage { diff --git a/Zend/tests/bug69676_2.phpt b/Zend/tests/bug69676_2.phpt new file mode 100644 index 0000000000..6ec3d499e5 --- /dev/null +++ b/Zend/tests/bug69676_2.phpt @@ -0,0 +1,22 @@ +--TEST-- +Bug #69676: Resolution of self::FOO in class constants not correct (variation) +--FILE-- +<?php + +class Foo { + const A = 'Foo::A'; + const B = self::A . ' and ' . self::C; + const C = 'Foo::C'; + +} + +class Bar extends Foo { + const A = 'Bar::A'; + const C = 'Bar::C'; +} + +var_dump(Bar::B); + +?> +--EXPECT-- +string(17) "Foo::A and Foo::C" diff --git a/Zend/tests/bug69676_3.phpt b/Zend/tests/bug69676_3.phpt new file mode 100644 index 0000000000..89f0090884 --- /dev/null +++ b/Zend/tests/bug69676_3.phpt @@ -0,0 +1,69 @@ +--TEST-- +Bug #69676: Resolution of self::FOO in class constants not correct (variation) +--FILE-- +<?php + +class P { + const N = 'P'; +} +class A extends P { + const selfN = self::N; + const parentN = parent::N; + const N = 'A'; +} +class B extends A { + const N = 'B'; +} + +var_dump(B::selfN); // A +var_dump(B::parentN); // P + +class A2 { + const selfN = self::N; + const N = 'A2'; +} +class B2 extends A2 { + const indSelfN = self::selfN; + const N = 'B2'; +} +class C2 extends B2 { + const N = 'C2'; +} + +var_dump(C2::indSelfN); // A2 + +class A3 { + const selfN = self::N; + const N = 'A3'; +} +class B3 extends A3 { + const exprSelfN = "expr" . self::selfN; + const N = 'B3'; +} +class C3 extends B3 { + const N = 'C3'; +} + +var_dump(C3::exprSelfN); // exprA3 + +class A4 { + const selfN = self::N; + const N = 'A4'; +} +class B4 extends A4 { + const N = 'B4'; + public $prop = self::selfN; +} +class C4 extends B4 { + const N = 'C4'; +} + +var_dump((new C4)->prop); // A4 + +?> +--EXPECT-- +string(1) "A" +string(1) "P" +string(2) "A2" +string(6) "exprA3" +string(2) "A4" diff --git a/Zend/tests/bug69989_2.phpt b/Zend/tests/bug69989_2.phpt new file mode 100644 index 0000000000..a6f320da3b --- /dev/null +++ b/Zend/tests/bug69989_2.phpt @@ -0,0 +1,42 @@ +--TEST-- +Collection of some cycles on unfinished generators +--FILE-- +<?php + +// CV +function gen1() { + $gen = yield; + yield; +} + +$gen = gen1(); +$gen->send($gen); + +// This +class Test { + public $gen; + public function gen2() { + yield; + } +} + +$test = new Test; +$test->gen = $test->gen2(); + +// Closure object +$gen3 = (function() use (&$gen3) { + yield; +})(); + +// Yield from array +function gen4() { + yield from [yield]; +} + +$gen = gen4(); +$gen->send($gen); + +?> +===DONE=== +--EXPECT-- +===DONE=== diff --git a/Zend/tests/bug69989_3.phpt b/Zend/tests/bug69989_3.phpt new file mode 100644 index 0000000000..260819197b --- /dev/null +++ b/Zend/tests/bug69989_3.phpt @@ -0,0 +1,44 @@ +--TEST-- +Generator cycle collection edge cases +--FILE-- +<?php + +// Extra args +function gen1() { + yield; +} +$obj = new stdClass; +$obj->gen = gen1($obj); + +// Symtable +function gen2() { + $varName = 'a'; + $$varName = yield; + yield; +} +$gen = gen2(); +$gen->send($gen); + +// Symtable indirect +function gen3() { + $varName = 'a'; + $$varName = 42; + $var = yield; + yield; +} +$gen = gen3(); +$gen->send($gen); + +// Yield from root +function gen4() { + yield from yield; +} +$gen = gen4(); +$gen2 = gen4($gen); +$gen2->send([1, 2, 3]); +$gen->send($gen2); + +?> +===DONE=== +--EXPECT-- +===DONE=== diff --git a/Zend/tests/bug70089.phpt b/Zend/tests/bug70089.phpt index c61db00c9e..e1884d9dac 100644 --- a/Zend/tests/bug70089.phpt +++ b/Zend/tests/bug70089.phpt @@ -34,4 +34,4 @@ try { string(36) "Cannot use string offset as an array" string(27) "Cannot unset string offsets" string(41) "Only variables can be passed by reference" -string(64) "Cannot increment/decrement overloaded objects nor string offsets" +string(41) "Cannot increment/decrement string offsets" diff --git a/Zend/tests/bug70685.phpt b/Zend/tests/bug70685.phpt index 7a49ff1825..8ae97f1bf0 100644 --- a/Zend/tests/bug70685.phpt +++ b/Zend/tests/bug70685.phpt @@ -15,7 +15,7 @@ var_dump($c); ?> --EXPECTF-- -Warning: Cannot bind internal method SplDoublyLinkedList::count() to object of class cls in %s on line %d +Warning: Cannot bind method SplDoublyLinkedList::count() to object of class cls in %s on line %d NULL Warning: Cannot rebind scope of closure created by ReflectionFunctionAbstract::getClosure() in %s on line %d diff --git a/Zend/tests/bug70689.phpt b/Zend/tests/bug70689.phpt index e3feeed9b0..882dd89b75 100644 --- a/Zend/tests/bug70689.phpt +++ b/Zend/tests/bug70689.phpt @@ -19,4 +19,8 @@ try { ?> --EXPECTF-- -Missing argument 1 for foo(), called in %sbug70689.php on line %d and defined +Fatal error: Uncaught ArgumentCountError: Too few arguments to function foo(), 0 passed in %sbug70689.php on line 12 and exactly 1 expected in %sbug70689.php:3 +Stack trace: +#0 %sbug70689.php(12): foo() +#1 {main} + thrown in %sbug70689.php on line 3 diff --git a/Zend/tests/bug70805_1.phpt b/Zend/tests/bug70805_1.phpt index 0225b4ce82..af57cdb5d9 100644 --- a/Zend/tests/bug70805_1.phpt +++ b/Zend/tests/bug70805_1.phpt @@ -1,5 +1,7 @@ --TEST-- Bug #70805 (Segmentation faults whilst running Drupal 8 test suite) (Crash) +--INI-- +zend.enable_gc = 1 --FILE-- <?php class A { diff --git a/Zend/tests/bug70805_2.phpt b/Zend/tests/bug70805_2.phpt index a9b11684f5..c878c83bbc 100644 --- a/Zend/tests/bug70805_2.phpt +++ b/Zend/tests/bug70805_2.phpt @@ -1,5 +1,7 @@ --TEST-- Bug #70805 (Segmentation faults whilst running Drupal 8 test suite) (Memleak) +--INI-- +zend.enable_gc = 1 --FILE-- <?php class A { diff --git a/Zend/tests/bug70918.phpt b/Zend/tests/bug70918.phpt new file mode 100644 index 0000000000..81e2192d8a --- /dev/null +++ b/Zend/tests/bug70918.phpt @@ -0,0 +1,47 @@ +--TEST-- +Bug #70918 (Segfault using static outside of class scope) +--FILE-- +<?php +try { + static::x; +} catch (Error $e) { + var_dump($e->getMessage()); +} + +try { + parent::x; +} catch (Error $e) { + var_dump($e->getMessage()); +} + +try { + self::x; +} catch (Error $e) { + var_dump($e->getMessage()); +} + +try { + new static; +} catch (Error $e) { + var_dump($e->getMessage()); +} + +try { + static::x(); +} catch (Error $e) { + var_dump($e->getMessage()); +} + +try { + static::$i; +} catch (Error $e) { + var_dump($e->getMessage()); +} +?> +--EXPECT-- +string(52) "Cannot access static:: when no class scope is active" +string(52) "Cannot access parent:: when no class scope is active" +string(50) "Cannot access self:: when no class scope is active" +string(52) "Cannot access static:: when no class scope is active" +string(52) "Cannot access static:: when no class scope is active" +string(52) "Cannot access static:: when no class scope is active" diff --git a/Zend/tests/bug71196.phpt b/Zend/tests/bug71196.phpt new file mode 100644 index 0000000000..ca25f9f4fc --- /dev/null +++ b/Zend/tests/bug71196.phpt @@ -0,0 +1,13 @@ +--TEST-- +Bug #71196 (Memory leak with out-of-order live ranges) +--FILE-- +<?php +try { + $a = "1"; + [1, (y().$a.$a) . ($a.$a)]; +} catch (Error $e) { + var_dump($e->getMessage()); +} +?> +--EXPECT-- +string(30) "Call to undefined function y()" diff --git a/Zend/tests/bug71266.phpt b/Zend/tests/bug71266.phpt new file mode 100644 index 0000000000..d67c6f6363 --- /dev/null +++ b/Zend/tests/bug71266.phpt @@ -0,0 +1,22 @@ +--TEST-- +Bug #71266 (Missing separation of properties HT in foreach etc) +--FILE-- +<?php +$one = 1; +$two = 2; +$arr = ['foo' => $one, 'bar' => $two]; +$obj = (object) $arr; +foreach ($obj as $val) { + var_dump($val); + $obj->bar = 42; +} + +$arr = ['foo' => $one, 'bar' => $two]; +$obj = (object) $arr; +next($obj); +var_dump(current($arr)); +?> +--EXPECT-- +int(1) +int(42) +int(1) diff --git a/Zend/tests/bug71428.1.phpt b/Zend/tests/bug71428.1.phpt index fbf342380f..e4d3a22f67 100644 --- a/Zend/tests/bug71428.1.phpt +++ b/Zend/tests/bug71428.1.phpt @@ -1,7 +1,5 @@ --TEST-- bug #71428.1: inheritance with null default values ---XFAIL-- -This is a BC break --FILE-- <?php class A { @@ -11,5 +9,5 @@ class B extends A { public function m(array $a = []) {} } --EXPECTF-- -Warning: Declaration of B::m(array $a = Array) should be compatible with A::m(array $a = NULL) in %sbug71428.1.php on line 7 +Warning: Declaration of B::m(array $a = Array) should be compatible with A::m(?array $a = NULL) in %sbug71428.1.php on line 7 diff --git a/Zend/tests/bug71428.3.phpt b/Zend/tests/bug71428.3.phpt index 65d397052e..558e87c56e 100644 --- a/Zend/tests/bug71428.3.phpt +++ b/Zend/tests/bug71428.3.phpt @@ -1,7 +1,5 @@ --TEST-- bug #71428: Validation type inheritance with = NULL ---XFAIL-- -This is a BC break --FILE-- <?php class A { } @@ -9,5 +7,5 @@ class B { public function m(A $a = NULL, $n) { echo "B.m";} }; class C extends B { public function m(A $a , $n) { echo "C.m";} }; ?> --EXPECTF-- -Warning: Declaration of C::m(A $a, $n) should be compatible with B::m(A $a = NULL, $n) in %sbug71428.3.php on line 4 +Warning: Declaration of C::m(A $a, $n) should be compatible with B::m(?A $a, $n) in %sbug71428.3.php on line 4 diff --git a/Zend/tests/bug71539.phpt b/Zend/tests/bug71539.phpt new file mode 100644 index 0000000000..16b5ed8358 --- /dev/null +++ b/Zend/tests/bug71539.phpt @@ -0,0 +1,16 @@ +--TEST-- +Bug #71539 (Memory error on $arr[$a] =& $arr[$b] if RHS rehashes) +--FILE-- +<?php +$array = []; +$array[0] =& $array['']; +$array[0] = 42; +var_dump($array); +?> +--EXPECT-- +array(2) { + [""]=> + &int(42) + [0]=> + &int(42) +} diff --git a/Zend/tests/bug71539_1.phpt b/Zend/tests/bug71539_1.phpt new file mode 100644 index 0000000000..935c9155a4 --- /dev/null +++ b/Zend/tests/bug71539_1.phpt @@ -0,0 +1,30 @@ +--TEST-- +Bug #71539.1 (Memory error on $arr[$a] =& $arr[$b] if RHS rehashes) +--FILE-- +<?php +$x = (object)['a'=>1,'b'=>2,'c'=>3,'d'=>4,'e'=>5,'f'=>6,'g'=>7]; +$x->h =& $x->i; +$x->h = 42; +var_dump($x); +?> +--EXPECT-- +object(stdClass)#1 (9) { + ["a"]=> + int(1) + ["b"]=> + int(2) + ["c"]=> + int(3) + ["d"]=> + int(4) + ["e"]=> + int(5) + ["f"]=> + int(6) + ["g"]=> + int(7) + ["i"]=> + &int(42) + ["h"]=> + &int(42) +} diff --git a/Zend/tests/bug71539_2.phpt b/Zend/tests/bug71539_2.phpt new file mode 100644 index 0000000000..380da467fb --- /dev/null +++ b/Zend/tests/bug71539_2.phpt @@ -0,0 +1,30 @@ +--TEST-- +Bug #71539.2 (Memory error on $arr[$a] =& $arr[$b] if RHS rehashes) +--FILE-- +<?php +$a = [0,1,2,3,4,5,6]; +$a[200] =& $a[100]; +$a[100] =42; +var_dump($a); +?> +--EXPECT-- +array(9) { + [0]=> + int(0) + [1]=> + int(1) + [2]=> + int(2) + [3]=> + int(3) + [4]=> + int(4) + [5]=> + int(5) + [6]=> + int(6) + [100]=> + &int(42) + [200]=> + &int(42) +} diff --git a/Zend/tests/bug71539_3.phpt b/Zend/tests/bug71539_3.phpt new file mode 100644 index 0000000000..7212a6de47 --- /dev/null +++ b/Zend/tests/bug71539_3.phpt @@ -0,0 +1,19 @@ +--TEST-- +Bug #71539.3 (Memory error on $arr[$a] =& $arr[$b] if RHS rehashes) +--FILE-- +<?php +$array = []; +$array[0][0] =& $array['']; +$array[0][0] = 42; +var_dump($array); +?> +--EXPECT-- +array(2) { + [""]=> + &int(42) + [0]=> + array(1) { + [0]=> + &int(42) + } +} diff --git a/Zend/tests/bug71539_4.phpt b/Zend/tests/bug71539_4.phpt new file mode 100644 index 0000000000..5b9cee05c1 --- /dev/null +++ b/Zend/tests/bug71539_4.phpt @@ -0,0 +1,19 @@ +--TEST-- +Bug #71539.4 (Memory error on $arr[$a] =& $arr[$b] if RHS rehashes) +--FILE-- +<?php +$array = [0=>[]]; +$array[0][0] =& $array[0]['']; +$array[0][0] = 42; +var_dump($array); +?> +--EXPECT-- +array(1) { + [0]=> + array(2) { + [""]=> + &int(42) + [0]=> + &int(42) + } +} diff --git a/Zend/tests/bug71539_5.phpt b/Zend/tests/bug71539_5.phpt new file mode 100644 index 0000000000..14559bf65e --- /dev/null +++ b/Zend/tests/bug71539_5.phpt @@ -0,0 +1,19 @@ +--TEST-- +Bug #71539.5 (Memory error on $arr[$a] =& $arr[$b] if RHS rehashes) +--FILE-- +<?php +$array = []; +$array['']->prop =& $array[0]; +$array[0] = 42; +var_dump($array); +?> +--EXPECT-- +array(2) { + [0]=> + &int(42) + [""]=> + object(stdClass)#1 (1) { + ["prop"]=> + &int(42) + } +} diff --git a/Zend/tests/bug71539_6.phpt b/Zend/tests/bug71539_6.phpt new file mode 100644 index 0000000000..2bf4f6b1e0 --- /dev/null +++ b/Zend/tests/bug71539_6.phpt @@ -0,0 +1,15 @@ +--TEST-- +Bug #71539.5 (Memory error on $arr[$a] =& $arr[$b] if RHS rehashes) +--FILE-- +<?php +$name = 'a'; +for ($i = 0; $i < 100000; $i++) { + if ($name != 'i') { + $$name =& $GLOBALS; + } + $name++; +} +?> +OK +--EXPECT-- +OK
\ No newline at end of file diff --git a/Zend/tests/bug71572.phpt b/Zend/tests/bug71572.phpt new file mode 100644 index 0000000000..4a823ec72f --- /dev/null +++ b/Zend/tests/bug71572.phpt @@ -0,0 +1,27 @@ +--TEST-- +Bug #71572: String offset assignment from an empty string inserts null byte +--FILE-- +<?php + +$str = "abc"; +var_dump($str{0} = ""); +var_dump($str{1} = ""); +var_dump($str{3} = ""); +var_dump($str{10} = ""); +var_dump($str); +?> +==DONE== +--EXPECTF-- +Warning: Cannot assign an empty string to a string offset in %s on line %d +NULL + +Warning: Cannot assign an empty string to a string offset in %s on line %d +NULL + +Warning: Cannot assign an empty string to a string offset in %s on line %d +NULL + +Warning: Cannot assign an empty string to a string offset in %s on line %d +NULL +string(3) "abc" +==DONE==
\ No newline at end of file diff --git a/Zend/tests/bug71818.phpt b/Zend/tests/bug71818.phpt new file mode 100644 index 0000000000..e09255ddac --- /dev/null +++ b/Zend/tests/bug71818.phpt @@ -0,0 +1,30 @@ +--TEST-- +Bug #71818 (Memory leak when array altered in destructor) +--INI-- +zend.enable_gc = 1 +--FILE-- +<?php +class MemoryLeak +{ + public function __construct() + { + $this->things[] = $this; + } + + public function __destruct() + { + $this->things[] = null; + } + + private $things = []; +} + +ini_set('memory_limit', '10M'); + +for ($i = 0; $i < 100000; ++$i) { + $obj = new MemoryLeak(); +} +echo "OK\n"; +?> +--EXPECT-- +OK diff --git a/Zend/tests/bug72107.phpt b/Zend/tests/bug72107.phpt new file mode 100644 index 0000000000..3f4c46cf70 --- /dev/null +++ b/Zend/tests/bug72107.phpt @@ -0,0 +1,14 @@ +--TEST-- +Bug #72107: Segfault when using func_get_args as error handler +--FILE-- +<?php +set_error_handler('func_get_args'); +function test($a) { + echo $undef; +} +test(1); +?> +--EXPECTF-- +Warning: Cannot call func_get_args() dynamically in %s on line %d + +Notice: Undefined variable: undef in %s on line %d diff --git a/Zend/tests/bug72119.phpt b/Zend/tests/bug72119.phpt index b8f070a25a..064381ada0 100644 --- a/Zend/tests/bug72119.phpt +++ b/Zend/tests/bug72119.phpt @@ -14,5 +14,6 @@ class Hello implements Foo { } echo "OK\n"; ?> ---EXPECT-- -OK +--EXPECTF-- +Fatal error: Declaration of Hello::bar(array $baz = Array) must be compatible with Foo::bar(?array $baz = NULL) in %s on line %d + diff --git a/Zend/tests/bug72162.phpt b/Zend/tests/bug72162.phpt index 5902c585d8..493342d838 100644 --- a/Zend/tests/bug72162.phpt +++ b/Zend/tests/bug72162.phpt @@ -7,4 +7,4 @@ $var11 = new StdClass(); $var16 = error_reporting($var11); ?> --EXPECTF-- -Catchable fatal error: Object of class stdClass could not be converted to string in %sbug72162.php on line %d +Recoverable fatal error: Object of class stdClass could not be converted to string in %sbug72162.php on line %d diff --git a/Zend/tests/bug72177.phpt b/Zend/tests/bug72177.phpt new file mode 100644 index 0000000000..b5658d354a --- /dev/null +++ b/Zend/tests/bug72177.phpt @@ -0,0 +1,35 @@ +--TEST-- +Bug #72177 Scope issue in __destruct after ReflectionProperty::setValue() +--FILE-- +<?php +class Child +{ + protected $bar; + + public function __destruct() + { + $this->bar = null; + } +} + +class Parnt +{ + protected $child; + + public function doSomething() + { + $this->child = new Child(); + + $prop = new \ReflectionProperty($this, 'child'); + $prop->setAccessible(true); + $prop->setValue($this, null); + } +} + +$p = new Parnt(); +$p->doSomething(); + +echo "OK\n"; +?> +--EXPECT-- +OK diff --git a/Zend/tests/bug72177_2.phpt b/Zend/tests/bug72177_2.phpt new file mode 100644 index 0000000000..718d6c061e --- /dev/null +++ b/Zend/tests/bug72177_2.phpt @@ -0,0 +1,34 @@ +--TEST-- +Bug #72177 Scope issue in __destruct after ReflectionProperty::setValue() +--FILE-- +<?php +class Foo +{ + private $bar = 'bar'; + + public function __construct() + { + unset($this->bar); + } +} + +class Bar extends Foo +{ + private $baz = 'baz'; + private static $tab = 'tab'; + + public function __get(string $name) + { + var_dump($this->baz); + var_dump(self::$tab); + return $name; + } +} + +$r = new ReflectionProperty(Foo::class, 'bar'); + +$r->setAccessible(true); +echo "OK\n"; +?> +--EXPECT-- +OK diff --git a/Zend/tests/bug72188.phpt b/Zend/tests/bug72188.phpt new file mode 100644 index 0000000000..0deab6b81b --- /dev/null +++ b/Zend/tests/bug72188.phpt @@ -0,0 +1,27 @@ +--TEST-- +Bug #72188 (Nested try/finally blocks losing return value) +--FILE-- +<?php +function test() { + try { + return 5; + } finally { + try { + echo 1; + } finally { + echo 2; + } + } +} + + + +$a = test(); +if($a !== 5) { + echo "FAILED: expected 5, received ", var_export($a), PHP_EOL; +} else { + echo "Passed", PHP_EOL; +} +?> +--EXPECT-- +12Passed diff --git a/Zend/tests/bug72215.phpt b/Zend/tests/bug72215.phpt new file mode 100644 index 0000000000..0ff16291ad --- /dev/null +++ b/Zend/tests/bug72215.phpt @@ -0,0 +1,16 @@ +--TEST-- +Bug #72215 (Wrong return value if var modified in finally) +--FILE-- +<?php +function test() { + $a = 1; + try { + return $a; + } finally { + $a = 2; + } +} +var_dump(test()); +?> +--EXPECT-- +int(1) diff --git a/Zend/tests/bug72215_1.phpt b/Zend/tests/bug72215_1.phpt new file mode 100644 index 0000000000..d56c9f881d --- /dev/null +++ b/Zend/tests/bug72215_1.phpt @@ -0,0 +1,21 @@ +--TEST-- +Bug #72215.1 (Wrong return value if var modified in finally) +--FILE-- +<?php +function &test(&$b) { + $a =& $b; + try { + return $a; + } finally { + $a = 2; + } +} +$x = 1; +$y =& test($x); +var_dump($y); +$x = 3; +var_dump($y); +?> +--EXPECT-- +int(2) +int(3) diff --git a/Zend/tests/bug72215_2.phpt b/Zend/tests/bug72215_2.phpt new file mode 100644 index 0000000000..cefb6d9632 --- /dev/null +++ b/Zend/tests/bug72215_2.phpt @@ -0,0 +1,22 @@ +--TEST-- +Bug #72215.1 (Wrong return value if var modified in finally) +--FILE-- +<?php +function &test(&$b) { + $a =& $b; + try { + return $a; + } finally { + $a =& $c; + $a = 2; + } +} +$x = 1; +$y =& test($x); +var_dump($y); +$x = 3; +var_dump($y); +?> +--EXPECT-- +int(1) +int(3) diff --git a/Zend/tests/bug72215_3.phpt b/Zend/tests/bug72215_3.phpt new file mode 100644 index 0000000000..6f10fd7dee --- /dev/null +++ b/Zend/tests/bug72215_3.phpt @@ -0,0 +1,15 @@ +--TEST-- +Bug #72215.3 (Wrong return value if var modified in finally) +--FILE-- +<?php +function &test() { + try { + return $a; + } finally { + $a = 2; + } +} +var_dump(test()); +?> +--EXPECT-- +int(2) diff --git a/Zend/tests/bug72216.phpt b/Zend/tests/bug72216.phpt new file mode 100644 index 0000000000..65b5556c70 --- /dev/null +++ b/Zend/tests/bug72216.phpt @@ -0,0 +1,16 @@ +--TEST-- +Bug #72216 (Return by reference with finally is not memory safe) +--FILE-- +<?php +function &test() { + $a = ["ok"]; + try { + return $a[0]; + } finally { + $a[""] = 42; + } +} +var_dump(test()); +?> +--EXPECT-- +string(2) "ok" diff --git a/Zend/tests/bug72221.phpt b/Zend/tests/bug72221.phpt new file mode 100644 index 0000000000..8f30099cab --- /dev/null +++ b/Zend/tests/bug72221.phpt @@ -0,0 +1,11 @@ +--TEST-- +Bug #72221 (Segmentation fault in stream_get_line / zend_memnstr_ex) +--FILE-- +<?php +$fp = fopen("php://memory", "r+"); +fwrite($fp, str_repeat("baad", 1024*1024)); +rewind($fp); +stream_get_line($fp, 1024*1024*2, "aaaa"); +echo "Done\n"; +--EXPECT-- +Done diff --git a/Zend/tests/bug72335.phpt b/Zend/tests/bug72335.phpt new file mode 100644 index 0000000000..854de34281 --- /dev/null +++ b/Zend/tests/bug72335.phpt @@ -0,0 +1,18 @@ +--TEST-- +Misoptimize due to type narrowing +--FILE-- +<?php + +function test() { + $b = false; + $x = (1<<53)+1; + do { + $x = 1.0 * ($x - (1<<53)); + } while ($b); + return $x; +} +var_dump(test()); + +?> +--EXPECT-- +float(1) diff --git a/Zend/tests/bug72347.phpt b/Zend/tests/bug72347.phpt new file mode 100644 index 0000000000..b86457207d --- /dev/null +++ b/Zend/tests/bug72347.phpt @@ -0,0 +1,17 @@ +--TEST-- +Bug #72347 (VERIFY_RETURN type casts visible in finally) +--FILE-- +<?php +function test() : int { + $d = 1.5; + try { + return $d; + } finally { + var_dump($d); + } +} +var_dump(test()); +?> +--EXPECT-- +float(1.5) +int(1) diff --git a/Zend/tests/bug72373.phpt b/Zend/tests/bug72373.phpt new file mode 100644 index 0000000000..67377c5ba7 --- /dev/null +++ b/Zend/tests/bug72373.phpt @@ -0,0 +1,20 @@ +--TEST-- +Bug #72373: TypeError after Generator function w/declared return type finishes +--FILE-- +<?php + +function foo() : Generator { + yield 1; + yield 2; + yield 3; +} + +foreach (foo() as $bar) { + echo $bar . "\n"; +} + +?> +--EXPECT-- +1 +2 +3 diff --git a/Zend/tests/bug72395.phpt b/Zend/tests/bug72395.phpt new file mode 100644 index 0000000000..e89ecdd5ad --- /dev/null +++ b/Zend/tests/bug72395.phpt @@ -0,0 +1,10 @@ +--TEST-- +Bug #72395 (list() regression) +--FILE-- +<?php +list(,,$a,,$b,) = array(1, 2, 3, 4, 5, 6); +var_dump($a, $b); +?> +--EXPECT-- +int(3) +int(5) diff --git a/Zend/tests/bug72441.phpt b/Zend/tests/bug72441.phpt new file mode 100644 index 0000000000..af57b3adb0 --- /dev/null +++ b/Zend/tests/bug72441.phpt @@ -0,0 +1,14 @@ +--TEST-- +Bug #72441 (Segmentation fault: RFC list_keys) +--FILE-- +<?php + +$array = []; + +list( + '' => $foo, + $bar +) = $array; +?> +--EXPECTF-- +Fatal error: Cannot mix keyed and unkeyed array entries in assignments in %sbug72441.php on line %d diff --git a/Zend/tests/bug72543.phpt b/Zend/tests/bug72543.phpt new file mode 100644 index 0000000000..4244b8ce41 --- /dev/null +++ b/Zend/tests/bug72543.phpt @@ -0,0 +1,39 @@ +--TEST-- +Bug #72543 (different references behavior comparing to PHP 5) +--FILE-- +<?php +function create_references(&$array) { + foreach ($array as $key => $value) { + create_references($array[$key]); + } +} + +function change_copy($copy) { + $copy['b']['z']['z'] = $copy['b']; +} + +$data = [ + 'a' => [ + 'b' => [], + ], +]; + +create_references($data); + +$copy = $data['a']; +var_dump($copy); + +change_copy($copy); +var_dump($copy); //RECURSION +?> +--EXPECT-- +array(1) { + ["b"]=> + array(0) { + } +} +array(1) { + ["b"]=> + array(0) { + } +} diff --git a/Zend/tests/bug72543_1.phpt b/Zend/tests/bug72543_1.phpt new file mode 100644 index 0000000000..f63ee7f14b --- /dev/null +++ b/Zend/tests/bug72543_1.phpt @@ -0,0 +1,19 @@ +--TEST-- +Bug #72543.1 (different references behavior comparing to PHP 5) +--FILE-- +<?php +$arr = []; +$arr[0] = null; +$ref =& $arr[0]; +unset($ref); +$arr[0][0] = $arr[0]; +var_dump($arr); +?> +--EXPECT-- +array(1) { + [0]=> + array(1) { + [0]=> + NULL + } +} diff --git a/Zend/tests/bug72543_2.phpt b/Zend/tests/bug72543_2.phpt new file mode 100644 index 0000000000..2070d65bdd --- /dev/null +++ b/Zend/tests/bug72543_2.phpt @@ -0,0 +1,19 @@ +--TEST-- +Bug #72543.2 (different references behavior comparing to PHP 5) +--FILE-- +<?php +$arr = []; +$arr[0] = null; +$ref =& $arr[0]; +unset($ref); +$arr[0][$arr[0]] = null; +var_dump($arr); +?> +--EXPECT-- +array(1) { + [0]=> + array(1) { + [""]=> + NULL + } +} diff --git a/Zend/tests/bug72543_3.phpt b/Zend/tests/bug72543_3.phpt new file mode 100644 index 0000000000..3835fafaa3 --- /dev/null +++ b/Zend/tests/bug72543_3.phpt @@ -0,0 +1,12 @@ +--TEST-- +Bug #72543.3 (different references behavior comparing to PHP 5) +--FILE-- +<?php +$x = new stdClass; +$x->a = 1; +$ref =& $x->a; +unset($ref); +var_dump($x->a + ($x->a = 2)); +?> +--EXPECT-- +int(3) diff --git a/Zend/tests/bug72543_4.phpt b/Zend/tests/bug72543_4.phpt new file mode 100644 index 0000000000..3480c1c42c --- /dev/null +++ b/Zend/tests/bug72543_4.phpt @@ -0,0 +1,11 @@ +--TEST-- +Bug #72543.4 (different references behavior comparing to PHP 5) +--FILE-- +<?php +$arr = [1]; +$ref =& $arr[0]; +unset($ref); +var_dump($arr[0] + ($arr[0] = 2)); +?> +--EXPECT-- +int(3) diff --git a/Zend/tests/bug72543_5.phpt b/Zend/tests/bug72543_5.phpt new file mode 100644 index 0000000000..66b3b75f2a --- /dev/null +++ b/Zend/tests/bug72543_5.phpt @@ -0,0 +1,10 @@ +--TEST-- +Bug #72543.5 (different references behavior comparing to PHP 5) +--FILE-- +<?php +$arr = [1]; +$ref =& $arr[0]; +var_dump($arr[0] + ($arr[0] = 2)); +?> +--EXPECT-- +int(4) diff --git a/Zend/tests/bug72598.phpt b/Zend/tests/bug72598.phpt new file mode 100644 index 0000000000..dfb09a05b8 --- /dev/null +++ b/Zend/tests/bug72598.phpt @@ -0,0 +1,26 @@ +--TEST-- +Bug #72598 (Reference is lost after array_slice()) +--FILE-- +<?php +function ref(&$ref) { + var_dump($ref); +} + +new class { + function __construct() { + $args = [&$this]; + for ($i = 0; $i < 2; $i++) { + $a = array_slice($args, 0, 1); + call_user_func_array('ref', $a); + } + } +}; +?> +--EXPECTF-- +Warning: Parameter 1 to ref() expected to be a reference, value given in %sbug72598.php on line 11 +object(class@anonymous)#1 (0) { +} + +Warning: Parameter 1 to ref() expected to be a reference, value given in %sbug72598.php on line 11 +object(class@anonymous)#1 (0) { +} diff --git a/Zend/tests/bug72598_2.phpt b/Zend/tests/bug72598_2.phpt new file mode 100644 index 0000000000..c3943806ff --- /dev/null +++ b/Zend/tests/bug72598_2.phpt @@ -0,0 +1,27 @@ +--TEST-- +Bug #72598.2 (Reference is lost after array_slice()) +--FILE-- +<?php +function ref(&$ref) { + var_dump($ref); + $ref = 1; +} + +new class { + function __construct() { + $b = 0; + $args = [&$b]; + unset($b); + for ($i = 0; $i < 2; $i++) { + $a = array_slice($args, 0, 1); + call_user_func_array('ref', $a); + } + } +}; +?> +--EXPECTF-- +Warning: Parameter 1 to ref() expected to be a reference, value given in %sbug72598_2.php on line 14 +int(0) + +Warning: Parameter 1 to ref() expected to be a reference, value given in %sbug72598_2.php on line 14 +int(0) diff --git a/Zend/tests/bug72918.phpt b/Zend/tests/bug72918.phpt new file mode 100644 index 0000000000..f3dc1d2918 --- /dev/null +++ b/Zend/tests/bug72918.phpt @@ -0,0 +1,22 @@ +--TEST--
+Bug #72918 (negative offset inside a quoted string leads to parse error)
+--FILE--
+<?php
+$array = [-3 => 'foo'];
+$string = 'abcde';
+
+echo "$array[-3]\n";
+echo "$string[-3]\n";
+echo <<<EOT
+$array[-3]
+$string[-3]
+
+EOT;
+?>
+===DONE===
+--EXPECT--
+foo
+c
+foo
+c
+===DONE===
diff --git a/Zend/tests/bug73288.phpt b/Zend/tests/bug73288.phpt new file mode 100644 index 0000000000..fefcf3bbcd --- /dev/null +++ b/Zend/tests/bug73288.phpt @@ -0,0 +1,34 @@ +--TEST-- +Bug #73288 (Segfault in __clone > Exception.toString > __get) +--INI-- +opcache.enable=1 +opcache.enable_cli=1 +--FILE-- +<?php + +class NoClone { + public function __clone() { + throw new Exception("No Cloneable"); + } +} + +class C { + public function __get($name) { + return new NoClone; + } +} + +function test_clone() { + $c = new C; + $b = clone $c->x; +} + +test_clone(); +?> +--EXPECTF-- +Fatal error: Uncaught Exception: No Cloneable in %sbug73288.php:%d +Stack trace: +#0 %s(%d): NoClone->__clone() +#1 %s(%d): test_clone() +#2 {main} + thrown in %sbug73288.php on line %d diff --git a/Zend/tests/bug74093.phpt b/Zend/tests/bug74093.phpt new file mode 100644 index 0000000000..7f20285805 --- /dev/null +++ b/Zend/tests/bug74093.phpt @@ -0,0 +1,20 @@ +--TEST-- +Bug #74093 (Maximum execution time of n+2 seconds exceed not written in error_log) +--SKIPIF-- +<?php +if (getenv("SKIP_SLOW_TESTS")) die("skip slow test"); +if (PHP_ZTS) die("skip only for no-zts build"); +if (substr(PHP_OS, 0, 3) == 'WIN') die("skip not for Windows"); +?> +--INI-- +memory_limit=1G +max_execution_time=1 +hard_timeout=1 +--FILE-- +<?php +$a1 = range(1, 1000000); +$a2 = range(100000, 1999999); +array_intersect($a1, $a2); +?> +--EXPECTF-- +Fatal error: Maximum execution time of 1+1 seconds exceeded %s diff --git a/Zend/tests/bug74164.phpt b/Zend/tests/bug74164.phpt new file mode 100644 index 0000000000..354b2f51e0 --- /dev/null +++ b/Zend/tests/bug74164.phpt @@ -0,0 +1,20 @@ +--TEST-- +Bug #74164 (PHP hangs when an invalid value is dynamically passed to typehinted by-ref arg) +--FILE-- +<?php + +namespace Foo; + +set_error_handler(function ($type, $msg) { + throw new \Exception($msg); +}); + +call_user_func(function (array &$ref) {var_dump("xxx");}, 'not_an_array_variable'); +?> +--EXPECTF-- +Fatal error: Uncaught Exception: Parameter 1 to Foo\{closure}() expected to be a reference, value given in %sbug74164.php:%d +Stack trace: +#0 [internal function]: Foo\{closure}(%s) +#1 %sbug74164.php(%d): call_user_func(%s) +#2 {main} + thrown in %sbug74164.php on line %d diff --git a/Zend/tests/bug74340.phpt b/Zend/tests/bug74340.phpt new file mode 100644 index 0000000000..f266dcc236 --- /dev/null +++ b/Zend/tests/bug74340.phpt @@ -0,0 +1,30 @@ +--TEST-- +Bug #74340: Magic function __get has different behavior in php 7.1.x +--FILE-- +<?php +class Test +{ + public function __get($var) + { + static $first = true; + echo '__get '.$var.PHP_EOL; + if ($first) { + $first = false; + $this->$var; + $this->{$var.'2'}; + $this->$var; + } + } +} + +$test = new Test; +$test->test; + +?> +--EXPECTF-- +__get test + +Notice: Undefined property: Test::$test in %s on line %d +__get test2 + +Notice: Undefined property: Test::$test in %s on line %d diff --git a/Zend/tests/bug74862.phpt b/Zend/tests/bug74862.phpt new file mode 100644 index 0000000000..7822575d04 --- /dev/null +++ b/Zend/tests/bug74862.phpt @@ -0,0 +1,43 @@ +--TEST-- +Bug #74862 (Unable to clone instance when private __clone defined) +--FILE-- +<?php + +class a { + private function __clone() + { + + } + + private function __construct() + { + + } + + public static function getInstance() + { + return new static(); + } + + public function cloneIt() + { + $a = clone $this; + + return $a; + } +} + +class c extends a { + +} + +// private constructor +$d = c::getInstance(); + +// private clone +$e = $d->cloneIt(); +var_dump($e); +?> +--EXPECT-- +object(c)#2 (0) { +} diff --git a/Zend/tests/bug74862_2.phpt b/Zend/tests/bug74862_2.phpt new file mode 100644 index 0000000000..2e544a380e --- /dev/null +++ b/Zend/tests/bug74862_2.phpt @@ -0,0 +1,46 @@ +--TEST-- +Bug #74862 (Unable to clone instance when private __clone defined in a child class) +--FILE-- +<?php + +class main { +} + +class a extends main { + private function __clone() + { + + } + + private function __construct() + { + + } + + public static function getInstance() + { + return new static(); + } + + public function cloneIt() + { + $a = clone $this; + + return $a; + } +} + +class c extends a { + +} + +// private constructor +$d = c::getInstance(); + +// private clone +$e = $d->cloneIt(); +var_dump($e); +?> +--EXPECT-- +object(c)#2 (0) { +} diff --git a/Zend/tests/bug75079.phpt b/Zend/tests/bug75079.phpt new file mode 100644 index 0000000000..9bf9c1ddb8 --- /dev/null +++ b/Zend/tests/bug75079.phpt @@ -0,0 +1,39 @@ +--TEST-- +Bug #75079: self keyword leads to incorrectly generated TypeError when in closure in trait +--FILE-- +<?php + +trait Foo +{ + public function selfDo(self ...$Selfs) + { + array_map( + function (self $Self) : self + { + return $Self; + }, + $Selfs + ); + } +} + +class Bar +{ + use Foo; +} + +class Baz +{ + use Foo; +} + +$Bar = new Bar; +$Baz = new Baz; + +$Bar->selfDo($Bar, $Bar); +$Baz->selfDo($Baz, $Baz); + +?> +===DONE=== +--EXPECT-- +===DONE=== diff --git a/Zend/tests/bug75079_2.phpt b/Zend/tests/bug75079_2.phpt new file mode 100644 index 0000000000..6e0b1cd27f --- /dev/null +++ b/Zend/tests/bug75079_2.phpt @@ -0,0 +1,36 @@ +--TEST-- +Bug #75079 variation without traits +--FILE-- +<?php + +class Foo +{ + private static $bar = 123; + + static function test(){ + return function(){ + return function(){ + return Foo::$bar; + }; + }; + } +} + + +$f = Foo::test(); + +var_dump($f()()); + +class A{} +$a = new A; +var_dump($f->bindTo($a, A::CLASS)()()); + +?> +--EXPECTF-- +int(123) + +Fatal error: Uncaught Error: Cannot access private property Foo::$bar in %s:%d +Stack trace: +#0 %s(%d): A->{closure}() +#1 {main} + thrown in %s on line %d diff --git a/Zend/tests/bug75786.phpt b/Zend/tests/bug75786.phpt new file mode 100644 index 0000000000..b93111b9e3 --- /dev/null +++ b/Zend/tests/bug75786.phpt @@ -0,0 +1,18 @@ +--TEST-- +Bug #75786: segfault when using spread operator on generator passed by reference +--FILE-- +<?php + +function &gen($items) { + foreach ($items as $key => &$value) { + yield $key => $value; + } +} + +var_dump(...gen(['a', 'b', 'c'])); + +?> +--EXPECT-- +string(1) "a" +string(1) "b" +string(1) "c" diff --git a/Zend/tests/bug76025.phpt b/Zend/tests/bug76025.phpt new file mode 100644 index 0000000000..2619984d1e --- /dev/null +++ b/Zend/tests/bug76025.phpt @@ -0,0 +1,18 @@ +--TEST-- +Bug #76025 (Segfault while throwing exception in error_handler) +--FILE-- +<?php + +function handleError($errno, $errstr, $errfile, $errline) { + $exception = new exception("blah"); + throw $exception; +} +set_error_handler('handleError', E_ALL); +$c = $b[$a]; +?> +--EXPECTF-- +Fatal error: Uncaught Exception: blah in %sbug76025.php:%d +Stack trace: +#0 %sbug76025.php(%d): handleError(8, 'Undefined varia...', '%s', %d, Array) +#1 {main} + thrown in %sbug76025.php on line %d diff --git a/Zend/tests/bug76383.phpt b/Zend/tests/bug76383.phpt new file mode 100644 index 0000000000..ae26ba8acd --- /dev/null +++ b/Zend/tests/bug76383.phpt @@ -0,0 +1,13 @@ +--TEST-- +Bug #76383: array_map on $GLOBALS returns IS_INDIRECT +--FILE-- +<?php + +$a = 1; +array_map(function($x) use (&$lastval) { $lastval = $x; }, $GLOBALS); +var_dump(gettype($lastval), $lastval); // will contain $a + +?> +--EXPECT-- +string(7) "integer" +int(1) diff --git a/Zend/tests/bug76502.phpt b/Zend/tests/bug76502.phpt new file mode 100644 index 0000000000..caacc99f70 --- /dev/null +++ b/Zend/tests/bug76502.phpt @@ -0,0 +1,36 @@ +--TEST-- +Bug #76502: Chain of mixed exceptions and errors does not serialize properly +--FILE-- +<?php + +$examples = [ + "Exception(Exception())" => new Exception("outer", 0, new Exception("inner")), + "Error(Error())" => new Error("outer", 0, new Error("inner")), + "Error(Exception())" => new Error("outer", 0, new Exception("inner")), + "Exception(Error())" => new Exception("outer", 0, new Error("inner")) +]; + +foreach ($examples as $name => $example) { + $processed = unserialize(serialize($example)); + $processedPrev = $processed->getPrevious(); + echo "---- $name ----\n"; + echo "before: ", get_class($example), ".previous == ", + get_class($example->getPrevious()), "\n"; + echo "after : ", get_class($processed), ".previous == ", + $processedPrev ? get_class($processedPrev) : "null", "\n"; +} + +?> +--EXPECT-- +---- Exception(Exception()) ---- +before: Exception.previous == Exception +after : Exception.previous == Exception +---- Error(Error()) ---- +before: Error.previous == Error +after : Error.previous == Error +---- Error(Exception()) ---- +before: Error.previous == Exception +after : Error.previous == Exception +---- Exception(Error()) ---- +before: Exception.previous == Error +after : Exception.previous == Error diff --git a/Zend/tests/bug76534.phpt b/Zend/tests/bug76534.phpt new file mode 100644 index 0000000000..956a29ba2c --- /dev/null +++ b/Zend/tests/bug76534.phpt @@ -0,0 +1,17 @@ +--TEST-- +Bug #76534 (PHP hangs on 'illegal string offset on string references with an error handler) +--FILE-- +<?php +set_error_handler(function ($severity, $message, $file, $line) { + throw new \Exception($message); +}); + +$x = "foo"; +$y = &$x["bar"]; +?> +--EXPECTF-- +Fatal error: Uncaught Exception: Illegal string offset 'bar' in %sbug76534.php:%d +Stack trace: +#0 %sbug76534.php(%d): {closure}(2, 'Illegal string ...', '%s', %d, Array) +#1 {main} + thrown in %sbug76534.php on line %d diff --git a/Zend/tests/bug76754.phpt b/Zend/tests/bug76754.phpt new file mode 100644 index 0000000000..424f1fbffc --- /dev/null +++ b/Zend/tests/bug76754.phpt @@ -0,0 +1,18 @@ +--TEST-- +Bug #76754 (parent private constant in extends class memory leak) +--INI-- +opcache.enable=0 +opcache.enable_cli=0 +--FILE-- +<?php + +class FOO +{ + private const FOO = 'BAR'; +} + +class BAR extends FOO { } +?> +okey +--EXPECT-- +okey diff --git a/Zend/tests/call_user_func_006.phpt b/Zend/tests/call_user_func_006.phpt new file mode 100644 index 0000000000..16a59bcf5b --- /dev/null +++ b/Zend/tests/call_user_func_006.phpt @@ -0,0 +1,28 @@ +--TEST-- +call_user_func() should error on reference arguments +--FILE-- +<?php + +namespace Foo; + +function bar(&$ref) { + $ref = 24; +} + +$x = 42; +$ref =& $x; +\call_user_func('Foo\bar', $x); +var_dump($x); + +$y = 42; +$ref =& $y; +call_user_func('Foo\bar', $y); +var_dump($y); + +?> +--EXPECTF-- +Warning: Parameter 1 to Foo\bar() expected to be a reference, value given in %s on line %d +int(42) + +Warning: Parameter 1 to Foo\bar() expected to be a reference, value given in %s on line %d +int(42) diff --git a/Zend/tests/call_user_func_008.phpt b/Zend/tests/call_user_func_008.phpt new file mode 100644 index 0000000000..3e727e7f43 --- /dev/null +++ b/Zend/tests/call_user_func_008.phpt @@ -0,0 +1,54 @@ +--TEST-- +call_user_func() behavior with references +--FILE-- +<?php + +function test(&$ref1, &$ref2) { + $ref1 += 42; + $ref2 -= 42; + return true; +} + +$i = $j = 0; +var_dump(call_user_func('test', $i, $j)); +var_dump($i, $j); + +var_dump(call_user_func_array('test', [$i, $j])); +var_dump($i, $j); + +$x =& $i; $y =& $j; +var_dump(call_user_func('test', $i, $j)); +var_dump($i, $j); + +var_dump(call_user_func_array('test', [$i, $j])); +var_dump($i, $j); + +?> +--EXPECTF-- +Warning: Parameter 1 to test() expected to be a reference, value given in %s on line %d + +Warning: Parameter 2 to test() expected to be a reference, value given in %s on line %d +bool(true) +int(0) +int(0) + +Warning: Parameter 1 to test() expected to be a reference, value given in %s on line %d + +Warning: Parameter 2 to test() expected to be a reference, value given in %s on line %d +bool(true) +int(0) +int(0) + +Warning: Parameter 1 to test() expected to be a reference, value given in %s on line %d + +Warning: Parameter 2 to test() expected to be a reference, value given in %s on line %d +bool(true) +int(0) +int(0) + +Warning: Parameter 1 to test() expected to be a reference, value given in %s on line %d + +Warning: Parameter 2 to test() expected to be a reference, value given in %s on line %d +bool(true) +int(0) +int(0) diff --git a/Zend/tests/call_user_func_009.phpt b/Zend/tests/call_user_func_009.phpt new file mode 100644 index 0000000000..d45380db15 --- /dev/null +++ b/Zend/tests/call_user_func_009.phpt @@ -0,0 +1,17 @@ +--TEST-- +call_user_func() behavior when passing literal to reference parameter +--FILE-- +<?php + +namespace Foo; + +var_dump(call_user_func('sort', [])); +var_dump(\call_user_func('sort', [])); + +?> +--EXPECTF-- +Warning: Parameter 1 to sort() expected to be a reference, value given in %s on line %d +bool(true) + +Warning: Parameter 1 to sort() expected to be a reference, value given in %s on line %d +bool(true) diff --git a/Zend/tests/class_properties_const.phpt b/Zend/tests/class_properties_const.phpt index ac871b5c2b..8f607bcfe2 100644 --- a/Zend/tests/class_properties_const.phpt +++ b/Zend/tests/class_properties_const.phpt @@ -22,4 +22,4 @@ NULL Notice: Undefined property: A::$1 in %sclass_properties_const.php on line %d NULL -Catchable fatal error: Object of class Closure could not be converted to string in %sclass_properties_const.php on line %d +Recoverable fatal error: Object of class Closure could not be converted to string in %sclass_properties_const.php on line %d diff --git a/Zend/tests/closure_027.phpt b/Zend/tests/closure_027.phpt index db42ae9307..76754f9fba 100644 --- a/Zend/tests/closure_027.phpt +++ b/Zend/tests/closure_027.phpt @@ -13,7 +13,11 @@ test(function() { return new stdclass; }); test(function() { }); $a = function($x) use ($y) {}; -test($a); +try { + test($a); +} catch (Throwable $e) { + echo "Exception: " . $e->getMessage() . "\n"; +} test(new stdclass); @@ -24,9 +28,7 @@ object(stdClass)#%d (0) { NULL Notice: Undefined variable: y in %s on line %d - -Warning: Missing argument 1 for {closure}(), called in %s on line %d and defined in %s on line %d -NULL +Exception: Too few arguments to function {closure}(), 0 passed in %s on line %d and exactly 1 expected Fatal error: Uncaught TypeError: Argument 1 passed to test() must be an instance of Closure, instance of stdClass given, called in %s on line %d and defined in %s:%d Stack trace: diff --git a/Zend/tests/closure_061.phpt b/Zend/tests/closure_061.phpt index 83ad16d2e1..1aa579a409 100644 --- a/Zend/tests/closure_061.phpt +++ b/Zend/tests/closure_061.phpt @@ -184,7 +184,7 @@ bindTo(new ClsChild, Cls::class): Success! bindTo(new ClsUnrelated, Cls::class): -Success! +Cannot bind method Cls::method() to object of class ClsUnrelated bindTo(new Cls, null): Cannot rebind scope of closure created by ReflectionFunctionAbstract::getClosure() @@ -205,7 +205,7 @@ bindTo(new SplStack, SplDoublyLinkedList::class): Success! bindTo(new ClsUnrelated, SplDoublyLinkedList::class): -Cannot bind internal method SplDoublyLinkedList::count() to object of class ClsUnrelated +Cannot bind method SplDoublyLinkedList::count() to object of class ClsUnrelated bindTo(null, null): Cannot unbind $this of internal method diff --git a/Zend/tests/closure_use_auto_global.phpt b/Zend/tests/closure_use_auto_global.phpt new file mode 100644 index 0000000000..9ab0897e12 --- /dev/null +++ b/Zend/tests/closure_use_auto_global.phpt @@ -0,0 +1,16 @@ +--TEST-- +Cannot use() auto-global +--FILE-- +<?php + +function test() { + $fn = function() use($GLOBALS) { + var_dump($GLOBALS); + }; + $fn(); +} +test(); + +?> +--EXPECTF-- +Fatal error: Cannot use auto-global as lexical variable in %s on line %d diff --git a/Zend/tests/closure_use_parameter_name.phpt b/Zend/tests/closure_use_parameter_name.phpt new file mode 100644 index 0000000000..7ecc6d8dd1 --- /dev/null +++ b/Zend/tests/closure_use_parameter_name.phpt @@ -0,0 +1,14 @@ +--TEST-- +Can't use name of lexical variable for parameter +--FILE-- +<?php + +$a = 1; +$fn = function ($a) use ($a) { + var_dump($a); +}; +$fn(2); + +?> +--EXPECTF-- +Fatal error: Cannot use lexical variable $a as a parameter name in %s on line %d diff --git a/Zend/tests/closure_use_variable_twice.phpt b/Zend/tests/closure_use_variable_twice.phpt new file mode 100644 index 0000000000..06c2645809 --- /dev/null +++ b/Zend/tests/closure_use_variable_twice.phpt @@ -0,0 +1,15 @@ +--TEST-- +Closure cannot use one variable twice +--FILE-- +<?php + +$a = 1; +$fn = function() use ($a, &$a) { + $a = 2; +}; +$fn(); +var_dump($a); + +?> +--EXPECTF-- +Fatal error: Cannot use variable $a twice in %s on line %d diff --git a/Zend/tests/closures/closure_from_callable.inc b/Zend/tests/closures/closure_from_callable.inc new file mode 100644 index 0000000000..5f0f220974 --- /dev/null +++ b/Zend/tests/closures/closure_from_callable.inc @@ -0,0 +1,187 @@ +<?php + +function bar($param1) +{ + return $param1; +} + + +$closure = function($param1) { + return $param1; +}; + +function test($fn) +{ + static $count = 0; + $input = "foo".$count; + $count++; + + $output = $fn($input); + return $input === $output; +} + +class Foo +{ + public static function publicStaticFunction($param1) + { + return $param1; + } + + private static function privateStaticFunction($param1) + { + return $param1; + } + + protected static function protectedStaticFunction($param1) + { + return $param1; + } + + private function privateInstanceFunc($param1) + { + return $param1; + } + + protected function protectedInstanceFunc($param1) + { + return $param1; + } + + + public function publicInstanceFunc($param1) + { + return $param1; + } + + public function closePrivateValid() + { + return Closure::fromCallable([$this, 'privateInstanceFunc']); + } + + public function closePrivateStatic() + { + return Closure::fromCallable([__CLASS__, 'privateStaticFunction']); + } + + public function bar($param1) + { + echo "this is bar\n"; + } + + public function getCallable() + { + return Closure::fromCallable([$this, 'publicInstanceFunc']); + } + + public function getSelfPublicInstance() + { + return Closure::fromCallable([$this, 'publicInstanceFunc']); + } + + public function getSelfColonPublicInstanceMethod() + { + return Closure::fromCallable('self::publicInstanceFunc'); + } +} + + + +class SubFoo extends Foo { + + public function closePrivateStaticInvalid() + { + return Closure::fromCallable([__CLASS__, 'privateStaticFunction']); + } + + + public function closePrivateInvalid() + { + return Closure::fromCallable([$this, 'privateInstanceFunc']); + } + + public function closeProtectedStaticMethod() + { + return Closure::fromCallable([__CLASS__, 'protectedStaticFunction']); + } + + public function closeProtectedValid() + { + return Closure::fromCallable([$this, 'protectedInstanceFunc']); + } + + public function getParentPublicInstanceMethod() + { + return Closure::fromCallable('parent::publicInstanceFunc'); + } + + public function getSelfColonParentPublicInstanceMethod() + { + return Closure::fromCallable('self::publicInstanceFunc'); + } + + + public function getSelfColonParentProtectedInstanceMethod() + { + return Closure::fromCallable('self::protectedInstanceFunc'); + } + + public function getSelfColonParentPrivateInstanceMethod() + { + return Closure::fromCallable('self::privateInstanceFunc'); + } +} + + +class MagicCall +{ + public function __call($name, $arguments) + { + $info = ['__call']; + $info[] = $name; + $info = array_merge($info, $arguments); + return implode(',', $info); + } + + public static function __callStatic($name, $arguments) + { + $info = ['__callStatic']; + $info[] = $name; + $info = array_merge($info, $arguments); + return implode(',', $info); + } +} + + + +class PublicInvokable +{ + public function __invoke($param1) + { + return $param1; + } +} + + +function functionAccessProtected() +{ + $foo = new Foo; + + return Closure::fromCallable([$foo, 'protectedStaticFunction']); +} + +function functionAccessPrivate() +{ + $foo = new Foo; + + return Closure::fromCallable([$foo, 'privateStaticFunction']); +} + + +function functionAccessMethodDoesntExist() +{ + $foo = new Foo; + + return Closure::fromCallable([$foo, 'thisDoesNotExist']); +} + +?> diff --git a/Zend/tests/closures/closure_from_callable_basic.phpt b/Zend/tests/closures/closure_from_callable_basic.phpt new file mode 100644 index 0000000000..2561bbfaa6 --- /dev/null +++ b/Zend/tests/closures/closure_from_callable_basic.phpt @@ -0,0 +1,122 @@ +--TEST-- +Testing Closure::fromCallable() functionality: Basic +--FILE-- +<?php + +include('closure_from_callable.inc'); + +echo 'Access public static function'; +$fn = Closure::fromCallable(['Foo', 'publicStaticFunction']); +echo $fn(" OK".PHP_EOL); + +echo 'Access public static function with different case'; +$fn = Closure::fromCallable(['fOo', 'publicStaticfUNCTION']); +echo $fn(" OK".PHP_EOL); + +echo 'Access public static function with colon scheme'; +$fn = Closure::fromCallable('Foo::publicStaticFunction'); +echo $fn(" OK".PHP_EOL); + +echo 'Access public instance method of object'; +$fn = Closure::fromCallable([new Foo, 'publicInstanceFunc']); +echo $fn(" OK".PHP_EOL); + +echo 'Access public instance method of parent object through parent:: '; +$fn = Closure::fromCallable([new Foo, 'publicInstanceFunc']); +echo $fn(" OK".PHP_EOL); + +echo 'Function that exists'; +$fn = Closure::fromCallable('bar'); +echo $fn(" OK".PHP_EOL); + +echo 'Function that exists with different spelling'; +$fn = Closure::fromCallable('BAR'); +echo $fn(" OK".PHP_EOL); + +echo 'Closure is already a closure'; +$fn = Closure::fromCallable($closure); +echo $fn(" OK".PHP_EOL); + +echo 'Class with public invokable'; +$fn = Closure::fromCallable(new PublicInvokable); +echo $fn(" OK".PHP_EOL); + +echo "Instance return private method as callable"; +$foo = new Foo; +$fn = $foo->closePrivateValid(); +echo $fn(" OK".PHP_EOL); + +echo "Instance return private static method as callable"; +$foo = new Foo; +$fn = $foo->closePrivateStatic(); +echo $fn(" OK".PHP_EOL); + +echo 'Instance return protected static method as callable'; +$subFoo = new SubFoo; +$fn = $subFoo->closeProtectedStaticMethod(); +echo $fn(" OK".PHP_EOL); + +echo 'Subclass closure over parent class protected method'; +$subFoo = new SubFoo; +$fn = $subFoo->closeProtectedValid(); +echo $fn(" OK".PHP_EOL); + +echo 'Subclass closure over parent class static protected method'; +$subFoo = new SubFoo; +$fn = $subFoo->closeProtectedStaticMethod(); +echo $fn(" OK".PHP_EOL); + +echo 'Access public instance method of parent object through "parent::" '; +$subFoo = new SubFoo; +$fn = $subFoo->getParentPublicInstanceMethod(); +echo $fn(" OK".PHP_EOL); + +echo 'Access public instance method of self object through "self::" '; +$foo = new Foo; +$fn = $foo->getSelfColonPublicInstanceMethod(); +echo $fn(" OK".PHP_EOL); + +echo 'Access public instance method of parent object through "self::" to parent method'; +$foo = new SubFoo; +$fn = $foo->getSelfColonParentPublicInstanceMethod(); +echo $fn(" OK".PHP_EOL); + +echo 'Access proteced instance method of parent object through "self::" to parent method'; +$foo = new SubFoo; +$fn = $foo->getSelfColonParentProtectedInstanceMethod(); +echo $fn(" OK".PHP_EOL); + +echo 'MagicCall __call instance method '; +$fn = Closure::fromCallable([new MagicCall, 'nonExistentMethod']); +echo $fn(" OK".PHP_EOL); + +echo 'MagicCall __callStatic static method '; +$fn = Closure::fromCallable(['MagicCall', 'nonExistentMethod']); +echo $fn(" OK".PHP_EOL); + + +?> +===DONE=== +--EXPECT-- + +Access public static function OK +Access public static function with different case OK +Access public static function with colon scheme OK +Access public instance method of object OK +Access public instance method of parent object through parent:: OK +Function that exists OK +Function that exists with different spelling OK +Closure is already a closure OK +Class with public invokable OK +Instance return private method as callable OK +Instance return private static method as callable OK +Instance return protected static method as callable OK +Subclass closure over parent class protected method OK +Subclass closure over parent class static protected method OK +Access public instance method of parent object through "parent::" OK +Access public instance method of self object through "self::" OK +Access public instance method of parent object through "self::" to parent method OK +Access proteced instance method of parent object through "self::" to parent method OK +MagicCall __call instance method __call,nonExistentMethod, OK +MagicCall __callStatic static method __callStatic,nonExistentMethod, OK +===DONE=== diff --git a/Zend/tests/closures/closure_from_callable_error.phpt b/Zend/tests/closures/closure_from_callable_error.phpt new file mode 100644 index 0000000000..d9db90bcad --- /dev/null +++ b/Zend/tests/closures/closure_from_callable_error.phpt @@ -0,0 +1,215 @@ +--TEST-- +Testing Closure::fromCallable() functionality: Errors +--FILE-- +<?php + +include('closure_from_callable.inc'); + +echo 'Cannot access privateInstance method statically'."\n"; +try { + $fn = Closure::fromCallable(['Foo', 'privateInstanceFunc']); + echo "Test failed to fail and return was : ".var_export($fn, true)."\n"; +} +catch (\TypeError $te) { + //This is the expected outcome. +} +catch (\Throwable $t) { + echo "Wrong exception type thrown: ".get_class($t)." : ".$t->getMessage()."\n"; +} + + +echo 'Cannot access privateInstance method statically with colon scheme'."\n"; +try { + $fn = Closure::fromCallable('Foo::privateInstanceFunc'); + echo "Test failed to fail and return was : ".var_export($fn, true)."\n"; +} +catch (\TypeError $te) { + //This is the expected outcome. +} +catch (\Throwable $t) { + echo "Wrong exception type thrown: ".get_class($t)." : ".$t->getMessage()."\n"; +} + +echo 'Cannot access privateInstance method'."\n"; +try { + $fn = Closure::fromCallable([new Foo, 'privateInstanceFunc']); + echo "Test failed to fail and return was : ".var_export($fn, true)."\n"; +} +catch (\TypeError $te) { + //This is the expected outcome. +} +catch (\Throwable $t) { + echo "Wrong exception type thrown: ".get_class($t)." : ".$t->getMessage()."\n"; +} + +echo 'SubClass cannot access private instance method'."\n"; +try { + $fn = Closure::fromCallable([new SubFoo, 'privateInstanceFunc']); + echo "Test failed to fail, closure is : ".var_export($fn, true)."\n"; +} +catch (\TypeError $te) { + //This is the expected outcome. +} +catch (\Throwable $t) { + echo "Wrong exception type thrown: ".get_class($t)." : ".$t->getMessage()."\n"; +} + +echo 'Cannot access private static function of instance'."\n"; +try { + $fn = Closure::fromCallable([new Foo, 'privateStaticFunction']); + echo "Test failed to fail, closure is : ".var_export($fn, true)."\n"; +} +catch (\TypeError $te) { + //This is the expected outcome. +} +catch (\Throwable $t) { + echo "Wrong exception type thrown: ".get_class($t)." : ".$t->getMessage()."\n"; +} + +echo 'Cannot access private static method statically'."\n"; +try { + $fn = Closure::fromCallable(['Foo', 'privateStaticFunction']); + echo "Test failed to fail, closure is : ".var_export($fn, true)."\n"; +} +catch (\TypeError $te) { + //This is the expected outcome. +} +catch (\Throwable $t) { + echo "Wrong exception type thrown: ".get_class($t)." : ".$t->getMessage()."\n"; +} + +echo 'Cannot access private static method statically with colon scheme'."\n"; +try { + $fn = Closure::fromCallable('Foo::privateStaticFunction'); + echo "Test failed to fail, closure is : ".var_export($fn, true)."\n"; +} +catch (\TypeError $te) { + //This is the expected outcome. +} +catch (\Throwable $t) { + echo "Wrong exception type thrown: ".get_class($t)." : ".$t->getMessage()."\n"; +} + +echo 'Non-existent method should fail'."\n"; +try { + $fn = Closure::fromCallable('Foo::nonExistentFunction'); + echo "Test failed to fail, closure is : ".var_export($fn, true)."\n"; +} +catch (\TypeError $te) { + //This is the expected outcome. +} +catch (\Throwable $t) { + echo "Wrong exception type thrown: ".get_class($t)." : ".$t->getMessage()."\n"; +} + +echo 'Non-existent class should fail'."\n"; +try { + $fn = Closure::fromCallable(['NonExistentClass', 'foo']); + echo "Test failed to fail, closure is : ".var_export($fn, true)."\n"; +} +catch (\TypeError $te) { + //This is the expected outcome. +} +catch (\Throwable $t) { + echo "Wrong exception type thrown: ".get_class($t)." : ".$t->getMessage()."\n"; +} + +echo 'Non-existent function should fail'."\n"; +try { + $fn = Closure::fromCallable('thisDoesNotExist'); + echo "Test failed to fail, closure is : ".var_export($fn, true)."\n"; +} +catch (\TypeError $te) { + //This is the expected outcome. +} +catch (\Throwable $t) { + echo "Wrong exception type thrown: ".get_class($t)." : ".$t->getMessage()."\n"; +} + + +echo 'Subclass cannot closure over parent private instance method'."\n"; +try { + $subFoo = new SubFoo; + $fn = $subFoo->closePrivateInvalid(); + echo "Test failed to fail, closure is : ".var_export($fn, true)."\n"; +} +catch (\TypeError $te) { + //This is the expected outcome. +} +catch (\Throwable $t) { + echo "Wrong exception type thrown: ".get_class($t)." : ".$t->getMessage()."\n"; +} + +echo 'Subclass cannot closure over parant private static method'."\n"; +try { + $subFoo = new SubFoo; + $fn = $subFoo->closePrivateStaticInvalid(); + echo "Test failed to fail, closure is : ".var_export($fn, true)."\n"; +} +catch (\TypeError $te) { + //This is the expected outcome. +} +catch (\Throwable $t) { + echo "Wrong exception type thrown: ".get_class($t)." : ".$t->getMessage()."\n"; +} + +echo 'Function scope cannot closure over protected instance method'."\n"; +try { + $fn = functionAccessProtected(); + echo "Test failed to fail, closure is : ".var_export($fn, true)."\n"; +} +catch (\TypeError $te) { + //This is the expected outcome. +} +catch (\Throwable $t) { + echo "Wrong exception type thrown: ".get_class($t)." : ".$t->getMessage()."\n"; +} + +echo 'Function scope cannot closure over private instance method'."\n"; +try { + $fn = functionAccessPrivate(); + echo "Test failed to fail, closure is : ".var_export($fn, true)."\n"; +} +catch (\TypeError $te) { + //This is the expected outcome. +} +catch (\Throwable $t) { + echo "Wrong exception type thrown: ".get_class($t)." : ".$t->getMessage()."\n"; +} + +echo 'Access private instance method of parent object through "self::" to parent method'."\n"; +try { + $foo = new SubFoo; + $fn = $foo->getSelfColonParentPrivateInstanceMethod(); + echo "Test failed to fail, closure is : ".var_export($fn, true)."\n"; +} +catch (\TypeError $te) { + //This is the expected outcome. +} +catch (\Throwable $t) { + echo "Wrong exception type thrown: ".get_class($t)." : ".$t->getMessage()."\n"; +} + +echo "OK\n"; + +?> +===DONE=== +--EXPECT-- + +Cannot access privateInstance method statically +Cannot access privateInstance method statically with colon scheme +Cannot access privateInstance method +SubClass cannot access private instance method +Cannot access private static function of instance +Cannot access private static method statically +Cannot access private static method statically with colon scheme +Non-existent method should fail +Non-existent class should fail +Non-existent function should fail +Subclass cannot closure over parent private instance method +Subclass cannot closure over parant private static method +Function scope cannot closure over protected instance method +Function scope cannot closure over private instance method +Access private instance method of parent object through "self::" to parent method +OK +===DONE=== diff --git a/Zend/tests/closures/closure_from_callable_lsb.phpt b/Zend/tests/closures/closure_from_callable_lsb.phpt new file mode 100644 index 0000000000..950985bdad --- /dev/null +++ b/Zend/tests/closures/closure_from_callable_lsb.phpt @@ -0,0 +1,21 @@ +--TEST-- +Testing Closure::fromCallable() functionality: Late static binding +--FILE-- +<?php + +class A { + public static function test() { + var_dump(static::class); + } +} + +class B extends A { +} + +Closure::fromCallable(['A', 'test'])(); +Closure::fromCallable(['B', 'test'])(); + +?> +--EXPECT-- +string(1) "A" +string(1) "B" diff --git a/Zend/tests/closures/closure_from_callable_non_static_statically.phpt b/Zend/tests/closures/closure_from_callable_non_static_statically.phpt new file mode 100644 index 0000000000..17d39c052e --- /dev/null +++ b/Zend/tests/closures/closure_from_callable_non_static_statically.phpt @@ -0,0 +1,20 @@ +--TEST-- +Testing Closure::fromCallable() functionality: Getting non-static method statically +--FILE-- +<?php + +class A { + public function method() { + } +} + +try { + $fn = Closure::fromCallable(['A', 'method']); + $fn(); +} catch (TypeError $e) { + echo $e->getMessage(), "\n"; +} + +?> +--EXPECT-- +Failed to create closure from callable: non-static method A::method() should not be called statically diff --git a/Zend/tests/closures/closure_from_callable_rebinding.phpt b/Zend/tests/closures/closure_from_callable_rebinding.phpt new file mode 100644 index 0000000000..6fb5c6ffc1 --- /dev/null +++ b/Zend/tests/closures/closure_from_callable_rebinding.phpt @@ -0,0 +1,20 @@ +--TEST-- +Testing Closure::fromCallable() functionality: Rebinding +--FILE-- +<?php + +class A { + public function method() { + var_dump($this); + } +} + +class B { +} + +$fn = Closure::fromCallable([new A, 'method']); +$fn->call(new B); + +?> +--EXPECTF-- +Warning: Cannot bind method A::method() to object of class B in %s on line %d diff --git a/Zend/tests/closures/closure_from_callable_reflection.phpt b/Zend/tests/closures/closure_from_callable_reflection.phpt new file mode 100644 index 0000000000..af40193fba --- /dev/null +++ b/Zend/tests/closures/closure_from_callable_reflection.phpt @@ -0,0 +1,46 @@ +--TEST-- +Testing Closure::fromCallable() functionality: Reflection +--FILE-- +<?php + +class Bar { + public static function staticMethod(Bar $bar, int $int, $none) {} + public static function instanceMethod(Bar $bar, int $int, $none) {} +} + +function foo(Bar $bar, int $int, $none) { + +} + +$fn = function (Bar $bar, int $x, $none) {}; +$bar = new Bar(); + +$callables = [ + 'foo', + $fn, + 'Bar::staticMethod', + [$bar, 'instanceMethod'] +]; + + +foreach ($callables as $callable) { + $closure = Closure::fromCallable($callable); + $refl = new ReflectionFunction($closure); + foreach ($refl->getParameters() as $param) { + if ($param->hasType()) { + $type = $param->getType(); + echo $type->getName() . "\n"; + } + } +} + +?> +--EXPECTF-- +Bar +int +Bar +int +Bar +int +Bar +int diff --git a/Zend/tests/constant_expressions_dynamic.phpt b/Zend/tests/constant_expressions_dynamic.phpt index d038591036..686dcc1d11 100644 --- a/Zend/tests/constant_expressions_dynamic.phpt +++ b/Zend/tests/constant_expressions_dynamic.phpt @@ -44,7 +44,9 @@ var_dump( ); ?> ---EXPECT-- +--EXPECTF-- + +Warning: A non-numeric value encountered in %s on line %d int(3) string(4) "1foo" bool(false) diff --git a/Zend/tests/constant_expressions_self_referencing_array.phpt b/Zend/tests/constant_expressions_self_referencing_array.phpt index 63f2b20ef5..c584b5d503 100644 --- a/Zend/tests/constant_expressions_self_referencing_array.phpt +++ b/Zend/tests/constant_expressions_self_referencing_array.phpt @@ -9,7 +9,7 @@ class A { var_dump(A::FOO); ?> --EXPECTF-- -Fatal error: Uncaught Error: Cannot declare self-referencing constant 'self::FOO' in %s:%d +Fatal error: Uncaught Error: Cannot declare self-referencing constant 'self::BAR' in %s:%d Stack trace: #0 {main} thrown in %s on line %d diff --git a/Zend/tests/dynamic_call_005.phpt b/Zend/tests/dynamic_call_005.phpt new file mode 100644 index 0000000000..840e298b82 --- /dev/null +++ b/Zend/tests/dynamic_call_005.phpt @@ -0,0 +1,29 @@ +--TEST-- +Dynamic calls to scope introspection functions are forbidden +--FILE-- +<?php + +function test_calls($func) { + $i = 1; + + array_map($func, [['i' => new stdClass]]); + var_dump($i); + + $func(['i' => new stdClass]); + var_dump($i); + + call_user_func($func, ['i' => new stdClass]); + var_dump($i); +} +test_calls('extract'); + +?> +--EXPECTF-- +Warning: Cannot call extract() dynamically in %s on line %d +int(1) + +Warning: Cannot call extract() dynamically in %s on line %d +int(1) + +Warning: Cannot call extract() dynamically in %s on line %d +int(1) diff --git a/Zend/tests/dynamic_call_006.phpt b/Zend/tests/dynamic_call_006.phpt new file mode 100644 index 0000000000..058e22fda0 --- /dev/null +++ b/Zend/tests/dynamic_call_006.phpt @@ -0,0 +1,48 @@ +--TEST-- +Dynamic calls to scope introspection functions are forbidden (function variations) +--FILE-- +<?php +function test() { + $func = 'extract'; + $func(['a' => 'b']); + + $func = 'compact'; + $func(['a']); + + $func = 'parse_str'; + $func('a=b'); + + $func = 'get_defined_vars'; + $func(); + + $func = 'assert'; + $func('1==2'); + + $func = 'func_get_args'; + $func(); + + $func = 'func_get_arg'; + $func(1); + + $func = 'func_num_args'; + $func(); +} +test(); + +?> +--EXPECTF-- +Warning: Cannot call extract() dynamically in %s on line %d + +Warning: Cannot call compact() dynamically in %s on line %d + +Warning: Cannot call parse_str() with a single argument dynamically in %s on line %d + +Warning: Cannot call get_defined_vars() dynamically in %s on line %d + +Warning: Cannot call assert() with string argument dynamically in %s on line %d + +Warning: Cannot call func_get_args() dynamically in %s on line %d + +Warning: Cannot call func_get_arg() dynamically in %s on line %d + +Warning: Cannot call func_num_args() dynamically in %s on line %d diff --git a/Zend/tests/dynamic_call_007.phpt b/Zend/tests/dynamic_call_007.phpt new file mode 100644 index 0000000000..61ae182914 --- /dev/null +++ b/Zend/tests/dynamic_call_007.phpt @@ -0,0 +1,17 @@ +--TEST-- +Dynamic calls to scope introspection functions are forbidden (misoptimization) +--FILE-- +<?php + +function test() { + $i = 1; + array_map('extract', [['i' => new stdClass]]); + $i += 1; + var_dump($i); +} +test(); + +?> +--EXPECTF-- +Warning: Cannot call extract() dynamically in %s on line %d +int(2) diff --git a/Zend/tests/dynamic_call_008.phpt b/Zend/tests/dynamic_call_008.phpt new file mode 100644 index 0000000000..24240472d1 --- /dev/null +++ b/Zend/tests/dynamic_call_008.phpt @@ -0,0 +1,13 @@ +--TEST-- +Don't optimize dynamic call to non-dynamic one if it drops the warning +--FILE-- +<?php + +function test() { + ((string) 'extract')(['a' => 42]); +} +test(); + +?> +--EXPECTF-- +Warning: Cannot call extract() dynamically in %s on line %d diff --git a/Zend/tests/dynamic_call_to_ref_returning_function.phpt b/Zend/tests/dynamic_call_to_ref_returning_function.phpt new file mode 100644 index 0000000000..c4b6a9bcff --- /dev/null +++ b/Zend/tests/dynamic_call_to_ref_returning_function.phpt @@ -0,0 +1,39 @@ +--TEST-- +When performing a dynamic call to a ret-by-ref function, the reference should be unwrapped +--FILE-- +<?php + +namespace Foo; + +function &retRef($x) { + return $x; +} + +var_dump(call_user_func('Foo\retRef', 42)); +var_dump(call_user_func_array('Foo\retRef', [42])); + +$closure = function &($x) { + return $x; +}; +var_dump($closure->call(new class {}, 42)); + +var_dump((new \ReflectionFunction('Foo\retRef'))->invoke(42)); +var_dump((new \ReflectionFunction('Foo\retRef'))->invokeArgs([42])); + +class Bar { + function &method($x) { + return $x; + } +} +var_dump((new \ReflectionMethod('Foo\Bar', 'method'))->invoke(new Bar, 42)); +var_dump((new \ReflectionMethod('Foo\Bar', 'method'))->invokeArgs(new Bar, [42])); + +?> +--EXPECT-- +int(42) +int(42) +int(42) +int(42) +int(42) +int(42) +int(42) diff --git a/Zend/tests/empty_str_offset.phpt b/Zend/tests/empty_str_offset.phpt index 486c052dc4..49e175dd21 100644 --- a/Zend/tests/empty_str_offset.phpt +++ b/Zend/tests/empty_str_offset.phpt @@ -8,6 +8,8 @@ print "- empty ---\n"; $str = "test0123"; var_dump(empty($str[-1])); +var_dump(empty($str[-10])); +var_dump(empty($str[-4])); // 0 var_dump(empty($str[0])); var_dump(empty($str[1])); var_dump(empty($str[4])); // 0 @@ -17,6 +19,8 @@ var_dump(empty($str[10000])); // non-numeric offsets print "- string ---\n"; var_dump(empty($str['-1'])); +var_dump(empty($str['-10'])); +var_dump(empty($str['-4'])); // 0 var_dump(empty($str['0'])); var_dump(empty($str['1'])); var_dump(empty($str['4'])); // 0 @@ -31,6 +35,8 @@ print "- null ---\n"; var_dump(empty($str[null])); print "- double ---\n"; var_dump(empty($str[-1.1])); +var_dump(empty($str[-10.5])); +var_dump(empty($str[-4.1])); var_dump(empty($str[-0.8])); var_dump(empty($str[-0.1])); var_dump(empty($str[0.2])); @@ -50,6 +56,8 @@ print "done\n"; ?> --EXPECTF-- - empty --- +bool(false) +bool(true) bool(true) bool(false) bool(false) @@ -58,6 +66,8 @@ bool(false) bool(true) bool(true) - string --- +bool(false) +bool(true) bool(true) bool(false) bool(false) @@ -72,6 +82,8 @@ bool(true) - null --- bool(false) - double --- +bool(false) +bool(true) bool(true) bool(false) bool(false) diff --git a/Zend/tests/entry_block_with_predecessors.phpt b/Zend/tests/entry_block_with_predecessors.phpt new file mode 100644 index 0000000000..ffc3147f1c --- /dev/null +++ b/Zend/tests/entry_block_with_predecessors.phpt @@ -0,0 +1,33 @@ +--TEST-- +For SSA form the entry block should have no predecessors +--FILE-- +<?php + +function test() { + while (true) { + var_dump($a + 1); + $a = 1; + if (@$i++) { + break; + } + } +} + +function test2() { + while (true) { + $a = 42; + if (@$i++ > 1) { + break; + } + $a = new stdClass; + } +} + +test(); +test2(); + +?> +--EXPECTF-- +Notice: Undefined variable: a in %s on line %d +int(1) +int(2) diff --git a/Zend/tests/error_reporting06.phpt b/Zend/tests/error_reporting06.phpt index 285a623f2b..175ea37e80 100644 --- a/Zend/tests/error_reporting06.phpt +++ b/Zend/tests/error_reporting06.phpt @@ -11,7 +11,7 @@ function foo1($arg) { function foo2($arg) { } -function foo3($arg) { +function foo3() { echo $undef3; throw new Exception("test"); } diff --git a/Zend/tests/error_reporting07.phpt b/Zend/tests/error_reporting07.phpt index c63efae604..09b7690d3c 100644 --- a/Zend/tests/error_reporting07.phpt +++ b/Zend/tests/error_reporting07.phpt @@ -11,7 +11,7 @@ function foo1($arg) { function foo2($arg) { } -function foo3($arg) { +function foo3() { echo $undef3; throw new Exception("test"); } diff --git a/Zend/tests/error_reporting08.phpt b/Zend/tests/error_reporting08.phpt index edf3292779..c9945046ee 100644 --- a/Zend/tests/error_reporting08.phpt +++ b/Zend/tests/error_reporting08.phpt @@ -11,7 +11,7 @@ function foo1($arg) { function foo2($arg) { } -function foo3($arg) { +function foo3() { error_reporting(E_ALL|E_STRICT); echo $undef3; throw new Exception("test"); diff --git a/Zend/tests/exception_009.phpt b/Zend/tests/exception_009.phpt index b22b3aa66e..32b048c40b 100644 --- a/Zend/tests/exception_009.phpt +++ b/Zend/tests/exception_009.phpt @@ -25,4 +25,4 @@ throw new my_exception; ?> --EXPECT-- -Catchable fatal error: Object of class stdClass could not be converted to string in Unknown on line 0 +Recoverable fatal error: Object of class stdClass could not be converted to string in Unknown on line 0 diff --git a/Zend/tests/foreach_list_keyed.phpt b/Zend/tests/foreach_list_keyed.phpt new file mode 100644 index 0000000000..f5fab4e342 --- /dev/null +++ b/Zend/tests/foreach_list_keyed.phpt @@ -0,0 +1,36 @@ +--TEST-- +foreach with list syntax, keyed +--FILE-- +<?php + +$points = [ + ["x" => 1, "y" => 2], + ["x" => 2, "y" => 1] +]; + +foreach ($points as list("x" => $x, "y" => $y)) { + var_dump($x, $y); +} + +echo PHP_EOL; + +$invertedPoints = [ + "x" => [1, 2], + "y" => [2, 1] +]; + +foreach ($invertedPoints as list(0 => $row1, 1 => $row2)) { + var_dump($row1, $row2); +} + +?> +--EXPECT-- +int(1) +int(2) +int(2) +int(1) + +int(1) +int(2) +int(2) +int(1) diff --git a/Zend/tests/fr47160.phpt b/Zend/tests/fr47160.phpt index ed2f15f990..786183c0c1 100644 --- a/Zend/tests/fr47160.phpt +++ b/Zend/tests/fr47160.phpt @@ -5,7 +5,7 @@ Calling method from array class Hello { public function world($x) { - echo "Hello, $x\n"; return $this; + echo "Hello, $x\n";return $this; } } @@ -37,8 +37,16 @@ class Magic3 { } $f = array('Hello','world'); -var_dump($f('you')); -var_dump(call_user_func($f, 'you')); +try { + var_dump($f('you')); +} catch (Throwable $e) { + echo "Exception: " . $e->getMessage() . "\n"; +} +try { + var_dump(call_user_func($f, 'you')); +} catch (Throwable $e) { + echo "Exception: " . $e->getMessage() . "\n"; +} printf("-----\n"); @@ -101,35 +109,31 @@ var_dump(call_user_func($f, 'you')); --EXPECTF-- Deprecated: Non-static method Hello::world() should not be called statically in %s on line %d Hello, you - -Notice: Undefined variable: this in %s on line %d -NULL +Exception: Using $this when not in object context Deprecated: %son-static method Hello::world() should not be called statically in %s on line %d Hello, you - -Notice: Undefined variable: this in %s on line %d -NULL +Exception: Using $this when not in object context ----- Hello, again -object(Hello)#1 (0) { +object(Hello)#%d (0) { } Hello, again -object(Hello)#1 (0) { +object(Hello)#%d (0) { } ----- Hello, there -object(Hello)#2 (0) { +object(Hello)#%d (0) { } Hello, there -object(Hello)#2 (0) { +object(Hello)#%d (0) { } ----- Hello, devs -object(Hello)#4 (0) { +object(Hello)#%d (0) { } Hello, devs -object(Hello)#4 (0) { +object(Hello)#%d (0) { } ----- Magic::__call called (foo)! diff --git a/Zend/tests/func_get_args.phpt b/Zend/tests/func_get_args.phpt new file mode 100644 index 0000000000..eea8ae4354 --- /dev/null +++ b/Zend/tests/func_get_args.phpt @@ -0,0 +1,10 @@ +--TEST-- +Testing func_get_args() +--FILE-- +<?php + +func_get_args(); + +?> +--EXPECTF-- +Warning: func_get_args(): Called from the global scope - no function context in %s on line 3 diff --git a/Zend/tests/function_arguments/argument_count_correct.phpt b/Zend/tests/function_arguments/argument_count_correct.phpt new file mode 100644 index 0000000000..44a87b8ba8 --- /dev/null +++ b/Zend/tests/function_arguments/argument_count_correct.phpt @@ -0,0 +1,20 @@ +--TEST-- +Call function with correct number of arguments +--FILE-- +<?php +function foo() { } +foo(); + +function bar($foo, $bar) { } +bar(1, 2); + +function bat(int $foo, string $bar) { } +bat(123, "foo"); +bat("123", "foo"); + +$fp = fopen(__FILE__, "r"); +fclose($fp); + +echo "done"; +--EXPECT-- +done
\ No newline at end of file diff --git a/Zend/tests/function_arguments/argument_count_correct_strict.phpt b/Zend/tests/function_arguments/argument_count_correct_strict.phpt new file mode 100644 index 0000000000..bfce61f0c9 --- /dev/null +++ b/Zend/tests/function_arguments/argument_count_correct_strict.phpt @@ -0,0 +1,20 @@ +--TEST-- +Call function with correct number of arguments with strict types +--FILE-- +<?php +declare(strict_types=1); +function foo() { } +foo(); + +function bar($foo, $bar) { } +bar(1, 2); + +function bat(int $foo, string $bar) { } +bat(123, "foo"); + +$fp = fopen(__FILE__, "r"); +fclose($fp); + +echo "done"; +--EXPECT-- +done
\ No newline at end of file diff --git a/Zend/tests/function_arguments/argument_count_incorrect_internal.phpt b/Zend/tests/function_arguments/argument_count_incorrect_internal.phpt new file mode 100644 index 0000000000..9d8d8bb7db --- /dev/null +++ b/Zend/tests/function_arguments/argument_count_incorrect_internal.phpt @@ -0,0 +1,10 @@ +--TEST-- +Call internal function with incorrect number of arguments +--FILE-- +<?php +substr("foo"); +array_diff([]); +--EXPECTF-- +Warning: substr() expects at least 2 parameters, 1 given in %s + +Warning: array_diff(): at least 2 parameters are required, 1 given in %s
\ No newline at end of file diff --git a/Zend/tests/function_arguments/argument_count_incorrect_internal_strict.phpt b/Zend/tests/function_arguments/argument_count_incorrect_internal_strict.phpt new file mode 100644 index 0000000000..33748649da --- /dev/null +++ b/Zend/tests/function_arguments/argument_count_incorrect_internal_strict.phpt @@ -0,0 +1,18 @@ +--TEST-- +Call internal function with incorrect number of arguments with strict types +--FILE-- +<?php +declare(strict_types=1); +try { + substr("foo"); +} catch (\Error $e) { + echo get_class($e) . PHP_EOL; + echo $e->getMessage() . PHP_EOL; +} + +array_diff([]); +--EXPECTF-- +ArgumentCountError +substr() expects at least 2 parameters, 1 given + +Warning: array_diff(): at least 2 parameters are required, 1 given in %s
\ No newline at end of file diff --git a/Zend/tests/function_arguments/argument_count_incorrect_userland.phpt b/Zend/tests/function_arguments/argument_count_incorrect_userland.phpt new file mode 100644 index 0000000000..97faa4eb5c --- /dev/null +++ b/Zend/tests/function_arguments/argument_count_incorrect_userland.phpt @@ -0,0 +1,44 @@ +--TEST-- +Call userland function with incorrect number of arguments +--FILE-- +<?php +try { + function foo($bar) { } + foo(); +} catch (\Error $e) { + echo get_class($e) . PHP_EOL; + echo $e->getMessage() . PHP_EOL; +} + +try { + function bar($foo, $bar) { } + bar(1); +} catch (\Error $e) { + echo get_class($e) . PHP_EOL; + echo $e->getMessage() . PHP_EOL; +} + +function bat(int $foo, string $bar) { } + +try { + bat(123); +} catch (\Error $e) { + echo get_class($e) . PHP_EOL; + echo $e->getMessage() . PHP_EOL; +} + +try { + bat("123"); +} catch (\Error $e) { + echo get_class($e) . PHP_EOL; + echo $e->getMessage() . PHP_EOL; +} +--EXPECTF-- +ArgumentCountError +Too few arguments to function foo(), 0 passed in %s and exactly 1 expected +ArgumentCountError +Too few arguments to function bar(), 1 passed in %s and exactly 2 expected +ArgumentCountError +Too few arguments to function bat(), 1 passed in %s and exactly 2 expected +ArgumentCountError +Too few arguments to function bat(), 1 passed in %s and exactly 2 expected
\ No newline at end of file diff --git a/Zend/tests/function_arguments/argument_count_incorrect_userland_strict.phpt b/Zend/tests/function_arguments/argument_count_incorrect_userland_strict.phpt new file mode 100644 index 0000000000..9029dc2625 --- /dev/null +++ b/Zend/tests/function_arguments/argument_count_incorrect_userland_strict.phpt @@ -0,0 +1,54 @@ +--TEST-- +Call userland function with incorrect number of arguments with strict types +--FILE-- +<?php +declare(strict_types=1); +try { + function foo($bar) { } + foo(); +} catch (\Error $e) { + echo get_class($e) . PHP_EOL; + echo $e->getMessage() . PHP_EOL; +} + +try { + function bar($foo, $bar) { } + bar(1); +} catch (\Error $e) { + echo get_class($e) . PHP_EOL; + echo $e->getMessage() . PHP_EOL; +} + +function bat(int $foo, string $bar) { } + +try { + bat(123); +} catch (\Error $e) { + echo get_class($e) . PHP_EOL; + echo $e->getMessage() . PHP_EOL; +} + +try { + bat("123"); +} catch (\Error $e) { + echo get_class($e) . PHP_EOL; + echo $e->getMessage() . PHP_EOL; +} + +try { + bat(123, 456); +} catch (\Error $e) { + echo get_class($e) . PHP_EOL; + echo $e->getMessage() . PHP_EOL; +} +--EXPECTF-- +ArgumentCountError +Too few arguments to function foo(), 0 passed in %s and exactly 1 expected +ArgumentCountError +Too few arguments to function bar(), 1 passed in %s and exactly 2 expected +ArgumentCountError +Too few arguments to function bat(), 1 passed in %s and exactly 2 expected +TypeError +Argument 1 passed to bat() must be of the type integer, string given, called in %s +TypeError +Argument 2 passed to bat() must be of the type string, integer given, called in %s
\ No newline at end of file diff --git a/Zend/tests/gc_013.phpt b/Zend/tests/gc_013.phpt index 9209ca2b40..0c5424086a 100644 --- a/Zend/tests/gc_013.phpt +++ b/Zend/tests/gc_013.phpt @@ -10,9 +10,9 @@ for ($i = 0; $i < 10001; $i++) { } $a[] = "xxx"; unset($a); -var_dump(gc_collect_cycles()); +var_dump(gc_collect_cycles() > 0); echo "ok\n"; ?> --EXPECT-- -int(2) +bool(true) ok diff --git a/Zend/tests/gc_014.phpt b/Zend/tests/gc_014.phpt index cd5a15e681..4fd8948af5 100644 --- a/Zend/tests/gc_014.phpt +++ b/Zend/tests/gc_014.phpt @@ -12,9 +12,9 @@ for ($i = 0; $i < 10001; $i++) { unset($b); $a->b = "xxx"; unset($a); -var_dump(gc_collect_cycles()); +var_dump(gc_collect_cycles() > 0); echo "ok\n"; ?> --EXPECT-- -int(2) +bool(true) ok diff --git a/Zend/tests/gc_015.phpt b/Zend/tests/gc_015.phpt index df85836ed8..24acddeae1 100644 --- a/Zend/tests/gc_015.phpt +++ b/Zend/tests/gc_015.phpt @@ -12,9 +12,9 @@ $a->b = "xxx"; unset($c); unset($a); unset($b); -var_dump(gc_collect_cycles()); +var_dump(gc_collect_cycles() > 0); echo "ok\n"; ?> --EXPECT-- -int(2) +bool(true) ok diff --git a/Zend/tests/gc_017.phpt b/Zend/tests/gc_017.phpt index 50be61025f..a1a8c3eaf6 100644 --- a/Zend/tests/gc_017.phpt +++ b/Zend/tests/gc_017.phpt @@ -10,7 +10,6 @@ class Node { public $parent; function __construct($name) { $this->name = $name; - $this->children = array(); $this->parent = null; } function insert($node) { @@ -32,12 +31,12 @@ $a->insert($c); unset($a); unset($b); unset($c); -var_dump(gc_collect_cycles()); +var_dump(gc_collect_cycles() >= 7); echo "ok\n" ?> --EXPECTF-- string(1) "%s" string(1) "%s" string(1) "%s" -int(10) +bool(true) ok diff --git a/Zend/tests/gc_033.phpt b/Zend/tests/gc_033.phpt index bcd1541254..2db10196ad 100644 --- a/Zend/tests/gc_033.phpt +++ b/Zend/tests/gc_033.phpt @@ -1,5 +1,7 @@ --TEST-- GC 033: Crash in GC while run with phpspec +--INI-- +zend.enable_gc = 1 --FILE-- <?php $a = new stdClass(); diff --git a/Zend/tests/gc_035.phpt b/Zend/tests/gc_035.phpt index 985264c770..177c3101f9 100644 --- a/Zend/tests/gc_035.phpt +++ b/Zend/tests/gc_035.phpt @@ -1,5 +1,7 @@ --TEST-- GC 035: Lost inner-cycles garbage +--INI-- +zend.enable_gc = 1 --FILE-- <?php class A { diff --git a/Zend/tests/generators/bug72523.phpt b/Zend/tests/generators/bug72523.phpt new file mode 100644 index 0000000000..74dc583974 --- /dev/null +++ b/Zend/tests/generators/bug72523.phpt @@ -0,0 +1,15 @@ +--TEST-- +Bug #72523 (dtrace issue with reflection (failed test)) +--FILE-- +<?php + +$gen = (new class() { + function a() { + yield "okey"; + } +})->a(); + +var_dump($gen->current()); +?> +--EXPECT-- +string(4) "okey" diff --git a/Zend/tests/generators/bug74157.phpt b/Zend/tests/generators/bug74157.phpt new file mode 100644 index 0000000000..d5f0233aec --- /dev/null +++ b/Zend/tests/generators/bug74157.phpt @@ -0,0 +1,23 @@ +--TEST-- +Bug #74157 (Segfault with nested generators) +--FILE-- +<?php + +function a() { + $a = $b = $c = 2; + foreach(range(1, 5) as $v) { + yield $v; + } + return; +} + +foreach (a(range(1, 3)) as $a) { + var_dump($a); +} +?> +--EXPECTF-- +int(1) +int(2) +int(3) +int(4) +int(5) diff --git a/Zend/tests/generators/bug74606.phpt b/Zend/tests/generators/bug74606.phpt new file mode 100644 index 0000000000..cfb7f7f8cd --- /dev/null +++ b/Zend/tests/generators/bug74606.phpt @@ -0,0 +1,29 @@ +--TEST-- +Bug #74606 (Segfault within try/catch/finally nesting in Generators) +--FILE-- +<?php + +function gen() { + $array = ["foo"]; + $array[] = "bar"; + + foreach ($array as $item) { + try { + try { + yield; + } finally { + echo "fin $item\n"; + } + } catch (\Exception $e) { + echo "catch\n"; + continue; + } + } +} +gen()->throw(new Exception); + +?> +--EXPECT-- +fin foo +catch +fin bar diff --git a/Zend/tests/generators/bug75396.phpt b/Zend/tests/generators/bug75396.phpt new file mode 100644 index 0000000000..6d5abf518f --- /dev/null +++ b/Zend/tests/generators/bug75396.phpt @@ -0,0 +1,22 @@ +--TEST-- +Bug #75396: Exit inside generator finally results in fatal error +--FILE-- +<?php + +$gen = (function () { + yield 42; + + try { + echo "Try\n"; + exit("Exit\n"); + } finally { + echo "Finally\n"; + } +})(); + +$gen->send("x"); + +?> +--EXPECT-- +Try +Exit diff --git a/Zend/tests/generators/gc_with_root_parent_mismatch.phpt b/Zend/tests/generators/gc_with_root_parent_mismatch.phpt new file mode 100644 index 0000000000..ee388b1c76 --- /dev/null +++ b/Zend/tests/generators/gc_with_root_parent_mismatch.phpt @@ -0,0 +1,27 @@ +--TEST-- +Generator GC when the yield from parent chain does not reach the root +--FILE-- +<?php + +function root() { + yield 1; + yield 2; +} + +function delegate($gen) { + yield from $gen; +} + +$gen = delegate(delegate(root())); +$gen1 = delegate(delegate($gen)); +$gen2 = delegate(delegate($gen)); +var_dump($gen1->current()); +var_dump($gen2->current()); +$gen1->next(); +$gen1->next(); +gc_collect_cycles(); + +?> +--EXPECT-- +int(1) +int(1) diff --git a/Zend/tests/generators/gc_with_yield_from.phpt b/Zend/tests/generators/gc_with_yield_from.phpt new file mode 100644 index 0000000000..952352c853 --- /dev/null +++ b/Zend/tests/generators/gc_with_yield_from.phpt @@ -0,0 +1,47 @@ +--TEST-- +Verify yield from on generators being properly cycle collected +--INI-- +zend.enable_gc = 1 +--FILE-- +<?php + +function root() { + global $gens; // create cyclic reference to root + try { + yield 1; + } finally { + var_dump($gens); + } +} + +function gen($x) { + global $gens; + yield from $gens[] = $x ? gen(--$x) : root(); +} + +$gen = $gens[] = gen(2); +var_dump($gen->current()); +unset($gen, $gens); +print "collect\n"; +gc_collect_cycles(); +print "end\n"; + +?> +--EXPECT-- +int(1) +collect +array(4) { + [0]=> + object(Generator)#1 (0) { + } + [1]=> + object(Generator)#2 (0) { + } + [2]=> + object(Generator)#3 (0) { + } + [3]=> + object(Generator)#4 (0) { + } +} +end diff --git a/Zend/tests/generators/generator_with_arg_unpacking.phpt b/Zend/tests/generators/generator_with_arg_unpacking.phpt new file mode 100644 index 0000000000..edf0bafd31 --- /dev/null +++ b/Zend/tests/generators/generator_with_arg_unpacking.phpt @@ -0,0 +1,12 @@ +--TEST-- +Generators with arguments unpacking +--FILE-- +<?php +(function() { yield; })(...range(1, 16384)); +call_user_func_array(function() { yield; }, range(1, 16384)); +$g = (function() { yield; })(...range(1, 16384)); +$g = call_user_func_array(function() { yield; }, range(1, 16384)); +echo "OK\n"; +?> +--EXPECT-- +OK
\ No newline at end of file diff --git a/Zend/tests/generators/generator_with_type_check.phpt b/Zend/tests/generators/generator_with_type_check.phpt new file mode 100644 index 0000000000..2aa16532dc --- /dev/null +++ b/Zend/tests/generators/generator_with_type_check.phpt @@ -0,0 +1,13 @@ +--TEST-- +Generator wit type check +--FILE-- +<?php +function gen(array $a) { yield; } +gen(42); +?> +--EXPECTF-- +Fatal error: Uncaught TypeError: Argument 1 passed to gen() must be of the type array, integer given, called in %sgenerator_with_type_check.php on line 3 and defined in %sgenerator_with_type_check.php:2 +Stack trace: +#0 %sgenerator_with_type_check.php(3): gen(42) +#1 {main} + thrown in %sgenerator_with_type_check.php on line 2 diff --git a/Zend/tests/generators/generator_with_type_check_2.phpt b/Zend/tests/generators/generator_with_type_check_2.phpt new file mode 100644 index 0000000000..d8ea4fbf0d --- /dev/null +++ b/Zend/tests/generators/generator_with_type_check_2.phpt @@ -0,0 +1,22 @@ +--TEST-- +Generator wit type check +--FILE-- +<?php +function gen(array $a) { yield; } +try { + gen(42); +} catch (TypeError $e) { + echo $e->getMessage()."\n"; +} + +try { + foreach (gen(42) as $val) { + var_dump($val); + } +} catch (TypeError $e) { + echo $e->getMessage()."\n"; +} +?> +--EXPECTF-- +Argument 1 passed to gen() must be of the type array, integer given, called in %sgenerator_with_type_check_2.php on line 4 +Argument 1 passed to gen() must be of the type array, integer given, called in %sgenerator_with_type_check_2.php on line 10 diff --git a/Zend/tests/generators/return_from_by_ref_generator.phpt b/Zend/tests/generators/return_from_by_ref_generator.phpt new file mode 100644 index 0000000000..32bebfbbde --- /dev/null +++ b/Zend/tests/generators/return_from_by_ref_generator.phpt @@ -0,0 +1,20 @@ +--TEST-- +Return from by-ref generator +--FILE-- +<?php + +function &gen() { + yield; + $arr = [42]; + return $arr[0]; +} + +function gen2() { + var_dump(yield from gen()); +} + +gen2()->next(); + +?> +--EXPECT-- +int(42) diff --git a/Zend/tests/generators/yield_from_iterator_agregate.phpt b/Zend/tests/generators/yield_from_iterator_agregate.phpt new file mode 100644 index 0000000000..3bd61e0b5a --- /dev/null +++ b/Zend/tests/generators/yield_from_iterator_agregate.phpt @@ -0,0 +1,17 @@ +--TEST-- +yield from with an IteratorAggregate +--FILE-- +<?php +class foo implements \IteratorAggregate { + public $prop = 1; + function getIterator() { + var_dump($this->prop); + yield; + } +} +(function(){ + yield from new foo; +})()->next(); +?> +--EXPECT-- +int(1) diff --git a/Zend/tests/global_with_side_effect_name.phpt b/Zend/tests/global_with_side_effect_name.phpt new file mode 100644 index 0000000000..a1ee240c48 --- /dev/null +++ b/Zend/tests/global_with_side_effect_name.phpt @@ -0,0 +1,22 @@ +--TEST-- +Global variable import using a name with side effects +--FILE-- +<?php + +function sf($arg) { + echo "called\n"; + return $arg; +} + +function test() { + global ${sf("a")}; + var_dump($a); +} + +$a = 42; +test(); + +?> +--EXPECT-- +called +int(42) diff --git a/Zend/tests/incompat_ctx_user.phpt b/Zend/tests/incompat_ctx_user.phpt index f05268cee9..25c95ba219 100644 --- a/Zend/tests/incompat_ctx_user.phpt +++ b/Zend/tests/incompat_ctx_user.phpt @@ -10,11 +10,12 @@ class B { function bar() { A::foo(); } } $b = new B; -$b->bar(); - +try { + $b->bar(); +} catch (Throwable $e) { + echo "Exception: " . $e->getMessage() . "\n"; +} ?> --EXPECTF-- Deprecated: Non-static method A::foo() should not be called statically in %s on line %d - -Notice: Undefined variable: this in %s on line %d -string(1) "A" +Exception: Using $this when not in object context diff --git a/Zend/tests/indexing_001.phpt b/Zend/tests/indexing_001.phpt index 0e466ab8ce..f247a420b5 100644 --- a/Zend/tests/indexing_001.phpt +++ b/Zend/tests/indexing_001.phpt @@ -12,7 +12,7 @@ foreach ($testvalues as $testvalue) { } echo "\n*** Indexing - Testing reference assignment with key ***\n"; -$testvalues=array(null, 0, 1, true, false,'',0.1,array()); +$testvalues=array(null, 0, 1, true, false,0.1,array()); foreach ($testvalues as $testvalue) { $testvalue['foo']=&$array; @@ -20,7 +20,7 @@ foreach ($testvalues as $testvalue) { } echo "*** Indexing - Testing value assignment no key ***\n"; $array=array(1); -$testvalues=array(null, 0, 1, true, false,'',0.1,array()); +$testvalues=array(null, 0, 1, true, false,0.1,array()); foreach ($testvalues as $testvalue) { $testvalue[]=$array; @@ -28,7 +28,7 @@ foreach ($testvalues as $testvalue) { } echo "\n*** Indexing - Testing reference assignment no key ***\n"; -$testvalues=array(null, 0, 1, true, false,'',0.1,array()); +$testvalues=array(null, 0, 1, true, false,0.1,array()); foreach ($testvalues as $testvalue) { $testvalue[]=&$array; @@ -63,13 +63,11 @@ array(1) { int(1) } } -array(1) { - ["foo"]=> - array(1) { - [0]=> - int(1) - } -} + +Warning: Illegal string offset 'foo' in %s on line %d + +Notice: Array to string conversion in %s on line %d +string(1) "A" Warning: Illegal string offset 'foo' in %s on line %d @@ -110,13 +108,6 @@ array(1) { int(1) } } -array(1) { - ["foo"]=> - &array(1) { - [0]=> - int(1) - } -} Warning: Cannot use a scalar value as an array in %s on line %d float(0.1) @@ -151,13 +142,6 @@ array(1) { int(1) } } -array(1) { - [0]=> - array(1) { - [0]=> - int(1) - } -} Warning: Cannot use a scalar value as an array in %s on line %d float(0.1) @@ -193,13 +177,6 @@ array(1) { int(1) } } -array(1) { - [0]=> - &array(1) { - [0]=> - int(1) - } -} Warning: Cannot use a scalar value as an array in %s on line %d float(0.1) @@ -211,4 +188,4 @@ array(1) { } } -Done
\ No newline at end of file +Done diff --git a/Zend/tests/indirect_call_array_003.phpt b/Zend/tests/indirect_call_array_003.phpt index 498c580c48..f1dde491f6 100644 --- a/Zend/tests/indirect_call_array_003.phpt +++ b/Zend/tests/indirect_call_array_003.phpt @@ -17,8 +17,11 @@ class foo { } $arr = array('foo', 'abc'); -$arr(); - +try { + $arr(); +} catch (Throwable $e) { + echo "Exception: " . $e->getMessage() . "\n"; +} $foo = new foo; $arr = array($foo, 'abc'); $arr(); @@ -28,9 +31,7 @@ $arr(); --EXPECTF-- From foo::__callStatic: string(3) "abc" - -Notice: Undefined variable: this in %s on line %d -NULL +Exception: Using $this when not in object context From foo::__call: string(3) "abc" object(foo)#%d (0) { diff --git a/Zend/tests/inference_infinite_loop.phpt b/Zend/tests/inference_infinite_loop.phpt new file mode 100644 index 0000000000..1e94ea8040 --- /dev/null +++ b/Zend/tests/inference_infinite_loop.phpt @@ -0,0 +1,17 @@ +--TEST-- +Type inference should not result in infinite loop +--FILE-- +<?php + +function test() { + $b = false; + do { + $a = $a + PHP_INT_MAX + 2; + $a = 0; + } while ($b); +} +test(); + +?> +--EXPECTF-- +Notice: Undefined variable: a in %s on line %d diff --git a/Zend/tests/instanceof_001.phpt b/Zend/tests/instanceof_001.phpt index b88e174c16..95e43ba506 100644 --- a/Zend/tests/instanceof_001.phpt +++ b/Zend/tests/instanceof_001.phpt @@ -26,4 +26,4 @@ bool(true) bool(true) bool(false) -Catchable fatal error: Object of class stdClass could not be converted to string in %s on line %d +Recoverable fatal error: Object of class stdClass could not be converted to string in %s on line %d diff --git a/Zend/tests/int_conversion_exponents.phpt b/Zend/tests/int_conversion_exponents.phpt new file mode 100644 index 0000000000..d924cb7b81 --- /dev/null +++ b/Zend/tests/int_conversion_exponents.phpt @@ -0,0 +1,52 @@ +--TEST-- +Integer conversion from scientific notation +--FILE-- +<?php + +var_dump((int)"1.2345e9"); +var_dump((int)"-1.2345e9"); +var_dump(intval("1.2345e9")); +var_dump(intval("-1.2345e9")); +var_dump("1.2345e9" % PHP_INT_MAX); +var_dump("-1.2345e9" % PHP_INT_MIN); +var_dump("1.2345e9" | 0); +var_dump("-1.2345e9" | 0); + +echo PHP_EOL; + +var_dump((int)" 1.2345e9 abc"); +var_dump((int)" -1.2345e9 abc"); +var_dump(intval(" 1.2345e9 abc")); +var_dump(intval(" -1.2345e9 abc")); +var_dump(" 1.2345e9 abc" % PHP_INT_MAX); +var_dump(" -1.2345e9 abc" % PHP_INT_MIN); +var_dump(" 1.2345e9 abc" | 0); +var_dump(" -1.2345e9 abc" | 0); + +?> +--EXPECTF-- +int(1234500000) +int(-1234500000) +int(1234500000) +int(-1234500000) +int(1234500000) +int(-1234500000) +int(1234500000) +int(-1234500000) + +int(1234500000) +int(-1234500000) +int(1234500000) +int(-1234500000) + +Notice: A non well formed numeric value encountered in %s on line %d +int(1234500000) + +Notice: A non well formed numeric value encountered in %s on line %d +int(-1234500000) + +Notice: A non well formed numeric value encountered in %s on line %d +int(1234500000) + +Notice: A non well formed numeric value encountered in %s on line %d +int(-1234500000) diff --git a/Zend/tests/isset_str_offset.phpt b/Zend/tests/isset_str_offset.phpt index 7a9164a381..d693f80a52 100644 --- a/Zend/tests/isset_str_offset.phpt +++ b/Zend/tests/isset_str_offset.phpt @@ -8,6 +8,7 @@ print "- isset ---\n"; $str = "test0123"; var_dump(isset($str[-1])); +var_dump(isset($str[-10])); var_dump(isset($str[0])); var_dump(isset($str[1])); var_dump(isset($str[4])); // 0 @@ -17,6 +18,7 @@ var_dump(isset($str[10000])); // non-numeric offsets print "- string ---\n"; var_dump(isset($str['-1'])); +var_dump(isset($str['-10'])); var_dump(isset($str['0'])); var_dump(isset($str['1'])); var_dump(isset($str['4'])); // 0 @@ -31,6 +33,7 @@ print "- null ---\n"; var_dump(isset($str[null])); print "- double ---\n"; var_dump(isset($str[-1.1])); +var_dump(isset($str[-10.5])); var_dump(isset($str[-0.8])); var_dump(isset($str[-0.1])); var_dump(isset($str[0.2])); @@ -50,6 +53,7 @@ print "done\n"; ?> --EXPECTF-- - isset --- +bool(true) bool(false) bool(true) bool(true) @@ -58,6 +62,7 @@ bool(true) bool(false) bool(false) - string --- +bool(true) bool(false) bool(true) bool(true) @@ -72,6 +77,7 @@ bool(false) - null --- bool(true) - double --- +bool(true) bool(false) bool(true) bool(true) diff --git a/Zend/tests/jump16.phpt b/Zend/tests/jump16.phpt new file mode 100644 index 0000000000..cc820c4a6c --- /dev/null +++ b/Zend/tests/jump16.phpt @@ -0,0 +1,27 @@ +--TEST-- +jump 16: goto into try/catch +--FILE-- +<?php +goto a; +try { + echo "1"; +a: + echo "2"; + throw new Exception(); +} catch (Exception $e) { + echo "3"; +} +echo "4"; +goto b; +try { + echo "5"; + throw new Exception(); +} catch (Exception $e) { + echo "6"; +b: + echo "7"; +} +echo "8\n"; +?> +--EXPECT-- +23478 diff --git a/Zend/tests/jump17.phpt b/Zend/tests/jump17.phpt new file mode 100644 index 0000000000..92d3be511b --- /dev/null +++ b/Zend/tests/jump17.phpt @@ -0,0 +1,22 @@ +--TEST-- +jump 17: goto into try/catch with finally +--FILE-- +<?php +goto b; +try { + echo "1"; +a: + echo "2"; + throw new Exception(); +} catch (Exception $e) { + echo "3"; +b: + echo "4"; +} finally { + echo "5"; +c: + echo "6"; +} +echo "7\n"; +--EXPECT-- +4567 diff --git a/Zend/tests/list_001.phpt b/Zend/tests/list_001.phpt index a9fff55004..4e0053edee 100644 --- a/Zend/tests/list_001.phpt +++ b/Zend/tests/list_001.phpt @@ -5,6 +5,8 @@ list($a, list($b)) = array(new stdclass, array(new stdclass)); var_dump($a, $b); +[$a, [$b]] = array(new stdclass, array(new stdclass)); +var_dump($a, $b); ?> --EXPECT-- @@ -12,3 +14,7 @@ object(stdClass)#1 (0) { } object(stdClass)#2 (0) { } +object(stdClass)#3 (0) { +} +object(stdClass)#4 (0) { +} diff --git a/Zend/tests/list_008.phpt b/Zend/tests/list_008.phpt new file mode 100644 index 0000000000..de8160c77e --- /dev/null +++ b/Zend/tests/list_008.phpt @@ -0,0 +1,10 @@ +--TEST-- +Assignment to invalid list() value +--FILE-- +<?php + +[42] = [1]; + +?> +--EXPECTF-- +Fatal error: Assignments can only happen to writable values in %s on line %d diff --git a/Zend/tests/list_009.phpt b/Zend/tests/list_009.phpt new file mode 100644 index 0000000000..c28ca8000a --- /dev/null +++ b/Zend/tests/list_009.phpt @@ -0,0 +1,14 @@ +--TEST-- +list with by-reference assignment should fail +--FILE-- +<?php + +$a = [1]; +[&$foo] = $a; +$foo = 2; + +var_dump($a); + +?> +--EXPECTF-- +Fatal error: [] and list() assignments cannot be by reference in %s on line %d diff --git a/Zend/tests/list_010.phpt b/Zend/tests/list_010.phpt new file mode 100644 index 0000000000..a89ffda5cd --- /dev/null +++ b/Zend/tests/list_010.phpt @@ -0,0 +1,11 @@ +--TEST-- +Do not allow mixing [] and list() +--FILE-- +<?php + +list([$a]) = [[1]]; +var_dump($a); + +?> +--EXPECTF-- +Fatal error: Cannot mix [] and list() in %s on line %d diff --git a/Zend/tests/list_011.phpt b/Zend/tests/list_011.phpt new file mode 100644 index 0000000000..316498c411 --- /dev/null +++ b/Zend/tests/list_011.phpt @@ -0,0 +1,10 @@ +--TEST-- +Disallow list() usage as if it were an array +--FILE-- +<?php + +var_dump(list(1, 2, 3)); + +?> +--EXPECTF-- +Parse error: syntax error, unexpected ')', expecting '=' in %s on line %d diff --git a/Zend/tests/list_012.phpt b/Zend/tests/list_012.phpt new file mode 100644 index 0000000000..072d28c01d --- /dev/null +++ b/Zend/tests/list_012.phpt @@ -0,0 +1,10 @@ +--TEST-- +Disallow empty elements in normal arrays +--FILE-- +<?php + +var_dump([, 1, 2]); + +?> +--EXPECTF-- +Fatal error: Cannot use empty array elements in arrays in %s on line %d diff --git a/Zend/tests/list_013.phpt b/Zend/tests/list_013.phpt new file mode 100644 index 0000000000..2869f5f423 --- /dev/null +++ b/Zend/tests/list_013.phpt @@ -0,0 +1,10 @@ +--TEST-- +Disallow tail empty elements in normal arrays +--FILE-- +<?php + +var_dump([1, 2, ,]); + +?> +--EXPECTF-- +Fatal error: Cannot use empty array elements in arrays in %s on line %d diff --git a/Zend/tests/list_014.phpt b/Zend/tests/list_014.phpt new file mode 100644 index 0000000000..7b77825f39 --- /dev/null +++ b/Zend/tests/list_014.phpt @@ -0,0 +1,11 @@ +--TEST-- +Cannot destructure using array(), even if nested +--FILE-- +<?php + +[array($a)] = [array(42)]; +var_dump($a); + +?> +--EXPECTF-- +Fatal error: Cannot assign to array(), use [] instead in %s on line %d diff --git a/Zend/tests/list_empty_error_keyed.phpt b/Zend/tests/list_empty_error_keyed.phpt new file mode 100644 index 0000000000..f363d244f9 --- /dev/null +++ b/Zend/tests/list_empty_error_keyed.phpt @@ -0,0 +1,11 @@ +--TEST-- +Cannot use empty elements in keyed array destructuring +--FILE-- +<?php + +$array = ['a' => 1, 'b' => 2]; +['a' => $a, , 'b' => $b] = $array; + +?> +--EXPECTF-- +Fatal error: Cannot use empty array entries in keyed array assignment in %s on line %d diff --git a/Zend/tests/list_keyed.phpt b/Zend/tests/list_keyed.phpt new file mode 100644 index 0000000000..b549ed9bf5 --- /dev/null +++ b/Zend/tests/list_keyed.phpt @@ -0,0 +1,71 @@ +--TEST-- +list() with keys +--FILE-- +<?php + +$antonyms = [ + "good" => "bad", + "happy" => "sad", +]; + +list("good" => $good_antonym, "happy" => $happy_antonym) = $antonyms; +var_dump($good_antonym, $happy_antonym); + +echo PHP_EOL; + +$powersOfTwo = [ + 1 => 2, + 2 => 4, + 3 => 8 +]; + +list(1 => $two_1, 2 => $two_2, 3 => $two_3) = $powersOfTwo; +var_dump($two_1, $two_2, $two_3); + +echo PHP_EOL; + +$contrivedMixedKeyTypesExample = [ + 7 => "the best PHP version", + "elePHPant" => "the cutest mascot" +]; + +list(7 => $seven, "elePHPant" => $elePHPant) = $contrivedMixedKeyTypesExample; +var_dump($seven, $elePHPant); + +echo PHP_EOL; + +$allTogetherNow = [ + "antonyms" => $antonyms, + "powersOfTwo" => $powersOfTwo, + "contrivedMixedKeyTypesExample" => $contrivedMixedKeyTypesExample +]; + +list( + "antonyms" => list("good" => $good_antonym, "happy" => $happy_antonym), + "powersOfTwo" => list(1 => $two_1, 2 => $two_2, 3 => $two_3), + "contrivedMixedKeyTypesExample" => list(7 => $seven, "elePHPant" => $elePHPant) +) = $allTogetherNow; + +var_dump($good_antonym, $happy_antonym); +var_dump($two_1, $two_2, $two_3); +var_dump($seven, $elePHPant); + +?> +--EXPECT-- +string(3) "bad" +string(3) "sad" + +int(2) +int(4) +int(8) + +string(20) "the best PHP version" +string(17) "the cutest mascot" + +string(3) "bad" +string(3) "sad" +int(2) +int(4) +int(8) +string(20) "the best PHP version" +string(17) "the cutest mascot" diff --git a/Zend/tests/list_keyed_ArrayAccess.phpt b/Zend/tests/list_keyed_ArrayAccess.phpt new file mode 100644 index 0000000000..1bb2013036 --- /dev/null +++ b/Zend/tests/list_keyed_ArrayAccess.phpt @@ -0,0 +1,54 @@ +--TEST-- +list() with keys and ArrayAccess +--FILE-- +<?php + +$antonymObject = new ArrayObject; +$antonymObject["good"] = "bad"; +$antonymObject["happy"] = "sad"; + +list("good" => $good, "happy" => $happy) = $antonymObject; +var_dump($good, $happy); + +echo PHP_EOL; + +$stdClassCollection = new SplObjectStorage; +$foo = new StdClass; +$stdClassCollection[$foo] = "foo"; +$bar = new StdClass; +$stdClassCollection[$bar] = "bar"; + +list($foo => $fooStr, $bar => $barStr) = $stdClassCollection; +var_dump($fooStr, $barStr); + +echo PHP_EOL; + +class IndexPrinter implements ArrayAccess +{ + public function offsetGet($offset) { + echo "GET "; + var_dump($offset); + } + public function offsetSet($offset, $value) { + } + public function offsetExists($offset) { + } + public function offsetUnset($offset) { + } +} + +$op = new IndexPrinter; +list(123 => $x) = $op; +// PHP shouldn't convert this to an integer offset, because it's ArrayAccess +list("123" => $x) = $op; + +?> +--EXPECT-- +string(3) "bad" +string(3) "sad" + +string(3) "foo" +string(3) "bar" + +GET int(123) +GET string(3) "123" diff --git a/Zend/tests/list_keyed_conversions.phpt b/Zend/tests/list_keyed_conversions.phpt new file mode 100644 index 0000000000..bf0349b327 --- /dev/null +++ b/Zend/tests/list_keyed_conversions.phpt @@ -0,0 +1,34 @@ +--TEST-- +list() with non-integer-or-string keys +--FILE-- +<?php + +$results = [ + 0 => 0, + 1 => 1, + "" => "" +]; + +list(NULL => $NULL, 1.5 => $float, FALSE => $FALSE, TRUE => $TRUE) = $results; +var_dump($NULL, $float, $FALSE, $TRUE); + +echo PHP_EOL; + +list("0" => $zeroString, "1" => $oneString) = $results; +var_dump($zeroString, $oneString); + +list(STDIN => $resource) = []; + +?> +--EXPECTF-- +string(0) "" +int(1) +int(0) +int(1) + +int(0) +int(1) + +Notice: Resource ID#%d used as offset, casting to integer (%d) in %s on line %d + +Notice: Undefined offset: 1 in %s on line %d diff --git a/Zend/tests/list_keyed_evaluation_order.inc b/Zend/tests/list_keyed_evaluation_order.inc new file mode 100644 index 0000000000..490a6d84fe --- /dev/null +++ b/Zend/tests/list_keyed_evaluation_order.inc @@ -0,0 +1,60 @@ +<?php declare(strict_types=1); + +// Observer objects for the Zend/tests/list_keyed_evaluation_order.* tests + +class Stringable +{ + private $name; + public function __construct(string $name) { + $this->name = $name; + } + + public function __toString(): string { + echo "$this->name evaluated.", PHP_EOL; + return $this->name; + } +} + +class Indexable implements ArrayAccess +{ + private $array; + public function __construct(array $array) { + $this->array = $array; + } + + public function offsetExists($offset): bool { + echo "Existence of offset $offset checked for.", PHP_EOL; + return isset($this->array[$offset]); + } + + public function offsetUnset($offset): void { + unset($this->array[$offset]); + echo "Offset $offset removed.", PHP_EOL; + } + + public function offsetGet($offset) { + echo "Offset $offset retrieved.", PHP_EOL; + return $this->array[$offset]; + } + + public function offsetSet($offset, $value): void { + $this->array[$offset] = $value; + echo "Offset $offset set to $value.", PHP_EOL; + } +} + +class IndexableRetrievable +{ + private $label; + private $indexable; + + public function __construct(string $label, Indexable $indexable) { + $this->label = $label; + $this->indexable = $indexable; + } + + public function getIndexable(): Indexable { + echo "Indexable $this->label retrieved.", PHP_EOL; + return $this->indexable; + } +} diff --git a/Zend/tests/list_keyed_evaluation_order.phpt b/Zend/tests/list_keyed_evaluation_order.phpt new file mode 100644 index 0000000000..0f0652b6a9 --- /dev/null +++ b/Zend/tests/list_keyed_evaluation_order.phpt @@ -0,0 +1,35 @@ +--TEST-- +list() with keys, evaluation order +--FILE-- +<?php + +require_once "list_keyed_evaluation_order.inc"; + +$a = new Stringable("A"); +$c = new Stringable("C"); + +$e = new IndexableRetrievable("E", new Indexable(["A" => "value for offset A", "C" => "value for offset C"])); + +$store = new Indexable([]); + +// list($a => $b, $c => $d) = $e; +// Should be evaluated in the order: +// 1. Evaluate $e +// 2. Evaluate $a +// 3. Evaluate $e[$a] +// 4. Assign $b from $e[$a] +// 5. Evaluate $c +// 6. Evaluate $e[$c] +// 7. Assign $c from $e[$a] + +list((string)$a => $store["B"], (string)$c => $store["D"]) = $e->getIndexable(); + +?> +--EXPECT-- +Indexable E retrieved. +A evaluated. +Offset A retrieved. +Offset B set to value for offset A. +C evaluated. +Offset C retrieved. +Offset D set to value for offset C. diff --git a/Zend/tests/list_keyed_evaluation_order_2.phpt b/Zend/tests/list_keyed_evaluation_order_2.phpt new file mode 100644 index 0000000000..ddfba68c46 --- /dev/null +++ b/Zend/tests/list_keyed_evaluation_order_2.phpt @@ -0,0 +1,77 @@ +--TEST-- +list() with keys, evaluation order #2 +--FILE-- +<?php + +// All the following should print 'a' then 'b' + +list($a, $b) = ['a', 'b']; +var_dump($a); +var_dump($b); + +list(0 => $a, 1 => $b) = ['a', 'b']; +var_dump($a); +var_dump($b); + +list(1 => $b, 0 => $a) = ['a', 'b']; +var_dump($a); +var_dump($b); + +$arr = []; +list($arr[], $arr[]) = ['a', 'b']; +var_dump($arr[0]); +var_dump($arr[1]); + +$arr = []; +list(0 => $arr[], 1 => $arr[]) = ['a', 'b']; +var_dump($arr[0]); +var_dump($arr[1]); + +$arr = []; +list(1 => $arr[], 0 => $arr[]) = ['b', 'a']; +var_dump($arr[0]); +var_dump($arr[1]); + +$arr = []; +list(list(1 => $arr[], 0 => $arr[])) = [['b', 'a']]; +var_dump($arr[0]); +var_dump($arr[1]); + +$arr = []; +list('key1' => $arr[], 'key2' => $arr[]) = ['key2' => 'b', 'key1' => 'a']; +var_dump($arr[0]); +var_dump($arr[1]); + +// This should print 'foo' +$a = 0; +list($a => $a) = ['foo', 'bar']; +var_dump($a); + +// This should print 'bar' then 'foo' +$a = 0; +$b = 1; +list($b => $a, $a => $c) = ['bar' => 'foo', 1 => 'bar']; +var_dump($a); +var_dump($c); + +?> +--EXPECT-- +string(1) "a" +string(1) "b" +string(1) "a" +string(1) "b" +string(1) "a" +string(1) "b" +string(1) "a" +string(1) "b" +string(1) "a" +string(1) "b" +string(1) "a" +string(1) "b" +string(1) "a" +string(1) "b" +string(1) "a" +string(1) "b" +string(3) "foo" +string(3) "bar" +string(3) "foo" diff --git a/Zend/tests/list_keyed_evaluation_order_3.phpt b/Zend/tests/list_keyed_evaluation_order_3.phpt new file mode 100644 index 0000000000..7850834c3b --- /dev/null +++ b/Zend/tests/list_keyed_evaluation_order_3.phpt @@ -0,0 +1,24 @@ +--TEST-- +list() with keys, evaluation order #3 +--FILE-- +<?php + +$i = 0; +$a = [ + 0 => [ + 'b' => 'bar', + 'a' => 'foo', + ], + 1 => 'a', + 3 => 'b', +]; +list($a[$i++] => $a[$i++], $a[$i++] => $a[$i++]) = $a[$i++]; +var_dump($i); // should be 5 +var_dump($a[2]); // should be 'foo' +var_dump($a[4]); // should be 'bar' + +?> +--EXPECT-- +int(5) +string(3) "foo" +string(3) "bar" diff --git a/Zend/tests/list_keyed_evaluation_order_nested.phpt b/Zend/tests/list_keyed_evaluation_order_nested.phpt new file mode 100644 index 0000000000..8a7725d4ea --- /dev/null +++ b/Zend/tests/list_keyed_evaluation_order_nested.phpt @@ -0,0 +1,77 @@ +--TEST-- +list() with keys, evaluation order: nested +--FILE-- +<?php + +require_once "list_keyed_evaluation_order.inc"; + +$a = new Stringable("A"); +$c = new Stringable("C"); +$f = new Stringable("F"); +$g = new Stringable("G"); +$i = new Stringable("I"); + +$k = new IndexableRetrievable("K", new Indexable([ + "A" => "offset value for A", + "C" => new Indexable([ + 0 => "offset value for 0", + 1 => "offset value for 1" + ]), + "F" => new Indexable([ + "G" => "offset value for G", + "I" => "offset value for I" + ]) +])); + +$store = new Indexable([]); + +// list($a => $b, $c => list($d, $e), $f => list($g => $h, $i => $j)) = $k; +// Should be evaluated in the order: +// 1. Evaluate $k +// 2. Evaluate $a +// 3. Evaluate $k[$a] +// 4. Assign $b from $k[$a] +// 5. Evaluate $c +// 6. Evaluate $k[$c] +// 7. Evaluate $k[$c][0] +// 8. Assign $d from $k[$c][0] +// 9. Evaluate $k[$c][1] +// 10. Assign $e from $k[$c][1] +// 11. Evaluate $f +// 12. Evaluate $k[$f] +// 13. Evaluate $g +// 14. Evaluate $k[$f][$g] +// 15. Assign $h from $k[$f][$g] +// 16. Evaluate $i +// 17. Evaluate $k[$f][$i] +// 18. Assign $j from $k[$f][$i] + +list( + (string)$a => $store["B"], + (string)$c => list($store["D"], $store["E"]), + (string)$f => list( + (string)$g => $store["H"], + (string)$i => $store["J"] + ) +) = $k->getIndexable(); + +?> +--EXPECT-- +Indexable K retrieved. +A evaluated. +Offset A retrieved. +Offset B set to offset value for A. +C evaluated. +Offset C retrieved. +Offset 0 retrieved. +Offset D set to offset value for 0. +Offset 1 retrieved. +Offset E set to offset value for 1. +F evaluated. +Offset F retrieved. +G evaluated. +Offset G retrieved. +Offset H set to offset value for G. +I evaluated. +Offset I retrieved. +Offset J set to offset value for I. diff --git a/Zend/tests/list_keyed_non_literals.phpt b/Zend/tests/list_keyed_non_literals.phpt new file mode 100644 index 0000000000..80f22eda22 --- /dev/null +++ b/Zend/tests/list_keyed_non_literals.phpt @@ -0,0 +1,30 @@ +--TEST-- +list() with constant keys +--FILE-- +<?php + +$arr = [ + 1 => "one", + 2 => "two", + 3 => "three" +]; + +const COMPILE_TIME_RESOLVABLE = 1; + +define('PROBABLY_NOT_COMPILE_TIME_RESOLVABLE', file_get_contents("data:text/plain,2")); + +$probablyNotCompileTimeResolvable3 = cos(0) * 3; + +list( + COMPILE_TIME_RESOLVABLE => $one, + PROBABLY_NOT_COMPILE_TIME_RESOLVABLE => $two, + $probablyNotCompileTimeResolvable3 => $three +) = $arr; + +var_dump($one, $two, $three); + +?> +--EXPECTF-- +string(3) "one" +string(3) "two" +string(5) "three" diff --git a/Zend/tests/list_keyed_trailing_comma.phpt b/Zend/tests/list_keyed_trailing_comma.phpt new file mode 100644 index 0000000000..e0af0aed21 --- /dev/null +++ b/Zend/tests/list_keyed_trailing_comma.phpt @@ -0,0 +1,38 @@ +--TEST-- +list() with keys and a trailing comma +--FILE-- +<?php + +$antonyms = [ + "good" => "bad", + "happy" => "sad", +]; + +list( + "good" => $good, + "happy" => $happy +) = $antonyms; + +var_dump($good, $happy); + +echo PHP_EOL; + +$antonyms = [ + "good" => "bad", + "happy" => "sad", +]; + +list( + "good" => $good, + "happy" => $happy, +) = $antonyms; + +var_dump($good, $happy); + +?> +--EXPECT-- +string(3) "bad" +string(3) "sad" + +string(3) "bad" +string(3) "sad" diff --git a/Zend/tests/list_keyed_undefined.phpt b/Zend/tests/list_keyed_undefined.phpt new file mode 100644 index 0000000000..a18e3b4d20 --- /dev/null +++ b/Zend/tests/list_keyed_undefined.phpt @@ -0,0 +1,22 @@ +--TEST-- +list() with undefined keys +--FILE-- +<?php + +$contrivedMixedKeyTypesExample = [ + 7 => "the best PHP version", + "elePHPant" => "the cutest mascot" +]; + +list(5 => $five, "duke" => $duke) = $contrivedMixedKeyTypesExample; + +var_dump($five, $duke); + +?> +--EXPECTF-- + +Notice: Undefined offset: 5 in %s on line %d + +Notice: Undefined index: duke in %s on line %d +NULL +NULL diff --git a/Zend/tests/list_mixed_keyed_unkeyed.phpt b/Zend/tests/list_mixed_keyed_unkeyed.phpt new file mode 100644 index 0000000000..245d20f31f --- /dev/null +++ b/Zend/tests/list_mixed_keyed_unkeyed.phpt @@ -0,0 +1,16 @@ +--TEST-- +list() with both keyed and unkeyed elements +--FILE-- +<?php + +$contrivedKeyedAndUnkeyedArrayExample = [ + 0, + 1 => 1, + "foo" => "bar" +]; + +list($zero, 1 => $one, "foo" => $foo) = $contrivedKeyedAndUnkeyedArrayExample; + +?> +--EXPECTF-- +Fatal error: Cannot mix keyed and unkeyed array entries in assignments in %s on line %d diff --git a/Zend/tests/list_mixed_nested_keyed_unkeyed.phpt b/Zend/tests/list_mixed_nested_keyed_unkeyed.phpt new file mode 100644 index 0000000000..3087775b76 --- /dev/null +++ b/Zend/tests/list_mixed_nested_keyed_unkeyed.phpt @@ -0,0 +1,34 @@ +--TEST-- +list() with nested unkeyed and keyed list() +--FILE-- +<?php + +$points = [ + ["x" => 1, "y" => 2], + ["x" => 2, "y" => 1] +]; + +list(list("x" => $x1, "y" => $y1), list("x" => $x2, "y" => $y2)) = $points; +var_dump($x1, $y1, $x2, $y2); + +echo PHP_EOL; + +$invertedPoints = [ + "x" => [1, 2], + "y" => [2, 1] +]; + +list("x" => list($x1, $x2), "y" => list($y1, $y2)) = $invertedPoints; +var_dump($x1, $y1, $x2, $y2); + +?> +--EXPECT-- +int(1) +int(2) +int(2) +int(1) + +int(1) +int(2) +int(2) +int(1) diff --git a/Zend/tests/method_argument_binding.phpt b/Zend/tests/method_argument_binding.phpt new file mode 100644 index 0000000000..dea12621a3 --- /dev/null +++ b/Zend/tests/method_argument_binding.phpt @@ -0,0 +1,46 @@ +--TEST-- +Edge cases in compile-time method argument binding +--FILE-- +<?php + +class A { + private function method($x) {} +} + +class B extends A { + public function test() { + $x = 1; + $this->method($x); + var_dump($x); + } +} + +class C extends B { + public function method(&$x) { + ++$x; + } +} + +(new C)->test(); + +class D { + private final function method(&$x) { + ++$x; + } +} + +class E extends D { + public function __call($name, $args) { } + + public function test() { + $this->method($x); + } +} + +(new E)->test(); + +?> +--EXPECTF-- +int(2) + +Notice: Undefined variable: x in %s on line %d diff --git a/Zend/tests/neg_num_string.phpt b/Zend/tests/neg_num_string.phpt new file mode 100644 index 0000000000..018568adea --- /dev/null +++ b/Zend/tests/neg_num_string.phpt @@ -0,0 +1,47 @@ +--TEST-- +Test edge-cases for negative num strings in interpolated string offsets +--FILE-- +<?php + +$a = [ + "0" => 1, + "-0" => 2, + "1" => 3, + "-1" => 4, + "0x0" => 5, + "-0x0" => 6, + "00" => 7, + "-00" => 8, + "9223372036854775808" => 9, + "-9223372036854775808" => 10, + "2147483648" => 11, + "-2147483648" => 12, +]; + +var_dump("$a[0]"); +var_dump("$a[-0]"); +var_dump("$a[1]"); +var_dump("$a[-1]"); +var_dump("$a[0x0]"); +var_dump("$a[-0x0]"); +var_dump("$a[00]"); +var_dump("$a[-00]"); +var_dump("$a[9223372036854775808]"); +var_dump("$a[-9223372036854775808]"); +var_dump("$a[2147483648]"); +var_dump("$a[-2147483648]"); + +?> +--EXPECT-- +string(1) "1" +string(1) "2" +string(1) "3" +string(1) "4" +string(1) "5" +string(1) "6" +string(1) "7" +string(1) "8" +string(1) "9" +string(2) "10" +string(2) "11" +string(2) "12" diff --git a/Zend/tests/new_args_without_ctor.phpt b/Zend/tests/new_args_without_ctor.phpt new file mode 100644 index 0000000000..91456890d2 --- /dev/null +++ b/Zend/tests/new_args_without_ctor.phpt @@ -0,0 +1,10 @@ +--TEST-- +Argument of new on class without constructor are evaluated +--FILE-- +<?php + +new stdClass(print 'a', print 'b'); + +?> +--EXPECT-- +ab diff --git a/Zend/tests/ns_071.phpt b/Zend/tests/ns_071.phpt index 2f2fcfad1a..d7f1592b38 100644 --- a/Zend/tests/ns_071.phpt +++ b/Zend/tests/ns_071.phpt @@ -18,7 +18,7 @@ new bar(new \stdclass); --EXPECTF-- NULL -Fatal error: Uncaught TypeError: Argument 1 passed to foo\bar::__construct() must be of the type array, object given, called in %s on line %d and defined in %s:%d +Fatal error: Uncaught TypeError: Argument 1 passed to foo\bar::__construct() must be of the type array or null, object given, called in %s on line %d and defined in %s:%d Stack trace: #0 %s(%d): foo\bar->__construct(Object(stdClass)) #1 {main} diff --git a/Zend/tests/ns_072.phpt b/Zend/tests/ns_072.phpt index 6375682890..34a9bbf6ad 100644 --- a/Zend/tests/ns_072.phpt +++ b/Zend/tests/ns_072.phpt @@ -30,7 +30,7 @@ object(foo\test)#%d (0) { } NULL -Fatal error: Uncaught TypeError: Argument 1 passed to foo\bar::__construct() must implement interface foo\foo, instance of stdClass given, called in %s on line %d and defined in %s:%d +Fatal error: Uncaught TypeError: Argument 1 passed to foo\bar::__construct() must implement interface foo\foo or be null, instance of stdClass given, called in %s on line %d and defined in %s:%d Stack trace: #0 %s(%d): foo\bar->__construct(Object(stdClass)) #1 {main} diff --git a/Zend/tests/nullable_types/array.phpt b/Zend/tests/nullable_types/array.phpt new file mode 100644 index 0000000000..7b0a2ed4d5 --- /dev/null +++ b/Zend/tests/nullable_types/array.phpt @@ -0,0 +1,17 @@ +--TEST-- +Explicitly nullable array type +--FILE-- +<?php + +function _array_(?array $v): ?array { + return $v; +} + +var_dump(_array_(null)); +var_dump(_array_([])); + +--EXPECT-- +NULL +array(0) { +} + diff --git a/Zend/tests/nullable_types/contravariant_nullable_param_succeeds.phpt b/Zend/tests/nullable_types/contravariant_nullable_param_succeeds.phpt new file mode 100644 index 0000000000..f4d1e315fc --- /dev/null +++ b/Zend/tests/nullable_types/contravariant_nullable_param_succeeds.phpt @@ -0,0 +1,19 @@ +--TEST-- +Subtype can add nullability to a parameter (contravariance) + +--FILE-- +<?php + +interface A { + function method(int $p); +} + +class B implements A { + function method(?int $p) { } +} + +$b = new B(); +$b->method(null); + +--EXPECT-- + diff --git a/Zend/tests/nullable_types/contravariant_nullable_return_fails.phpt b/Zend/tests/nullable_types/contravariant_nullable_return_fails.phpt new file mode 100644 index 0000000000..c9be479ead --- /dev/null +++ b/Zend/tests/nullable_types/contravariant_nullable_return_fails.phpt @@ -0,0 +1,17 @@ +--TEST-- +Return type cannot add nullability (contravariance) + +--FILE-- +<?php + +interface A { + function method(): int; +} + +interface B extends A { + function method(): ?int; +} + +--EXPECTF-- +Fatal error: Declaration of B::method(): ?int must be compatible with A::method(): int in %s on line %d + diff --git a/Zend/tests/nullable_types/covariant_nullable_param_fails.phpt b/Zend/tests/nullable_types/covariant_nullable_param_fails.phpt new file mode 100644 index 0000000000..65b2858e6b --- /dev/null +++ b/Zend/tests/nullable_types/covariant_nullable_param_fails.phpt @@ -0,0 +1,17 @@ +--TEST-- +Subtype cannot remove nullable parameter (covariance) + +--FILE-- +<?php + +interface A { + function method(?int $p); +} + +class B implements A { + function method(int $p) { } +} + +--EXPECTF-- +Fatal error: Declaration of B::method(int $p) must be compatible with A::method(?int $p) in %s on line %d + diff --git a/Zend/tests/nullable_types/covariant_nullable_return_succeds.phpt b/Zend/tests/nullable_types/covariant_nullable_return_succeds.phpt new file mode 100644 index 0000000000..5776f9b99d --- /dev/null +++ b/Zend/tests/nullable_types/covariant_nullable_return_succeds.phpt @@ -0,0 +1,16 @@ +--TEST-- +Nullable covariant return types + +--FILE-- +<?php + +interface A { + function method(): ?int; +} + +interface B extends A { + function method(): int; +} + +--EXPECT-- + diff --git a/Zend/tests/nullable_types/float.phpt b/Zend/tests/nullable_types/float.phpt new file mode 100644 index 0000000000..8e44524cf0 --- /dev/null +++ b/Zend/tests/nullable_types/float.phpt @@ -0,0 +1,16 @@ +--TEST-- +Explicitly nullable float type +--FILE-- +<?php + +function _float_(?float $v): ?float { + return $v; +} + +var_dump(_float_(null)); +var_dump(_float_(1.3)); + +--EXPECT-- +NULL +float(1.3) + diff --git a/Zend/tests/nullable_types/int.phpt b/Zend/tests/nullable_types/int.phpt new file mode 100644 index 0000000000..ec75132edb --- /dev/null +++ b/Zend/tests/nullable_types/int.phpt @@ -0,0 +1,16 @@ +--TEST-- +Explicitly nullable int type +--FILE-- +<?php + +function _int_(?int $v): ?int { + return $v; +} + +var_dump(_int_(null)); +var_dump(_int_(1)); + +--EXPECT-- +NULL +int(1) + diff --git a/Zend/tests/nullable_types/invariant_param_and_return_succeeds.phpt b/Zend/tests/nullable_types/invariant_param_and_return_succeeds.phpt new file mode 100644 index 0000000000..0542e52c0f --- /dev/null +++ b/Zend/tests/nullable_types/invariant_param_and_return_succeeds.phpt @@ -0,0 +1,24 @@ +--TEST-- +Invariant parameter and return types work with nullable types + +--FILE-- +<?php + +interface A { + function method(?int $i): ?int; +} + +class B implements A { + function method(?int $i): ?int { + return $i; + } +} + +$b = new B(); +var_dump($b->method(null)); +var_dump($b->method(1)); + +--EXPECT-- +NULL +int(1) + diff --git a/Zend/tests/nullable_types/nullable_type_parameters_do_not_have_default_value.phpt b/Zend/tests/nullable_types/nullable_type_parameters_do_not_have_default_value.phpt new file mode 100644 index 0000000000..3050feed53 --- /dev/null +++ b/Zend/tests/nullable_types/nullable_type_parameters_do_not_have_default_value.phpt @@ -0,0 +1,17 @@ +--TEST-- +Explicit nullable types do not imply a default value + +--FILE-- +<?php + +function f(?callable $p) {} + +f(); + +--EXPECTF-- +Fatal error: Uncaught ArgumentCountError: Too few arguments to function f(), 0 passed in %snullable_type_parameters_do_not_have_default_value.php on line %d and exactly 1 expected in %s:%d +Stack trace: +#%d %s +#%d %s + thrown in %s on line %d + diff --git a/Zend/tests/nullable_types/string.phpt b/Zend/tests/nullable_types/string.phpt new file mode 100644 index 0000000000..ffc6591b6b --- /dev/null +++ b/Zend/tests/nullable_types/string.phpt @@ -0,0 +1,16 @@ +--TEST-- +Explicitly nullable string type +--FILE-- +<?php + +function _string_(?string $v): ?string { + return $v; +} + +var_dump(_string_(null)); +var_dump(_string_("php")); + +--EXPECT-- +NULL +string(3) "php" + diff --git a/Zend/tests/numeric_string_errors.phpt b/Zend/tests/numeric_string_errors.phpt new file mode 100644 index 0000000000..e98c58dda7 --- /dev/null +++ b/Zend/tests/numeric_string_errors.phpt @@ -0,0 +1,195 @@ +--TEST-- +Invalid numeric string E_WARNINGs and E_NOTICEs +--FILE-- +<?php + +var_dump("2 Lorem" + "3 ipsum"); +var_dump("dolor" + "sit"); +echo "---", PHP_EOL; +var_dump("5 amet," - "7 consectetur"); +var_dump("adipiscing" - "elit,"); +echo "---", PHP_EOL; +var_dump("11 sed" * "13 do"); +var_dump("eiusmod" * "tempor"); +echo "---", PHP_EOL; +var_dump("17 incididunt" / "19 ut"); +var_dump("labore" / "et"); +echo "---", PHP_EOL; +var_dump("23 dolore" ** "29 magna"); +var_dump("aliqua." ** "Ut"); +echo "---", PHP_EOL; +var_dump("31 enim" % "37 ad"); +try { + var_dump("minim" % "veniam,"); +} catch (DivisionByZeroError $e) { +} +echo "---", PHP_EOL; +var_dump("41 minim" << "43 veniam,"); +var_dump("quis" << "nostrud"); +echo "---", PHP_EOL; +var_dump("47 exercitation" >> "53 ullamco"); +var_dump("laboris" >> "nisi"); +echo "---", PHP_EOL; +var_dump("59 ut" | 61); +var_dump(67 | "71 aliquip"); +var_dump("ex" | 73); +var_dump(79 | "ea"); +echo "---", PHP_EOL; +var_dump("83 commodo" & 89); +var_dump(97 & "101 consequat."); +var_dump("Duis" & 103); +var_dump(107 & "aute"); +echo "---", PHP_EOL; +var_dump("109 irure" ^ 113); +var_dump(127 ^ "131 dolor"); +var_dump("in" ^ 137); +var_dump(139 ^ "reprehenderit"); +echo "---", PHP_EOL; +var_dump(+"149 in"); +var_dump(+"voluptate"); +echo "---", PHP_EOL; +var_dump(-"151 velit"); +var_dump(-"esse"); +?> +--EXPECTF-- + +Notice: A non well formed numeric value encountered in %s on line %d + +Notice: A non well formed numeric value encountered in %s on line %d +int(5) + +Warning: A non-numeric value encountered in %s on line %d + +Warning: A non-numeric value encountered in %s on line %d +int(0) +--- + +Notice: A non well formed numeric value encountered in %s on line %d + +Notice: A non well formed numeric value encountered in %s on line %d +int(-2) + +Warning: A non-numeric value encountered in %s on line %d + +Warning: A non-numeric value encountered in %s on line %d +int(0) +--- + +Notice: A non well formed numeric value encountered in %s on line %d + +Notice: A non well formed numeric value encountered in %s on line %d +int(143) + +Warning: A non-numeric value encountered in %s on line %d + +Warning: A non-numeric value encountered in %s on line %d +int(0) +--- + +Notice: A non well formed numeric value encountered in %s on line %d + +Notice: A non well formed numeric value encountered in %s on line %d +float(0.89473684210526) + +Warning: A non-numeric value encountered in %s on line %d + +Warning: A non-numeric value encountered in %s on line %d + +Warning: Division by zero in %s on line %d +float(NAN) +--- + +Notice: A non well formed numeric value encountered in %s on line %d + +Notice: A non well formed numeric value encountered in %s on line %d +float(3.0910586430935E+39) + +Warning: A non-numeric value encountered in %s on line %d + +Warning: A non-numeric value encountered in %s on line %d +int(1) +--- + +Notice: A non well formed numeric value encountered in %s on line %d + +Notice: A non well formed numeric value encountered in %s on line %d +int(31) + +Warning: A non-numeric value encountered in %s on line %d + +Warning: A non-numeric value encountered in %s on line %d +--- + +Notice: A non well formed numeric value encountered in %s on line %d + +Notice: A non well formed numeric value encountered in %s on line %d +int(%d) + +Warning: A non-numeric value encountered in %s on line %d + +Warning: A non-numeric value encountered in %s on line %d +int(0) +--- + +Notice: A non well formed numeric value encountered in %s on line %d + +Notice: A non well formed numeric value encountered in %s on line %d +int(0) + +Warning: A non-numeric value encountered in %s on line %d + +Warning: A non-numeric value encountered in %s on line %d +int(0) +--- + +Notice: A non well formed numeric value encountered in %s on line %d +int(63) + +Notice: A non well formed numeric value encountered in %s on line %d +int(71) + +Warning: A non-numeric value encountered in %s on line %d +int(73) + +Warning: A non-numeric value encountered in %s on line %d +int(79) +--- + +Notice: A non well formed numeric value encountered in %s on line %d +int(81) + +Notice: A non well formed numeric value encountered in %s on line %d +int(97) + +Warning: A non-numeric value encountered in %s on line %d +int(0) + +Warning: A non-numeric value encountered in %s on line %d +int(0) +--- + +Notice: A non well formed numeric value encountered in %s on line %d +int(28) + +Notice: A non well formed numeric value encountered in %s on line %d +int(252) + +Warning: A non-numeric value encountered in %s on line %d +int(137) + +Warning: A non-numeric value encountered in %s on line %d +int(139) +--- + +Notice: A non well formed numeric value encountered in %s on line %d +int(149) + +Warning: A non-numeric value encountered in %s on line %d +int(0) +--- + +Notice: A non well formed numeric value encountered in %s on line %d +int(-151) + +Warning: A non-numeric value encountered in %s on line %d +int(0) diff --git a/Zend/tests/numeric_string_errors_assign.phpt b/Zend/tests/numeric_string_errors_assign.phpt new file mode 100644 index 0000000000..8d882aadcc --- /dev/null +++ b/Zend/tests/numeric_string_errors_assign.phpt @@ -0,0 +1,236 @@ +--TEST-- +Invalid numeric string E_WARNINGs and E_NOTICEs, combined assignment operations +--FILE-- +<?php + +// prevents CT eval +function foxcache($val) { + return [$val][0]; +} + +$a = foxcache("2 Lorem"); +$a += "3 ipsum"; +var_dump($a); +$a = foxcache("dolor"); +$a += "sit"; +var_dump($a); +echo "---", PHP_EOL; +$a = foxcache("5 amet,"); +$a -= "7 consectetur"; +var_dump($a); +$a = foxcache("adipiscing"); +$a -= "elit,"; +var_dump($a); +echo "---", PHP_EOL; +$a = foxcache("11 sed"); +$a *= "13 do"; +var_dump($a); +$a = foxcache("eiusmod"); +$a *= "tempor"; +var_dump($a); +echo "---", PHP_EOL; +$a = foxcache("17 incididunt"); +$a /= "19 ut"; +var_dump($a); +$a = foxcache("labore"); +$a /= "et"; +var_dump($a); +echo "---", PHP_EOL; +$a = foxcache("23 dolore"); +$a **= "29 magna"; +var_dump($a); +$a = foxcache("aliqua."); +$a **= "Ut"; +var_dump($a); +echo "---", PHP_EOL; +$a = foxcache("31 enim"); +$a %= "37 ad"; +var_dump($a); +try { + $a = foxcache("minim"); + $a %= "veniam,"; + var_dump($a); +} catch (DivisionByZeroError $e) { +} +echo "---", PHP_EOL; +$a = foxcache("41 minim"); +$a <<= "43 veniam,"; +var_dump($a); +$a = foxcache("quis"); +$a <<= "nostrud"; +var_dump($a); +echo "---", PHP_EOL; +$a = foxcache("47 exercitation"); +$a >>= "53 ullamco"; +var_dump($a); +$a = foxcache("laboris"); +$a >>= "nisi"; +var_dump($a); +echo "---", PHP_EOL; +$a = foxcache("59 ut"); +$a |= 61; +var_dump($a); +$a = foxcache(67); +$a |= "71 aliquip"; +var_dump($a); +$a = foxcache("ex"); +$a |= 73; +var_dump($a); +$a = foxcache(79); +$a |= "ea"; +var_dump($a); +echo "---", PHP_EOL; +$a = foxcache("83 commodo"); +$a &= 89; +var_dump($a); +$a = foxcache(97); +$a &= "101 consequat."; +var_dump($a); +$a = foxcache("Duis"); +$a &= 103; +var_dump($a); +$a = foxcache(107); +$a &= "aute"; +var_dump($a); +echo "---", PHP_EOL; +$a = foxcache("109 irure"); +$a ^= 113; +var_dump($a); +$a = foxcache(127); +$a ^= "131 dolor"; +var_dump($a); +$a = foxcache("in"); +$a ^= 137; +var_dump($a); +$a = foxcache(139); +$a ^= "reprehenderit"; +var_dump($a); +?> +--EXPECTF-- + +Notice: A non well formed numeric value encountered in %s on line %d + +Notice: A non well formed numeric value encountered in %s on line %d +int(5) + +Warning: A non-numeric value encountered in %s on line %d + +Warning: A non-numeric value encountered in %s on line %d +int(0) +--- + +Notice: A non well formed numeric value encountered in %s on line %d + +Notice: A non well formed numeric value encountered in %s on line %d +int(-2) + +Warning: A non-numeric value encountered in %s on line %d + +Warning: A non-numeric value encountered in %s on line %d +int(0) +--- + +Notice: A non well formed numeric value encountered in %s on line %d + +Notice: A non well formed numeric value encountered in %s on line %d +int(143) + +Warning: A non-numeric value encountered in %s on line %d + +Warning: A non-numeric value encountered in %s on line %d +int(0) +--- + +Notice: A non well formed numeric value encountered in %s on line %d + +Notice: A non well formed numeric value encountered in %s on line %d +float(0.89473684210526) + +Warning: A non-numeric value encountered in %s on line %d + +Warning: A non-numeric value encountered in %s on line %d + +Warning: Division by zero in %s on line %d +float(NAN) +--- + +Notice: A non well formed numeric value encountered in %s on line %d + +Notice: A non well formed numeric value encountered in %s on line %d +float(3.0910586430935E+39) + +Warning: A non-numeric value encountered in %s on line %d + +Warning: A non-numeric value encountered in %s on line %d +int(1) +--- + +Notice: A non well formed numeric value encountered in %s on line %d + +Notice: A non well formed numeric value encountered in %s on line %d +int(31) + +Warning: A non-numeric value encountered in %s on line %d + +Warning: A non-numeric value encountered in %s on line %d +--- + +Notice: A non well formed numeric value encountered in %s on line %d + +Notice: A non well formed numeric value encountered in %s on line %d +int(%d) + +Warning: A non-numeric value encountered in %s on line %d + +Warning: A non-numeric value encountered in %s on line %d +int(0) +--- + +Notice: A non well formed numeric value encountered in %s on line %d + +Notice: A non well formed numeric value encountered in %s on line %d +int(0) + +Warning: A non-numeric value encountered in %s on line %d + +Warning: A non-numeric value encountered in %s on line %d +int(0) +--- + +Notice: A non well formed numeric value encountered in %s on line %d +int(63) + +Notice: A non well formed numeric value encountered in %s on line %d +int(71) + +Warning: A non-numeric value encountered in %s on line %d +int(73) + +Warning: A non-numeric value encountered in %s on line %d +int(79) +--- + +Notice: A non well formed numeric value encountered in %s on line %d +int(81) + +Notice: A non well formed numeric value encountered in %s on line %d +int(97) + +Warning: A non-numeric value encountered in %s on line %d +int(0) + +Warning: A non-numeric value encountered in %s on line %d +int(0) +--- + +Notice: A non well formed numeric value encountered in %s on line %d +int(28) + +Notice: A non well formed numeric value encountered in %s on line %d +int(252) + +Warning: A non-numeric value encountered in %s on line %d +int(137) + +Warning: A non-numeric value encountered in %s on line %d +int(139) diff --git a/Zend/tests/objects_022.phpt b/Zend/tests/objects_022.phpt index 01f961bae1..5f537feaf4 100644 --- a/Zend/tests/objects_022.phpt +++ b/Zend/tests/objects_022.phpt @@ -25,7 +25,7 @@ $foo = new foo; $foo->testFoo(new foo); $foo->testBar(new bar); $foo->testBaz(new baz); -$foo->testFoo(new stdClass); // Catchable fatal error +$foo->testFoo(new stdClass); // Recoverable fatal error ?> --EXPECTF-- diff --git a/Zend/tests/oct_overflow_char.phpt b/Zend/tests/oct_overflow_char.phpt new file mode 100644 index 0000000000..32060d8593 --- /dev/null +++ b/Zend/tests/oct_overflow_char.phpt @@ -0,0 +1,10 @@ +--TEST-- +Octal overflow in string interpolation +--FILE-- +<?php + +// "abc", ordinarily 'b' would be \142, but we'll deliberately overflow the value by \400 +echo "\141\542\143\n"; +--EXPECTF-- +Warning: Octal escape sequence overflow \542 is greater than \377 in %s%eoct_overflow_char.php on line 4 +abc diff --git a/Zend/tests/overloaded_func_001.phpt b/Zend/tests/overloaded_func_001.phpt new file mode 100644 index 0000000000..2702772a46 --- /dev/null +++ b/Zend/tests/overloaded_func_001.phpt @@ -0,0 +1,15 @@ +--TEST-- +Overloaded function 001 +--SKIPIF-- +<?php +if (!PHP_DEBUG) die("skip only run in debug version"); +?> +--FILE-- +<?php +var_dump(_ZendTestClass::test()); +?> +--EXPECTF-- +Fatal error: Uncaught Error: Cannot call overloaded function for non-object in %soverloaded_func_001.php:%d +Stack trace: +#0 {main} + thrown in %soverloaded_func_001.php on line %d diff --git a/Zend/tests/overloaded_func_002.phpt b/Zend/tests/overloaded_func_002.phpt new file mode 100644 index 0000000000..6c16965919 --- /dev/null +++ b/Zend/tests/overloaded_func_002.phpt @@ -0,0 +1,13 @@ +--TEST-- +Overloaded function 002 +--SKIPIF-- +<?php +if (!PHP_DEBUG) die("skip only run in debug version"); +?> +--FILE-- +<?php +$a = new _ZendTestClass(); +var_dump($a->{trim(" test")}()); +?> +--EXPECT-- +string(4) "test" diff --git a/Zend/tests/parse_str_with_unpack.phpt b/Zend/tests/parse_str_with_unpack.phpt new file mode 100644 index 0000000000..50b296d710 --- /dev/null +++ b/Zend/tests/parse_str_with_unpack.phpt @@ -0,0 +1,15 @@ +--TEST-- +Calling parse_str through argument unpacking +--FILE-- +<?php + +function test() { + $i = 0; + parse_str(...["i=41"]); + var_dump($i + 1); +} +test(); + +?> +--EXPECT-- +int(42) diff --git a/Zend/tests/php_errormsg_misoptimization.phpt b/Zend/tests/php_errormsg_misoptimization.phpt new file mode 100644 index 0000000000..c121c1021a --- /dev/null +++ b/Zend/tests/php_errormsg_misoptimization.phpt @@ -0,0 +1,20 @@ +--TEST-- +The variable $php_errormsg shouldn't be optimized as it may be unpredictably modified +--INI-- +track_errors=1 +--FILE-- +<?php + +function test() { + $php_errormsg = 1; + echo $undef; + var_dump($php_errormsg + 1); +} +test(); + +?> +--EXPECTF-- +Notice: Undefined variable: undef in %s on line %d + +Warning: A non-numeric value encountered in %s on line %d +int(1) diff --git a/Zend/tests/return_types/029.phpt b/Zend/tests/return_types/029.phpt index 011182df37..adc07cde7f 100644 --- a/Zend/tests/return_types/029.phpt +++ b/Zend/tests/return_types/029.phpt @@ -9,14 +9,19 @@ function foo() : array { try { throw new Exception("xxxx"); } finally { - return ; + return null; } } foo(); ?> --EXPECTF-- -Fatal error: Uncaught TypeError: Return value of foo() must be of the type array, none returned in %s29.php:%d +Fatal error: Uncaught Exception: xxxx in %s:%d +Stack trace: +#0 %s(%d): foo() +#1 {main} + +Next TypeError: Return value of foo() must be of the type array, null returned in %s29.php:%d Stack trace: #0 %s(%d): foo() #1 {main} diff --git a/Zend/tests/return_types/030.phpt b/Zend/tests/return_types/030.phpt new file mode 100644 index 0000000000..288137f05c --- /dev/null +++ b/Zend/tests/return_types/030.phpt @@ -0,0 +1,23 @@ +--TEST-- +Nullable return value +--FILE-- +<?php +function foo($x) : ?array { + return $x; +} + +foo([]); +echo "ok\n"; +foo(null); +echo "ok\n"; +foo(0); +?> +--EXPECTF-- +ok +ok + +Fatal error: Uncaught TypeError: Return value of foo() must be of the type array or null, integer returned in %s030.php:3 +Stack trace: +#0 %s030.php(10): foo(0) +#1 {main} + thrown in %s030.php on line 3 diff --git a/Zend/tests/return_types/031.phpt b/Zend/tests/return_types/031.phpt new file mode 100644 index 0000000000..91ee2f8ce4 --- /dev/null +++ b/Zend/tests/return_types/031.phpt @@ -0,0 +1,14 @@ +--TEST-- +Nullable return type inheritance rules (non-nullable and nullable) +--FILE-- +<?php +class A { + function foo(): int {} +} +class B extends A { + function foo(): ?int {} +} +?> +DONE +--EXPECTF-- +Fatal error: Declaration of B::foo(): ?int must be compatible with A::foo(): int in %s031.php on line 7
\ No newline at end of file diff --git a/Zend/tests/return_types/032.phpt b/Zend/tests/return_types/032.phpt new file mode 100644 index 0000000000..00790b5d60 --- /dev/null +++ b/Zend/tests/return_types/032.phpt @@ -0,0 +1,14 @@ +--TEST-- +Nullable return type inheritance rules (nullable and non-nullable) +--FILE-- +<?php +class A { + function foo(): ?int {} +} +class B extends A { + function foo(): int {} +} +?> +DONE +--EXPECT-- +DONE diff --git a/Zend/tests/return_types/bug71092.phpt b/Zend/tests/return_types/bug71092.phpt index a1ebc79085..1d4fe983b3 100644 --- a/Zend/tests/return_types/bug71092.phpt +++ b/Zend/tests/return_types/bug71092.phpt @@ -9,14 +9,14 @@ function boom(): array { $data = [['id']]; switch ($data[0]) { case ['id']: - return; + return null; } } boom(); ?> --EXPECTF-- -Fatal error: Uncaught TypeError: Return value of boom() must be of the type array, none returned in %sbug71092.php:%d +Fatal error: Uncaught TypeError: Return value of boom() must be of the type array, null returned in %sbug71092.php:%d Stack trace: #0 %s(%d): boom() #1 {main} diff --git a/Zend/tests/return_types/generators002.phpt b/Zend/tests/return_types/generators002.phpt index f7dbfda69b..519c97a962 100644 --- a/Zend/tests/return_types/generators002.phpt +++ b/Zend/tests/return_types/generators002.phpt @@ -8,4 +8,4 @@ function test1() : StdClass { } --EXPECTF-- -Fatal error: Generators may only declare a return type of Generator, Iterator or Traversable, StdClass is not permitted in %s on line %d +Fatal error: Generators may only declare a return type of Generator, Iterator, Traversable, or iterable, StdClass is not permitted in %s on line %d diff --git a/Zend/tests/return_types/void_allowed.phpt b/Zend/tests/return_types/void_allowed.phpt new file mode 100644 index 0000000000..8f07c7392e --- /dev/null +++ b/Zend/tests/return_types/void_allowed.phpt @@ -0,0 +1,20 @@ +--TEST-- +void return type: acceptable cases +--FILE-- +<?php + +function foo(): void { + // okay +} + +foo(); + +function bar(): void { + return; // okay +} + +bar(); + +echo "OK!", PHP_EOL; +--EXPECT-- +OK! diff --git a/Zend/tests/return_types/void_disallowed1.phpt b/Zend/tests/return_types/void_disallowed1.phpt new file mode 100644 index 0000000000..365e2060bf --- /dev/null +++ b/Zend/tests/return_types/void_disallowed1.phpt @@ -0,0 +1,12 @@ +--TEST-- +void return type: unacceptable cases: explicit NULL return +--FILE-- +<?php + +function foo(): void { + return NULL; // not permitted in a void function +} + +// Note the lack of function call: function validated at compile-time +--EXPECTF-- +Fatal error: A void function must not return a value (did you mean "return;" instead of "return null;"?) in %s on line %d diff --git a/Zend/tests/return_types/void_disallowed2.phpt b/Zend/tests/return_types/void_disallowed2.phpt new file mode 100644 index 0000000000..7bbc3ac24f --- /dev/null +++ b/Zend/tests/return_types/void_disallowed2.phpt @@ -0,0 +1,12 @@ +--TEST-- +void return type: unacceptable cases: explicit return of some other value +--FILE-- +<?php + +function foo(): void { + return -1; // not permitted in a void function +} + +// Note the lack of function call: function validated at compile-time +--EXPECTF-- +Fatal error: A void function must not return a value in %s on line %d diff --git a/Zend/tests/return_types/void_parameter.phpt b/Zend/tests/return_types/void_parameter.phpt new file mode 100644 index 0000000000..4c6e918406 --- /dev/null +++ b/Zend/tests/return_types/void_parameter.phpt @@ -0,0 +1,8 @@ +--TEST-- +void return type: not valid as a parameter type +--FILE-- +<?php + +function foobar(void $a) {} +--EXPECTF-- +Fatal error: void cannot be used as a parameter type in %s on line %d diff --git a/Zend/tests/self_and.phpt b/Zend/tests/self_and.phpt index e9ddc849eb..071eb509cb 100644 --- a/Zend/tests/self_and.phpt +++ b/Zend/tests/self_and.phpt @@ -28,7 +28,11 @@ echo "Done\n"; ?> --EXPECTF-- int(18) + +Warning: A non-numeric value encountered in %s on line %d int(0) + +Notice: A non well formed numeric value encountered in %s on line %d int(33) string(1) " " string(2) " " diff --git a/Zend/tests/self_instanceof_outside_class.phpt b/Zend/tests/self_instanceof_outside_class.phpt new file mode 100644 index 0000000000..4caef37883 --- /dev/null +++ b/Zend/tests/self_instanceof_outside_class.phpt @@ -0,0 +1,17 @@ +--TEST-- +instanceof self outside a class +--FILE-- +<?php + +$fn = function() { + try { + new stdClass instanceof self; + } catch (Error $e) { + echo $e->getMessage(), "\n"; + } +}; +$fn(); + +?> +--EXPECT-- +Cannot access self:: when no class scope is active diff --git a/Zend/tests/self_method_or_prop_outside_class.phpt b/Zend/tests/self_method_or_prop_outside_class.phpt new file mode 100644 index 0000000000..e4a499def8 --- /dev/null +++ b/Zend/tests/self_method_or_prop_outside_class.phpt @@ -0,0 +1,36 @@ +--TEST-- +Accessing self:: properties or methods outside a class +--FILE-- +<?php + +$fn = function() { + $str = "foo"; + try { + self::${$str . "bar"}; + } catch (Error $e) { + echo $e->getMessage(), "\n"; + } + try { + unset(self::${$str . "bar"}); + } catch (Error $e) { + echo $e->getMessage(), "\n"; + } + try { + isset(self::${$str . "bar"}); + } catch (Error $e) { + echo $e->getMessage(), "\n"; + } + try { + self::{$str . "bar"}(); + } catch (Error $e) { + echo $e->getMessage(), "\n"; + } +}; +$fn(); + +?> +--EXPECT-- +Cannot access self:: when no class scope is active +Cannot access self:: when no class scope is active +Cannot access self:: when no class scope is active +Cannot access self:: when no class scope is active diff --git a/Zend/tests/self_mod.phpt b/Zend/tests/self_mod.phpt index 19e45d88fc..0b10987aeb 100644 --- a/Zend/tests/self_mod.phpt +++ b/Zend/tests/self_mod.phpt @@ -20,6 +20,10 @@ echo "Done\n"; ?> --EXPECTF-- int(13) + +Warning: A non-numeric value encountered in %s on line %d int(0) + +Notice: A non well formed numeric value encountered in %s on line %d int(3) Done diff --git a/Zend/tests/self_or.phpt b/Zend/tests/self_or.phpt index 991aafa980..cecf70d795 100644 --- a/Zend/tests/self_or.phpt +++ b/Zend/tests/self_or.phpt @@ -28,7 +28,11 @@ echo "Done\n"; ?> --EXPECTF-- int(127) + +Warning: A non-numeric value encountered in %s on line %d int(11) + +Notice: A non well formed numeric value encountered in %s on line %d int(45345) string(1) "f" string(2) "ff" diff --git a/Zend/tests/self_xor.phpt b/Zend/tests/self_xor.phpt index f306a9cd69..e36a315b10 100644 --- a/Zend/tests/self_xor.phpt +++ b/Zend/tests/self_xor.phpt @@ -28,7 +28,11 @@ echo "Done\n"; ?> --EXPECTF-- int(109) + +Warning: A non-numeric value encountered in %s on line %d int(11) + +Notice: A non well formed numeric value encountered in %s on line %d int(45312) string(1) "F" string(2) "FF" diff --git a/Zend/tests/shift_001.phpt b/Zend/tests/shift_001.phpt index aeb399452d..7546f1a6d8 100644 --- a/Zend/tests/shift_001.phpt +++ b/Zend/tests/shift_001.phpt @@ -20,6 +20,10 @@ echo "Done\n"; ?> --EXPECTF-- int(492) + +Warning: A non-numeric value encountered in %s on line %d int(0) + +Notice: A non well formed numeric value encountered in %s on line %d int(362760) Done diff --git a/Zend/tests/shift_002.phpt b/Zend/tests/shift_002.phpt index 4d8421a566..6288152585 100644 --- a/Zend/tests/shift_002.phpt +++ b/Zend/tests/shift_002.phpt @@ -20,6 +20,10 @@ echo "Done\n"; ?> --EXPECTF-- int(30) + +Warning: A non-numeric value encountered in %s on line %d int(0) + +Notice: A non well formed numeric value encountered in %s on line %d int(5668) Done diff --git a/Zend/tests/str_offset_001.phpt b/Zend/tests/str_offset_001.phpt index 8a6b91b49a..3317674857 100644 --- a/Zend/tests/str_offset_001.phpt +++ b/Zend/tests/str_offset_001.phpt @@ -1,51 +1,46 @@ ---TEST--
-string offset 001
---FILE--
-<?php
-function foo($x) {
- var_dump($x);
-}
-
-$str = "abc";
-var_dump($str[-1]);
-var_dump($str[0]);
-var_dump($str[1]);
-var_dump($str[2]);
-var_dump($str[3]);
-var_dump($str[1][0]);
-var_dump($str[2][1]);
-
-foo($str[-1]);
-foo($str[0]);
-foo($str[1]);
-foo($str[2]);
-foo($str[3]);
-foo($str[1][0]);
-foo($str[2][1]);
-?>
---EXPECTF--
-Notice: Uninitialized string offset: -1 in %sstr_offset_001.php on line %d
-string(0) ""
-string(1) "a"
-string(1) "b"
-string(1) "c"
-
-Notice: Uninitialized string offset: 3 in %sstr_offset_001.php on line %d
-string(0) ""
-string(1) "b"
-
-Notice: Uninitialized string offset: 1 in %sstr_offset_001.php on line %d
-string(0) ""
-
-Notice: Uninitialized string offset: -1 in %sstr_offset_001.php on line %d
-string(0) ""
-string(1) "a"
-string(1) "b"
-string(1) "c"
-
-Notice: Uninitialized string offset: 3 in %sstr_offset_001.php on line %d
-string(0) ""
-string(1) "b"
-
-Notice: Uninitialized string offset: 1 in %sstr_offset_001.php on line %d
-string(0) ""
+--TEST-- +string offset 001 +--FILE-- +<?php +// Test positive or null string offsets + +function foo($x) { + var_dump($x); +} + +$str = "abc"; +var_dump($str[0]); +var_dump($str[1]); +var_dump($str[2]); +var_dump($str[3]); +var_dump($str[1][0]); +var_dump($str[2][1]); + +foo($str[0]); +foo($str[1]); +foo($str[2]); +foo($str[3]); +foo($str[1][0]); +foo($str[2][1]); +?> +--EXPECTF-- +string(1) "a" +string(1) "b" +string(1) "c" + +Notice: Uninitialized string offset: 3 in %sstr_offset_001.php on line %d +string(0) "" +string(1) "b" + +Notice: Uninitialized string offset: 1 in %sstr_offset_001.php on line %d +string(0) "" +string(1) "a" +string(1) "b" +string(1) "c" + +Notice: Uninitialized string offset: 3 in %sstr_offset_001.php on line %d +string(0) "" +string(1) "b" + +Notice: Uninitialized string offset: 1 in %sstr_offset_001.php on line %d +string(0) "" diff --git a/Zend/tests/str_offset_003.phpt b/Zend/tests/str_offset_003.phpt new file mode 100644 index 0000000000..e357ac0c01 --- /dev/null +++ b/Zend/tests/str_offset_003.phpt @@ -0,0 +1,37 @@ +--TEST-- +string offset 003 +--FILE-- +<?php +// Test negative string offsets + +function foo($x) { + var_dump($x); +} + +$str = "abcdef"; +var_dump($str[-10]); +var_dump($str[-3]); +var_dump($str[2][-2]); +var_dump($str[2][-1]); + +foo($str[-10]); +foo($str[-3]); +foo($str[2][-2]); +foo($str[2][-1]); +?> +--EXPECTF-- +Notice: Uninitialized string offset: -10 in %sstr_offset_003.php on line %d +string(0) "" +string(1) "d" + +Notice: Uninitialized string offset: -2 in %sstr_offset_003.php on line %d +string(0) "" +string(1) "c" + +Notice: Uninitialized string offset: -10 in %sstr_offset_003.php on line %d +string(0) "" +string(1) "d" + +Notice: Uninitialized string offset: -2 in %sstr_offset_003.php on line %d +string(0) "" +string(1) "c" diff --git a/Zend/tests/str_offset_004.phpt b/Zend/tests/str_offset_004.phpt new file mode 100644 index 0000000000..c8ce607535 --- /dev/null +++ b/Zend/tests/str_offset_004.phpt @@ -0,0 +1,49 @@ +--TEST-- +string offset 004 +--FILE-- +<?php +// Test assignments using (positive and negative) string offsets + +$str = "abcdefghijklmno"; +$i = 3; +$j = -4; + +$str{2} = 'C'; +var_dump($str); + +$str{$i} = 'Z'; +var_dump($str); + +$str{-5} = 'P'; +var_dump($str); + +$str{$j} = 'Q'; +var_dump($str); + +$str{-20} = 'Y'; +var_dump($str); + +$str{-strlen($str)} = strtoupper($str{0}); /* An exotic ucfirst() ;) */ +var_dump($str); + +$str{20} = 'N'; +var_dump($str); + +$str{-2} = 'UFO'; +var_dump($str); + +$str{-$i} = $str{$j*2}; +var_dump($str); +?> +--EXPECTF-- +string(15) "abCdefghijklmno" +string(15) "abCZefghijklmno" +string(15) "abCZefghijPlmno" +string(15) "abCZefghijPQmno" + +Warning: Illegal string offset: -20 in %sstr_offset_004.php on line %d +string(15) "abCZefghijPQmno" +string(15) "AbCZefghijPQmno" +string(21) "AbCZefghijPQmno N" +string(21) "AbCZefghijPQmno UN" +string(21) "AbCZefghijPQmno nUN" diff --git a/Zend/tests/string_offset_errors.phpt b/Zend/tests/string_offset_errors.phpt new file mode 100644 index 0000000000..b709408c35 --- /dev/null +++ b/Zend/tests/string_offset_errors.phpt @@ -0,0 +1,27 @@ +--TEST-- +Some string offset errors +--FILE-- +<?php + +function &test() : string { + $str = "foo"; + return $str[0]; +} + +try { + test(); +} catch (Error $e) { + echo $e->getMessage(), "\n"; +} + +try { + $str = "foo"; + $str[0] =& $str[1]; +} catch (Error $e) { + echo $e->getMessage(), "\n"; +} + +?> +--EXPECT-- +Cannot return string offsets by reference +Cannot create references to/from string offsets diff --git a/Zend/tests/temporary_cleaning_001.phpt b/Zend/tests/temporary_cleaning_001.phpt index 40340bc3da..f2ccbb35b8 100644 --- a/Zend/tests/temporary_cleaning_001.phpt +++ b/Zend/tests/temporary_cleaning_001.phpt @@ -1,7 +1,5 @@ --TEST-- Temporary leak on exception ---XFAIL-- -See Bug #62210 and attempt to fix it in "tmp_livelibess" branch --FILE-- <?php diff --git a/Zend/tests/temporary_cleaning_003.phpt b/Zend/tests/temporary_cleaning_003.phpt index 0f7d9450eb..acff8c85f0 100644 --- a/Zend/tests/temporary_cleaning_003.phpt +++ b/Zend/tests/temporary_cleaning_003.phpt @@ -1,7 +1,5 @@ --TEST-- Fundamental memory leak test on temporaries ---XFAIL-- -See Bug #62210 and attempt to fix it in "tmp_livelibess" branch --FILE-- <?php diff --git a/Zend/tests/temporary_cleaning_004.phpt b/Zend/tests/temporary_cleaning_004.phpt index e2b093654f..b8a02516b0 100644 --- a/Zend/tests/temporary_cleaning_004.phpt +++ b/Zend/tests/temporary_cleaning_004.phpt @@ -1,7 +1,5 @@ --TEST-- Temporary leak with switch ---XFAIL-- -See Bug #62210 and attempt to fix it in "tmp_livelibess" branch --FILE-- <?php diff --git a/Zend/tests/temporary_cleaning_005.phpt b/Zend/tests/temporary_cleaning_005.phpt index f671c32543..e8c7febe0b 100644 --- a/Zend/tests/temporary_cleaning_005.phpt +++ b/Zend/tests/temporary_cleaning_005.phpt @@ -1,7 +1,5 @@ --TEST-- Temporary leak with foreach ---XFAIL-- -See Bug #62210 and attempt to fix it in "tmp_livelibess" branch --FILE-- <?php diff --git a/Zend/tests/temporary_cleaning_006.phpt b/Zend/tests/temporary_cleaning_006.phpt index 435e7b12dd..a7936d3915 100644 --- a/Zend/tests/temporary_cleaning_006.phpt +++ b/Zend/tests/temporary_cleaning_006.phpt @@ -1,7 +1,5 @@ --TEST-- Exception after separation during indirect write to fcall result ---XFAIL-- -See Bug #62210 and attempt to fix it in "tmp_livelibess" branch --FILE-- <?php diff --git a/Zend/tests/temporary_cleaning_008.phpt b/Zend/tests/temporary_cleaning_008.phpt new file mode 100644 index 0000000000..fabd3b4b38 --- /dev/null +++ b/Zend/tests/temporary_cleaning_008.phpt @@ -0,0 +1,15 @@ +--TEST-- +Optimization of constant switch expression +--FILE-- +<?php +try { + switch ("1" . (int)2) { + case 12: + throw new Exception(); + } +} catch (Exception $e) { + echo "exception\n"; +} +?> +--EXPECT-- +exception diff --git a/Zend/tests/temporary_cleaning_009.phpt b/Zend/tests/temporary_cleaning_009.phpt new file mode 100644 index 0000000000..32a84a6ffd --- /dev/null +++ b/Zend/tests/temporary_cleaning_009.phpt @@ -0,0 +1,27 @@ +--TEST-- +Live range & free on return +--FILE-- +<?php +class bar { + public $foo = 1; + public $bar = 1; + + function __destruct() { + throw $this->foo; + } +} +foreach (new bar as &$foo) { + try { + $foo = new Exception; + return; // frees the loop variable + } catch (Exception $e) { + echo "exception\n"; + } +} +echo "end\n"; +?> +--EXPECTF-- +Fatal error: Uncaught Exception in %stemporary_cleaning_009.php:12 +Stack trace: +#0 {main} + thrown in %stemporary_cleaning_009.php on line 12 diff --git a/Zend/tests/temporary_cleaning_010.phpt b/Zend/tests/temporary_cleaning_010.phpt new file mode 100644 index 0000000000..e4456041b2 --- /dev/null +++ b/Zend/tests/temporary_cleaning_010.phpt @@ -0,0 +1,21 @@ +--TEST-- +Live range & throw from finally +--FILE-- +<?php +function test() { + try { + $a = [1, 2, 3]; + return $a + []; + } finally { + throw new Exception; + } +} + +try { + test(); +} catch (Exception $e) { + echo "exception\n"; +} +?> +--EXPECT-- +exception diff --git a/Zend/tests/temporary_cleaning_011.phpt b/Zend/tests/temporary_cleaning_011.phpt new file mode 100644 index 0000000000..e4a6af3ab9 --- /dev/null +++ b/Zend/tests/temporary_cleaning_011.phpt @@ -0,0 +1,20 @@ +--TEST-- +Live range & lists +--FILE-- +<?php +class A { + function __destruct() { + throw new Exception(); + } +} +$b = new A(); +$x = 0; +$c = [[$x,$x]]; +try { + list($a, $b) = $c[0]; +} catch (Exception $e) { + echo "exception\n"; +} +?> +--EXPECT-- +exception diff --git a/Zend/tests/temporary_cleaning_012.phpt b/Zend/tests/temporary_cleaning_012.phpt new file mode 100644 index 0000000000..fdbea6d41d --- /dev/null +++ b/Zend/tests/temporary_cleaning_012.phpt @@ -0,0 +1,20 @@ +--TEST-- +Live range of ZEND_NEW must be assigned to correct variable +--FILE-- +<?php + +class Foo { + public static function test() { + self::$property = new self; + } +} + +try { + Foo::test(); +} catch (Error $e) { + echo $e->getMessage(), "\n"; +} + +?> +--EXPECT-- +Access to undeclared static property: Foo::$property diff --git a/Zend/tests/this_as_global.phpt b/Zend/tests/this_as_global.phpt new file mode 100644 index 0000000000..0ba9ade1b9 --- /dev/null +++ b/Zend/tests/this_as_global.phpt @@ -0,0 +1,12 @@ +--TEST-- +$this as global variable +--FILE-- +<?php +function foo() { + global $this; + var_dump($this); +} +foo(); +?> +--EXPECTF-- +Fatal error: Cannot use $this as global variable in %sthis_as_global.php on line 3 diff --git a/Zend/tests/this_as_parameter.phpt b/Zend/tests/this_as_parameter.phpt new file mode 100644 index 0000000000..93101969a7 --- /dev/null +++ b/Zend/tests/this_as_parameter.phpt @@ -0,0 +1,11 @@ +--TEST-- +$this as parameter +--FILE-- +<?php +function foo($this) { + var_dump($this); +} +foo(5); +?> +--EXPECTF-- +Fatal error: Cannot use $this as parameter in %sthis_as_parameter.php on line 2 diff --git a/Zend/tests/this_as_static.phpt b/Zend/tests/this_as_static.phpt new file mode 100644 index 0000000000..f094449c12 --- /dev/null +++ b/Zend/tests/this_as_static.phpt @@ -0,0 +1,12 @@ +--TEST-- +$this as static variable +--FILE-- +<?php +function foo() { + static $this; + var_dump($this); +} +foo(); +?> +--EXPECTF-- +Fatal error: Cannot use $this as static variable in %sthis_as_static.php on line 3 diff --git a/Zend/tests/this_in_catch.phpt b/Zend/tests/this_in_catch.phpt new file mode 100644 index 0000000000..d621bb18ea --- /dev/null +++ b/Zend/tests/this_in_catch.phpt @@ -0,0 +1,18 @@ +--TEST-- +$this in catch +--FILE-- +<?php +class C { + function foo() { + try { + throw new Exception(); + } catch (Exception $this) { + } + var_dump($this); + } +} +$obj = new C; +$obj->foo(); +?> +--EXPECTF-- +Fatal error: Cannot re-assign $this in %sthis_in_catch.php on line 6 diff --git a/Zend/tests/this_in_extract.phpt b/Zend/tests/this_in_extract.phpt new file mode 100644 index 0000000000..de8da3d0a5 --- /dev/null +++ b/Zend/tests/this_in_extract.phpt @@ -0,0 +1,17 @@ +--TEST-- +$this re-assign in extract() +--FILE-- +<?php +function foo() { + extract(["this"=>42]); + var_dump($this); +} +foo(); +?> +--EXPECTF-- +Fatal error: Uncaught Error: Cannot re-assign $this in %sthis_in_extract.php:3 +Stack trace: +#0 %sthis_in_extract.php(3): extract(Array) +#1 %sthis_in_extract.php(6): foo() +#2 {main} + thrown in %sthis_in_extract.php on line 3 diff --git a/Zend/tests/this_in_foreach_001.phpt b/Zend/tests/this_in_foreach_001.phpt new file mode 100644 index 0000000000..a724338b90 --- /dev/null +++ b/Zend/tests/this_in_foreach_001.phpt @@ -0,0 +1,11 @@ +--TEST-- +$this in foreach +--FILE-- +<?php +$a = [1]; +foreach ($a as $this) { + var_dump($this); +} +?> +--EXPECTF-- +Fatal error: Cannot re-assign $this in %sthis_in_foreach_001.php on line 3 diff --git a/Zend/tests/this_in_foreach_002.phpt b/Zend/tests/this_in_foreach_002.phpt new file mode 100644 index 0000000000..511ea36a24 --- /dev/null +++ b/Zend/tests/this_in_foreach_002.phpt @@ -0,0 +1,11 @@ +--TEST-- +$this in foreach +--FILE-- +<?php +$a = [1]; +foreach ($a as $this => $dummy) { + var_dump($this); +} +?> +--EXPECTF-- +Fatal error: Cannot re-assign $this in %sthis_in_foreach_002.php on line 3 diff --git a/Zend/tests/this_in_foreach_003.phpt b/Zend/tests/this_in_foreach_003.phpt new file mode 100644 index 0000000000..5f5b5ae0d8 --- /dev/null +++ b/Zend/tests/this_in_foreach_003.phpt @@ -0,0 +1,11 @@ +--TEST-- +$this in foreach +--FILE-- +<?php +$a = [1]; +foreach ($a as &$this) { + var_dump($this); +} +?> +--EXPECTF-- +Fatal error: Cannot re-assign $this in %sthis_in_foreach_003.php on line 3 diff --git a/Zend/tests/this_in_foreach_004.phpt b/Zend/tests/this_in_foreach_004.phpt new file mode 100644 index 0000000000..13bfbf18b4 --- /dev/null +++ b/Zend/tests/this_in_foreach_004.phpt @@ -0,0 +1,11 @@ +--TEST-- +$this in foreach +--FILE-- +<?php +$a = [[1]]; +foreach ($a as list($this)) { + var_dump($this); +} +?> +--EXPECTF-- +Fatal error: Cannot re-assign $this in %sthis_in_foreach_004.php on line 3 diff --git a/Zend/tests/this_in_isset.phpt b/Zend/tests/this_in_isset.phpt new file mode 100644 index 0000000000..2ae335df93 --- /dev/null +++ b/Zend/tests/this_in_isset.phpt @@ -0,0 +1,41 @@ +--TEST-- +$this in isset +--FILE-- +<?php +var_dump(isset($this)); +try { + var_dump(isset($this->foo)); +} catch (Throwable $e) { + echo "exception\n"; +} +try { + var_dump(isset($this->foo->bar)); +} catch (Throwable $e) { + echo "exception\n"; +} +try { + var_dump(isset($this[0])); +} catch (Throwable $e) { + echo "exception\n"; +} + +class A extends ArrayObject { + public $foo = 5; + function foo() { + $this[0] = 5; + var_dump(isset($this)); + var_dump(isset($this->foo)); + var_dump(isset($this[0])); + } +} +$a = new A(); +$a->foo(); +?> +--EXPECT-- +bool(false) +exception +exception +exception +bool(true) +bool(true) +bool(true) diff --git a/Zend/tests/this_in_mb_parse_str.phpt b/Zend/tests/this_in_mb_parse_str.phpt new file mode 100644 index 0000000000..8dfac94722 --- /dev/null +++ b/Zend/tests/this_in_mb_parse_str.phpt @@ -0,0 +1,19 @@ +--TEST-- +$this re-assign in mb_parse_str() +--SKIPIF-- +<?php extension_loaded('mbstring') or die('skip mbstring not available'); ?> +--FILE-- +<?php +function foo() { + mb_parse_str("this=42"); + var_dump($this); +} +foo(); +?> +--EXPECTF-- +Fatal error: Uncaught Error: Cannot re-assign $this in %sthis_in_mb_parse_str.php:3 +Stack trace: +#0 %sthis_in_mb_parse_str.php(3): mb_parse_str('this=42') +#1 %sthis_in_mb_parse_str.php(6): foo() +#2 {main} + thrown in %sthis_in_mb_parse_str.php on line 3 diff --git a/Zend/tests/this_in_parse_str.phpt b/Zend/tests/this_in_parse_str.phpt new file mode 100644 index 0000000000..4540d282cc --- /dev/null +++ b/Zend/tests/this_in_parse_str.phpt @@ -0,0 +1,17 @@ +--TEST-- +$this re-assign in parse_str() +--FILE-- +<?php +function foo() { + parse_str("this=42"); + var_dump($this); +} +foo(); +?> +--EXPECTF-- +Fatal error: Uncaught Error: Cannot re-assign $this in %sthis_in_parse_str.php:3 +Stack trace: +#0 %sthis_in_parse_str.php(3): parse_str('this=42') +#1 %sthis_in_parse_str.php(6): foo() +#2 {main} + thrown in %sthis_in_parse_str.php on line 3 diff --git a/Zend/tests/this_in_unset.phpt b/Zend/tests/this_in_unset.phpt new file mode 100644 index 0000000000..bc815049f9 --- /dev/null +++ b/Zend/tests/this_in_unset.phpt @@ -0,0 +1,8 @@ +--TEST-- +$this in unset +--FILE-- +<?php +unset($this); +?> +--EXPECTF-- +Fatal error: Cannot unset $this in %sthis_in_unset.php on line 2 diff --git a/Zend/tests/this_reassign.phpt b/Zend/tests/this_reassign.phpt new file mode 100644 index 0000000000..d965ef4701 --- /dev/null +++ b/Zend/tests/this_reassign.phpt @@ -0,0 +1,17 @@ +--TEST-- +$this re-assign +--FILE-- +<?php +function foo() { + $a = "this"; + $$a = 0; + var_dump($$a); +} +foo(); +?> +--EXPECTF-- +Fatal error: Uncaught Error: Cannot re-assign $this in %sthis_reassign.php:4 +Stack trace: +#0 %sthis_reassign.php(7): foo() +#1 {main} + thrown in %sthis_reassign.php on line 4 diff --git a/Zend/tests/traits/no_static_arg_binding.phpt b/Zend/tests/traits/no_static_arg_binding.phpt new file mode 100644 index 0000000000..3134cf621b --- /dev/null +++ b/Zend/tests/traits/no_static_arg_binding.phpt @@ -0,0 +1,28 @@ +--TEST-- +Don't statically bind arguments for self:: calls in traits +--FILE-- +<?php + +trait T { + public static function method($arg) { + } + public static function call() { + $i = 0; + self::method($i); + var_dump($i); + } +} + +class C { + use T; + + public static function method(&$arg) { + $arg++; + } +} + +C::call(); + +?> +--EXPECT-- +int(1) diff --git a/Zend/tests/try/bug70228.phpt b/Zend/tests/try/bug70228.phpt index 23f5864740..8b812517a3 100644 --- a/Zend/tests/try/bug70228.phpt +++ b/Zend/tests/try/bug70228.phpt @@ -1,16 +1,14 @@ --TEST-- Bug #70228 (memleak if return in finally block) ---XFAIL-- -See https://bugs.php.net/bug.php?id=70228 --FILE-- <?php function foo() { try { return str_repeat("a", 2); } - finally { return true; } + finally { return str_repeat("b", 2); } } var_dump(foo()); ?> --EXPECT-- -string(3) "bar" +string(2) "bb" diff --git a/Zend/tests/try/bug70228_2.phpt b/Zend/tests/try/bug70228_2.phpt new file mode 100644 index 0000000000..c988e706ce --- /dev/null +++ b/Zend/tests/try/bug70228_2.phpt @@ -0,0 +1,20 @@ +--TEST-- +Bug #70228 (memleak if return in finally block) +--FILE-- +<?php +function test() { + try { + throw new Exception(1); + } finally { + try { + throw new Exception(2); + } finally { + return 42; + } + } +} + +var_dump(test()); +?> +--EXPECT-- +int(42) diff --git a/Zend/tests/try/bug70228_3.phpt b/Zend/tests/try/bug70228_3.phpt new file mode 100644 index 0000000000..55dbe4f891 --- /dev/null +++ b/Zend/tests/try/bug70228_3.phpt @@ -0,0 +1,31 @@ +--TEST-- +Bug #70228 (memleak if return in finally block) +--FILE-- +<?php +function test() { + try { + throw new Exception(1); + } finally { + try { + try { + } finally { + return 42; + } + } finally { + throw new Exception(2); + } + } +} + +try { + var_dump(test()); +} catch (Exception $e) { + do { + echo $e->getMessage() . "\n"; + $e = $e->getPrevious(); + } while ($e); +} +?> +--EXPECT-- +2 +1 diff --git a/Zend/tests/try/bug70228_4.phpt b/Zend/tests/try/bug70228_4.phpt new file mode 100644 index 0000000000..f0ab3b0c2c --- /dev/null +++ b/Zend/tests/try/bug70228_4.phpt @@ -0,0 +1,32 @@ +--TEST-- +Bug #70228 (memleak if return in finally block) +--FILE-- +<?php +function test() { + try { + throw new Exception(1); + } finally { + try { + try { + try { + } finally { + return 42; + } + } finally { + throw new Exception(3); + } + } catch (Exception $e) {} + } +} + +try { + var_dump(test()); +} catch (Exception $e) { + do { + echo $e->getMessage() . "\n"; + $e = $e->getPrevious(); + } while ($e); +} +?> +--EXPECT-- +1 diff --git a/Zend/tests/try/bug70228_5.phpt b/Zend/tests/try/bug70228_5.phpt new file mode 100644 index 0000000000..29cbf4910d --- /dev/null +++ b/Zend/tests/try/bug70228_5.phpt @@ -0,0 +1,20 @@ +--TEST-- +Bug #70228 (memleak if return hidden by throw in finally block) +--FILE-- +<?php +function test() { + try { + return str_repeat("a", 2); + } finally { + throw new Exception("ops"); + } +} + +try { + test(); +} catch (Exception $e) { + echo $e->getMessage(), "\n"; +} +?> +--EXPECT-- +ops diff --git a/Zend/tests/try/bug70228_6.phpt b/Zend/tests/try/bug70228_6.phpt new file mode 100644 index 0000000000..fc68657f4c --- /dev/null +++ b/Zend/tests/try/bug70228_6.phpt @@ -0,0 +1,18 @@ +--TEST-- +Bug #70228 (memleak if return in finally block) +--FILE-- +<?php +function test($x) { + foreach ($x as $v) { + try { + return str_repeat("a", 2); + } finally { + return 42; + } + } +} + +var_dump(test([1])); +?> +--EXPECT-- +int(42) diff --git a/Zend/tests/try/bug70228_7.phpt b/Zend/tests/try/bug70228_7.phpt new file mode 100644 index 0000000000..4b8a80351c --- /dev/null +++ b/Zend/tests/try/bug70228_7.phpt @@ -0,0 +1,29 @@ +--TEST-- +Bug #70228 (memleak if return in finally block) +--FILE-- +<?php + +function foo() { + $array = [1, 2, $n = 3]; + foreach ($array as $value) { + var_dump($value); + try { + try { + foreach ($array as $_) { + return str_repeat("a", 2); + } + } finally { + throw new Exception; + } + } catch (Exception $e) { } + } +} + +foo(); +?> +===DONE=== +--EXPECT-- +int(1) +int(2) +int(3) +===DONE=== diff --git a/Zend/tests/try/bug70228_8.phpt b/Zend/tests/try/bug70228_8.phpt new file mode 100644 index 0000000000..ad13113c71 --- /dev/null +++ b/Zend/tests/try/bug70228_8.phpt @@ -0,0 +1,30 @@ +--TEST-- +Bug #70228 (memleak if return in finally block) +--FILE-- +<?php + +function foo() { + $array = [1, 2, $n = 3]; + foreach ($array as $value) { + var_dump($value); + try { + try { + switch (str_repeat("b", 2)) { + case "bb": + return str_repeat("a", 2); + } + } finally { + throw new Exception; + } + } catch (Exception $e) { } + } +} + +foo(); +?> +===DONE=== +--EXPECT-- +int(1) +int(2) +int(3) +===DONE=== diff --git a/Zend/tests/try/bug71604.phpt b/Zend/tests/try/bug71604.phpt new file mode 100644 index 0000000000..79803b93ea --- /dev/null +++ b/Zend/tests/try/bug71604.phpt @@ -0,0 +1,25 @@ +--TEST-- +Bug #71604: Aborted Generators continue after nested finally +--FILE-- +<?php +function gen() { + try { + try { + yield; + } finally { + print "INNER\n"; + } + } catch (Exception $e) { + print "EX\n"; + } finally { + print "OUTER\n"; + } + print "NOTREACHED\n"; +} + +gen()->current(); + +?> +--EXPECT-- +INNER +OUTER diff --git a/Zend/tests/try/bug71604_2.phpt b/Zend/tests/try/bug71604_2.phpt new file mode 100644 index 0000000000..8736cd8347 --- /dev/null +++ b/Zend/tests/try/bug71604_2.phpt @@ -0,0 +1,39 @@ +--TEST-- +Bug #71604: Aborted Generators continue after nested finally (2) +--FILE-- +<?php + +function gen() { + try { + throw new Exception(1); + } finally { + try { + throw new Exception(2); + } finally { + try { + yield; + } finally { + } + } + } +} + +try { + gen()->rewind(); +} catch (Exception $e) { + echo $e, "\n"; +} + +?> +--EXPECTF-- +Exception: 1 in %s:%d +Stack trace: +#0 [internal function]: gen() +#1 %s(%d): Generator->rewind() +#2 {main} + +Next Exception: 2 in %s:%d +Stack trace: +#0 [internal function]: gen() +#1 %s(%d): Generator->rewind() +#2 {main} diff --git a/Zend/tests/try/bug71604_3.phpt b/Zend/tests/try/bug71604_3.phpt new file mode 100644 index 0000000000..058c9a70a8 --- /dev/null +++ b/Zend/tests/try/bug71604_3.phpt @@ -0,0 +1,38 @@ +--TEST-- +Bug #71604: Aborted Generators continue after nested finally (3) +--FILE-- +<?php + +function gen() { + try { + throw new Exception(1); + } finally { + try { + yield; + } finally { + try { + throw new Exception(2); + } finally { + } + } + } +} + +try { + gen()->rewind(); +} catch (Exception $e) { + echo $e, "\n"; +} + +?> +--EXPECTF-- +Exception: 1 in %s:%d +Stack trace: +#0 [internal function]: gen() +#1 %s(%d): Generator->rewind() +#2 {main} + +Next Exception: 2 in %s:%d +Stack trace: +#0 %s(%d): gen() +#1 {main} diff --git a/Zend/tests/try/bug72213.phpt b/Zend/tests/try/bug72213.phpt new file mode 100644 index 0000000000..624050295e --- /dev/null +++ b/Zend/tests/try/bug72213.phpt @@ -0,0 +1,25 @@ +--TEST-- +Bug #72213 (Finally leaks on nested exceptions) +--FILE-- +<?php +function test() { + try { + throw new Exception('a'); + } finally { + try { + throw new Exception('b'); + } finally { + } + } +} + +try { + test(); +} catch (Exception $e) { + var_dump($e->getMessage()); + var_dump($e->getPrevious()->getMessage()); +} +?> +--EXPECT-- +string(1) "b" +string(1) "a" diff --git a/Zend/tests/try/bug72213_2.phpt b/Zend/tests/try/bug72213_2.phpt new file mode 100644 index 0000000000..790abe125d --- /dev/null +++ b/Zend/tests/try/bug72213_2.phpt @@ -0,0 +1,25 @@ +--TEST-- +Bug #72213 (Finally leaks on nested exceptions) +--FILE-- +<?php +function test() { + try { + throw new Exception(1); + } finally { + try { + try { + throw new Exception(2); + } finally { + } + } catch (Exception $e) { + } + } +} + +try { + test(); +} catch (Exception $e) { + echo "caught {$e->getMessage()}\n"; +} +--EXPECT-- +caught 1 diff --git a/Zend/tests/try/bug74444.phpt b/Zend/tests/try/bug74444.phpt new file mode 100644 index 0000000000..838d12ef03 --- /dev/null +++ b/Zend/tests/try/bug74444.phpt @@ -0,0 +1,77 @@ +--TEST-- +Bug #74444 (multiple catch freezes in some cases) +--FILE-- +<?php +function foo() +{ + echo ''; + echo ''; + echo ''; + echo ''; + echo ''; + echo ''; + echo ''; + echo ''; + echo ''; + echo ''; + echo ''; + echo ''; + echo ''; + echo ''; + echo ''; + echo ''; + echo ''; + echo ''; + echo ''; + echo ''; + echo ''; + echo ''; + echo ''; + echo ''; + echo ''; + echo ''; + echo ''; + echo ''; + echo ''; + echo ''; + echo ''; + echo ''; + echo ''; + echo ''; + echo ''; + echo ''; + echo ''; + echo ''; + echo ''; + echo ''; + echo ''; + echo ''; + echo ''; + echo ''; + echo ''; + echo ''; + echo ''; + echo ''; + echo ''; + echo ''; + echo ''; + echo ''; + echo ''; + echo ''; + echo ''; + echo ''; + echo ''; + echo ''; + echo ''; + try { + throw new \RuntimeException(); + } catch (\FooEx | \RuntimeException $e) { + echo 1; + } + echo 2; +} + +foo(); + +--EXPECT-- +12 diff --git a/Zend/tests/try/exceptions.inc b/Zend/tests/try/exceptions.inc new file mode 100644 index 0000000000..68cb1c62f7 --- /dev/null +++ b/Zend/tests/try/exceptions.inc @@ -0,0 +1,6 @@ +<?php + +class Exception1 extends Exception {} +class Exception2 extends Exception {} +class Exception3 extends Exception {} +class Exception4 extends Exception {} diff --git a/Zend/tests/try/try_finally_021.phpt b/Zend/tests/try/try_finally_021.phpt new file mode 100644 index 0000000000..ed162f40d0 --- /dev/null +++ b/Zend/tests/try/try_finally_021.phpt @@ -0,0 +1,20 @@ +--TEST-- +Live range & return from finally +--FILE-- +<?php +$array = [1]; +foreach ([0] as $_) { + foreach ($array as $v) { + try { + echo "ok\n"; + return; + } finally { + echo "ok\n"; + return; + } + } +} +?> +--EXPECT-- +ok +ok diff --git a/Zend/tests/try/try_finally_022.phpt b/Zend/tests/try/try_finally_022.phpt new file mode 100644 index 0000000000..51f6a26419 --- /dev/null +++ b/Zend/tests/try/try_finally_022.phpt @@ -0,0 +1,41 @@ +--TEST-- +Try finally (exception in "return" statement) +--FILE-- +<?php +class A { + public $x = 1; + public $y = 2; + function __destruct() { + throw new Exception(); + } +} +try{ + $a = 0; + switch ($a) { + case 0: + } + switch ($a) { + case 0: + } + switch ($a) { + case 0: + } + foreach([new stdClass()] as $x) { + foreach(new A() as $a) { + foreach([new stdClass()] as $y) { + try { + if (0) { echo "0" . (int)5; } + return $a; + } catch (Exception $e) { + echo "exception1\n"; + } + } + } + } +} catch (Exception $e) { + echo "exception2\n"; +} +?> +--EXPECT-- +exception2 + diff --git a/Zend/tests/try/try_finally_023.phpt b/Zend/tests/try/try_finally_023.phpt new file mode 100644 index 0000000000..e88eddb3b2 --- /dev/null +++ b/Zend/tests/try/try_finally_023.phpt @@ -0,0 +1,37 @@ +--TEST-- +Loop var dtor throwing exception during return inside try/catch inside finally +--FILE-- +<?php + +class Dtor { + public function __destruct() { + throw new Exception(2); + } +} + +function test() { + try { + throw new Exception(1); + } finally { + try { + foreach ([new Dtor] as $v) { + unset($v); + return 42; + } + } catch (Exception $e) { + } + } +} + +try { + test(); +} catch (Exception $e) { + echo $e, "\n"; +} + +?> +--EXPECTF-- +Exception: 1 in %s:%d +Stack trace: +#0 %s(%d): test() +#1 {main} diff --git a/Zend/tests/try/try_finally_024.phpt b/Zend/tests/try/try_finally_024.phpt new file mode 100644 index 0000000000..eb0b26acbf --- /dev/null +++ b/Zend/tests/try/try_finally_024.phpt @@ -0,0 +1,38 @@ +--TEST-- +Exception in finally inside finally following try/catch containing throwing try/finally +--FILE-- +<?php + +function test() { + try { + throw new Exception(1); + } finally { + try { + try { + } finally { + throw new Exception(2); + } + } catch (Exception $e) {} + try { + } finally { + throw new Exception(3); + } + } +} + +try { + test(); +} catch (Exception $e) { + echo $e, "\n"; +} +?> +--EXPECTF-- +Exception: 1 in %s:%d +Stack trace: +#0 %s(%d): test() +#1 {main} + +Next Exception: 3 in %s:%d +Stack trace: +#0 %s(%d): test() +#1 {main} diff --git a/Zend/tests/try/try_finally_025.phpt b/Zend/tests/try/try_finally_025.phpt new file mode 100644 index 0000000000..7ca535bcf6 --- /dev/null +++ b/Zend/tests/try/try_finally_025.phpt @@ -0,0 +1,28 @@ +--TEST-- +Throw in try of try/finally inside catch +--FILE-- +<?php + +function test() { + try { + throw new Exception(1); + } catch (Exception $e) { + try { + throw new Exception(2); + } finally { + } + } +} + +try { + test(); +} catch (Exception $e) { + echo $e, "\n"; +} + +?> +--EXPECTF-- +Exception: 2 in %s:%d +Stack trace: +#0 %s(%d): test() +#1 {main} diff --git a/Zend/tests/try/try_finally_026.phpt b/Zend/tests/try/try_finally_026.phpt new file mode 100644 index 0000000000..29a5de3b3a --- /dev/null +++ b/Zend/tests/try/try_finally_026.phpt @@ -0,0 +1,37 @@ +--TEST-- +Throw in finally inside catch inside finally +--FILE-- +<?php + +function test() { + try { + throw new Exception(1); + } finally { + try { + throw new Exception(2); + } catch (Exception $e) { + try { + } finally { + throw new Exception(3); + } + } + } +} + +try { + test(); +} catch (Exception $e) { + echo $e, "\n"; +} + +?> +--EXPECTF-- +Exception: 1 in %s:%d +Stack trace: +#0 %s(%d): test() +#1 {main} + +Next Exception: 3 in %s:%d +Stack trace: +#0 %s(%d): test() +#1 {main} diff --git a/Zend/tests/try/try_finally_027.phpt b/Zend/tests/try/try_finally_027.phpt new file mode 100644 index 0000000000..1e66479eb0 --- /dev/null +++ b/Zend/tests/try/try_finally_027.phpt @@ -0,0 +1,34 @@ +--TEST-- +Return in try with throw in finally, inside other finally +--FILE-- +<?php + +function test() { + try { + throw new Exception(1); + } finally { + try { + return 42; + } finally { + throw new Exception(2); + } + } +} + +try { + test(); +} catch (Exception $e) { + echo $e, "\n"; +} + +?> +--EXPECTF-- +Exception: 1 in %s:%d +Stack trace: +#0 %s(%d): test() +#1 {main} + +Next Exception: 2 in %s:%d +Stack trace: +#0 %s(%d): test() +#1 {main} diff --git a/Zend/tests/try/try_multicatch_001.phpt b/Zend/tests/try/try_multicatch_001.phpt new file mode 100644 index 0000000000..0dffd32c72 --- /dev/null +++ b/Zend/tests/try/try_multicatch_001.phpt @@ -0,0 +1,19 @@ +--TEST-- +Parsing test +--FILE-- +<?php + +require_once __DIR__ . '/exceptions.inc'; + +try { + echo 'TRY' . PHP_EOL; +} catch(Exception1 | Exception2 $e) { + echo 'Exception'; +} finally { + echo 'FINALLY' . PHP_EOL; +} + +?> +--EXPECT-- +TRY +FINALLY diff --git a/Zend/tests/try/try_multicatch_002.phpt b/Zend/tests/try/try_multicatch_002.phpt new file mode 100644 index 0000000000..0e70fec7eb --- /dev/null +++ b/Zend/tests/try/try_multicatch_002.phpt @@ -0,0 +1,21 @@ +--TEST-- +Catch first exception in the multicatch +--FILE-- +<?php + +require_once __DIR__ . '/exceptions.inc'; + +try { + echo 'TRY' . PHP_EOL; + throw new Exception1; +} catch(Exception1 | Exception2 | Exception3 $e) { + echo get_class($e) . PHP_EOL; +} finally { + echo 'FINALLY' . PHP_EOL; +} + +?> +--EXPECT-- +TRY +Exception1 +FINALLY diff --git a/Zend/tests/try/try_multicatch_003.phpt b/Zend/tests/try/try_multicatch_003.phpt new file mode 100644 index 0000000000..6aed1a2b09 --- /dev/null +++ b/Zend/tests/try/try_multicatch_003.phpt @@ -0,0 +1,21 @@ +--TEST-- +Catch second exception in the multicatch +--FILE-- +<?php + +require_once __DIR__ . '/exceptions.inc'; + +try { + echo 'TRY' . PHP_EOL; + throw new Exception2; +} catch(Exception1 | Exception2 | Exception3 $e) { + echo get_class($e) . PHP_EOL; +} finally { + echo 'FINALLY' . PHP_EOL; +} + +?> +--EXPECT-- +TRY +Exception2 +FINALLY diff --git a/Zend/tests/try/try_multicatch_004.phpt b/Zend/tests/try/try_multicatch_004.phpt new file mode 100644 index 0000000000..d8b245a767 --- /dev/null +++ b/Zend/tests/try/try_multicatch_004.phpt @@ -0,0 +1,21 @@ +--TEST-- +Catch last exception in the multicatch +--FILE-- +<?php + +require_once __DIR__ . '/exceptions.inc'; + +try { + echo 'TRY' . PHP_EOL; + throw new Exception3; +} catch(Exception1 | Exception2 | Exception3 $e) { + echo get_class($e) . PHP_EOL; +} finally { + echo 'FINALLY' . PHP_EOL; +} + +?> +--EXPECT-- +TRY +Exception3 +FINALLY diff --git a/Zend/tests/try/try_multicatch_005.phpt b/Zend/tests/try/try_multicatch_005.phpt new file mode 100644 index 0000000000..cc3fc890fa --- /dev/null +++ b/Zend/tests/try/try_multicatch_005.phpt @@ -0,0 +1,25 @@ +--TEST-- +Catch exception in the nested multicatch +--FILE-- +<?php + +require_once __DIR__ . '/exceptions.inc'; + +try { + try { + echo 'TRY' . PHP_EOL; + throw new Exception3; + } catch (Exception1 | Exception3 $e) { + echo get_class($e) . PHP_EOL; + } +} catch(Exception2 | Exception3 $e) { + echo 'Should never be executed'; +} finally { + echo 'FINALLY' . PHP_EOL; +} + +?> +--EXPECT-- +TRY +Exception3 +FINALLY diff --git a/Zend/tests/try/try_multicatch_006.phpt b/Zend/tests/try/try_multicatch_006.phpt new file mode 100644 index 0000000000..e4505f1b24 --- /dev/null +++ b/Zend/tests/try/try_multicatch_006.phpt @@ -0,0 +1,22 @@ +--TEST-- +Catch first exception in the second multicatch +--FILE-- +<?php +require_once __DIR__ . '/exceptions.inc'; + +try { + echo 'TRY' . PHP_EOL; + throw new Exception3; +} catch(Exception1 | Exception2 $e) { + echo get_class($e) . PHP_EOL; +} catch(Exception3 | Exception4 $e) { + echo get_class($e) . PHP_EOL; +} finally { + echo 'FINALLY' . PHP_EOL; +} +?> +--EXPECT-- +TRY +Exception3 +FINALLY + diff --git a/Zend/tests/try/try_multicatch_007.phpt b/Zend/tests/try/try_multicatch_007.phpt new file mode 100644 index 0000000000..aa073b0592 --- /dev/null +++ b/Zend/tests/try/try_multicatch_007.phpt @@ -0,0 +1,22 @@ +--TEST-- +Catch second exception in the second multicatch +--FILE-- +<?php +require_once __DIR__ . '/exceptions.inc'; + +try { + echo 'TRY' . PHP_EOL; + throw new Exception4; +} catch(Exception1 | Exception2 $e) { + echo get_class($e) . PHP_EOL; +} catch(Exception3 | Exception4 $e) { + echo get_class($e) . PHP_EOL; +} finally { + echo 'FINALLY' . PHP_EOL; +} +?> +--EXPECT-- +TRY +Exception4 +FINALLY + diff --git a/Zend/tests/type_declarations/iterable_001.phpt b/Zend/tests/type_declarations/iterable_001.phpt new file mode 100644 index 0000000000..f0c8bba610 --- /dev/null +++ b/Zend/tests/type_declarations/iterable_001.phpt @@ -0,0 +1,48 @@ +--TEST-- +iterable type#001 +--FILE-- +<?php + +function test(iterable $iterable) { + var_dump($iterable); +} + +function gen() { + yield 1; + yield 2; + yield 3; +}; + +test([1, 2, 3]); +test(gen()); +test(new ArrayIterator([1, 2, 3])); + +try { + test(1); +} catch (Throwable $e) { + echo $e->getMessage(); +} + +--EXPECTF-- +array(3) { + [0]=> + int(1) + [1]=> + int(2) + [2]=> + int(3) +} +object(Generator)#1 (0) { +} +object(ArrayIterator)#1 (1) { + ["storage":"ArrayIterator":private]=> + array(3) { + [0]=> + int(1) + [1]=> + int(2) + [2]=> + int(3) + } +} +Argument 1 passed to test() must be iterable, integer given, called in %s on line %d diff --git a/Zend/tests/type_declarations/iterable_002.phpt b/Zend/tests/type_declarations/iterable_002.phpt new file mode 100644 index 0000000000..74f6d83f1e --- /dev/null +++ b/Zend/tests/type_declarations/iterable_002.phpt @@ -0,0 +1,21 @@ +--TEST-- +iterable type#002 - Default values +--FILE-- +<?php + +function foo(iterable $iterable = null) { + // Null should be allowed as a default value +} + +function bar(iterable $iterable = []) { + // Array should be allowed as a default value +} + +function baz(iterable $iterable = 1) { + // No other values should be allowed as defaults +} + +?> +--EXPECTF-- + +Fatal error: Default value for parameters with iterable type can only be an array or NULL in %s on line %d diff --git a/Zend/tests/type_declarations/iterable_003.phpt b/Zend/tests/type_declarations/iterable_003.phpt new file mode 100644 index 0000000000..8c91c993d0 --- /dev/null +++ b/Zend/tests/type_declarations/iterable_003.phpt @@ -0,0 +1,32 @@ +--TEST-- +iterable type#003 - Return types +--FILE-- +<?php + +function foo(): iterable { + return []; +} +function bar(): iterable { + return (function () { yield; })(); +} + +function baz(): iterable { + return 1; +} + +var_dump(foo()); +var_dump(bar()); + +try { + baz(); +} catch (Throwable $e) { + echo $e->getMessage(); +} + +?> +--EXPECT-- +array(0) { +} +object(Generator)#2 (0) { +} +Return value of baz() must be iterable, integer returned diff --git a/Zend/tests/type_declarations/iterable_004.phpt b/Zend/tests/type_declarations/iterable_004.phpt new file mode 100644 index 0000000000..47e79fa6b3 --- /dev/null +++ b/Zend/tests/type_declarations/iterable_004.phpt @@ -0,0 +1,25 @@ +--TEST-- +iterable type#004 - Parameter covariance +--FILE-- +<?php + +class Foo { + function testArray(array $array) {} + + function testTraversable(Traversable $traversable) {} + + function testScalar(int $int) {} +} + +class Bar extends Foo { + function testArray(iterable $iterable) {} + + function testTraversable(iterable $iterable) {} + + function testScalar(iterable $iterable) {} +} + +?> +--EXPECTF-- + +Warning: Declaration of Bar::testScalar(iterable $iterable) should be compatible with Foo::testScalar(int $int) in %s on line %d diff --git a/Zend/tests/type_declarations/iterable_005.phpt b/Zend/tests/type_declarations/iterable_005.phpt new file mode 100644 index 0000000000..9c0584b51a --- /dev/null +++ b/Zend/tests/type_declarations/iterable_005.phpt @@ -0,0 +1,33 @@ +--TEST-- +iterable type#005 - Return type covariance +--FILE-- +<?php + +class Test { + function method(): iterable { + return []; + } +} + +class TestArray extends Test { + function method(): array { + return []; + } +} + +class TestTraversable extends Test { + function method(): Traversable { + return new ArrayIterator([]); + } +} + +class TestScalar extends Test { + function method(): int { + return 1; + } +} + +?> +--EXPECTF-- + +Fatal error: Declaration of TestScalar::method(): int must be compatible with Test::method(): iterable in %s on line %d diff --git a/Zend/tests/type_declarations/nullable_typed_return_without_value.phpt b/Zend/tests/type_declarations/nullable_typed_return_without_value.phpt new file mode 100644 index 0000000000..b16e7c6434 --- /dev/null +++ b/Zend/tests/type_declarations/nullable_typed_return_without_value.phpt @@ -0,0 +1,14 @@ +--TEST-- +Nullable typed return without value generates friendlier error message +--FILE-- +<?php + +function test() : ?int { + return; +} + +test(); + +?> +--EXPECTF-- +Fatal error: A function with return type must return a value (did you mean "return null;" instead of "return;"?) in %s on line %d diff --git a/Zend/tests/type_declarations/nullable_void.phpt b/Zend/tests/type_declarations/nullable_void.phpt new file mode 100644 index 0000000000..4ff0edb0d8 --- /dev/null +++ b/Zend/tests/type_declarations/nullable_void.phpt @@ -0,0 +1,11 @@ +--TEST-- +Void cannot be nullable +--FILE-- +<?php + +function test() : ?void { +} + +?> +--EXPECTF-- +Fatal error: Void type cannot be nullable in %s on line %d diff --git a/Zend/tests/type_declarations/scalar_none.phpt b/Zend/tests/type_declarations/scalar_none.phpt index 3bec609599..025276adef 100644 --- a/Zend/tests/type_declarations/scalar_none.phpt +++ b/Zend/tests/type_declarations/scalar_none.phpt @@ -28,20 +28,20 @@ foreach ($functions as $type => $function) { echo "Testing $type:", PHP_EOL; try { var_dump($function()); - } catch (TypeError $e) { + } catch (Throwable $e) { echo "*** Caught " . $e->getMessage() . PHP_EOL; } } echo PHP_EOL . "Done"; --EXPECTF-- Testing int: -*** Caught Argument 1 passed to {closure}() must be of the type integer, none given, called in %s on line %d +*** Caught Too few arguments to function {closure}(), 0 passed in %s on line %d and exactly 1 expected Testing float: -*** Caught Argument 1 passed to {closure}() must be of the type float, none given, called in %s on line %d +*** Caught Too few arguments to function {closure}(), 0 passed in %s on line %d and exactly 1 expected Testing string: -*** Caught Argument 1 passed to {closure}() must be of the type string, none given, called in %s on line %d +*** Caught Too few arguments to function {closure}(), 0 passed in %s on line %d and exactly 1 expected Testing bool: -*** Caught Argument 1 passed to {closure}() must be of the type boolean, none given, called in %s on line %d +*** Caught Too few arguments to function {closure}(), 0 passed in %s on line %d and exactly 1 expected Testing int nullable: NULL Testing float nullable: diff --git a/Zend/tests/type_declarations/typed_return_without_value.phpt b/Zend/tests/type_declarations/typed_return_without_value.phpt new file mode 100644 index 0000000000..1bf932becb --- /dev/null +++ b/Zend/tests/type_declarations/typed_return_without_value.phpt @@ -0,0 +1,14 @@ +--TEST-- +Typed return without value generates compile-time error +--FILE-- +<?php + +function test() : int { + return; +} + +test(); + +?> +--EXPECTF-- +Fatal error: A function with return type must return a value in %s on line %d diff --git a/Zend/tests/typehints/fq_nullable.phpt b/Zend/tests/typehints/fq_nullable.phpt new file mode 100644 index 0000000000..24ba2ffa62 --- /dev/null +++ b/Zend/tests/typehints/fq_nullable.phpt @@ -0,0 +1,13 @@ +--TEST-- +Fully-qualified nullable parameter type +--FILE-- +<?php + +namespace Foo; +function test(?\stdClass $param) {} +test(new \stdClass); + +?> +===DONE=== +--EXPECT-- +===DONE=== diff --git a/Zend/tests/typehints/or_null.phpt b/Zend/tests/typehints/or_null.phpt new file mode 100644 index 0000000000..8c20052165 --- /dev/null +++ b/Zend/tests/typehints/or_null.phpt @@ -0,0 +1,317 @@ +--TEST-- +Test "or null"/"or be null" in type-checking errors for userland functions +--FILE-- +<?php + +// This should test every branch in zend_execute.c's `zend_verify_arg_type`, `zend_verify_return_type` and `zend_verify_missing_return_type` functions which produces an "or null"/"or be null" part in its error message + +function unloadedClass(?I\Dont\Exist $param) {} + +try { + unloadedClass(new \StdClass); +} catch (\TypeError $e) { + echo $e, PHP_EOL; +} + +class RealClass {} +interface RealInterface {} + +function loadedClass(?RealClass $param) {} +function loadedInterface(?RealInterface $param) {} + +try { + loadedClass(new \StdClass); +} catch (\TypeError $e) { + echo $e, PHP_EOL; +} + +try { + loadedInterface(new \StdClass); +} catch (\TypeError $e) { + echo $e, PHP_EOL; +} + +try { + unloadedClass(1); +} catch (\TypeError $e) { + echo $e, PHP_EOL; +} + +try { + loadedClass(1); +} catch (\TypeError $e) { + echo $e, PHP_EOL; +} + +try { + loadedInterface(1); +} catch (\TypeError $e) { + echo $e, PHP_EOL; +} + +function callableF(?callable $param) {} + +try { + callableF(1); +} catch (\TypeError $e) { + echo $e, PHP_EOL; +} + +function iterableF(?iterable $param) {} + +try { + iterableF(1); +} catch (\TypeError $e) { + echo $e, PHP_EOL; +} + +function intF(?int $param) {} + +try { + intF(new StdClass); +} catch (\TypeError $e) { + echo $e, PHP_EOL; +} + +function returnUnloadedClass(): ?I\Dont\Exist { + return new \StdClass; +} + +try { + returnUnloadedClass(); +} catch (\TypeError $e) { + echo $e, PHP_EOL; +} + +function returnLoadedClass(): ?RealClass { + return new \StdClass; +} + +try { + returnLoadedClass(); +} catch (\TypeError $e) { + echo $e, PHP_EOL; +} + +function returnLoadedInterface(): ?RealInterface { + return new \StdClass; +} + +try { + returnLoadedInterface(); +} catch (\TypeError $e) { + echo $e, PHP_EOL; +} + +function returnUnloadedClassScalar(): ?I\Dont\Exist { + return 1; +} + +try { + returnUnloadedClassScalar(); +} catch (\TypeError $e) { + echo $e, PHP_EOL; +} + +function returnLoadedClassScalar(): ?RealClass { + return 1; +} + +try { + returnLoadedClassScalar(); +} catch (\TypeError $e) { + echo $e, PHP_EOL; +} + +function returnLoadedInterfaceScalar(): ?RealInterface { + return 1; +} + +try { + returnLoadedInterfaceScalar(); +} catch (\TypeError $e) { + echo $e, PHP_EOL; +} + +function returnCallable(): ?callable { + return 1; +} + +try { + returnCallable(); +} catch (\TypeError $e) { + echo $e, PHP_EOL; +} + +function returnIterable(): ?iterable { + return 1; +} + +try { + returnIterable(); +} catch (\TypeError $e) { + echo $e, PHP_EOL; +} + +function returnInt(): ?int { + return new \StdClass; +} + +try { + returnInt(); +} catch (\TypeError $e) { + echo $e, PHP_EOL; +} + +function returnMissingUnloadedClass(): ?I\Dont\Exist { +} + +try { + returnMissingUnloadedClass(); +} catch (\TypeError $e) { + echo $e, PHP_EOL; +} + +function returnMissingLoadedClass(): ?RealClass { +} + +try { + returnMissingLoadedClass(); +} catch (\TypeError $e) { + echo $e, PHP_EOL; +} + +function returnMissingLoadedInterface(): ?RealInterface { +} + +try { + returnMissingLoadedInterface(); +} catch (\TypeError $e) { + echo $e, PHP_EOL; +} + +function returnMissingCallable(): ?callable { +} + +try { + returnMissingCallable(); +} catch (\TypeError $e) { + echo $e, PHP_EOL; +} + +function returnMissingIterable(): ?iterable { +} + +try { + returnMissingIterable(); +} catch (\TypeError $e) { + echo $e, PHP_EOL; +} + +function returnMissingInt(): ?int { +} + +try { + returnMissingInt(); +} catch (\TypeError $e) { + echo $e, PHP_EOL; +} + +?> +--EXPECTF-- +TypeError: Argument 1 passed to unloadedClass() must be an instance of I\Dont\Exist or null, instance of stdClass given, called in %s on line 8 and defined in %s:5 +Stack trace: +#0 %s(8): unloadedClass(Object(stdClass)) +#1 {main} +TypeError: Argument 1 passed to loadedClass() must be an instance of RealClass or null, instance of stdClass given, called in %s on line 20 and defined in %s:16 +Stack trace: +#0 %s(20): loadedClass(Object(stdClass)) +#1 {main} +TypeError: Argument 1 passed to loadedInterface() must implement interface RealInterface or be null, instance of stdClass given, called in %s on line 26 and defined in %s:17 +Stack trace: +#0 %s(26): loadedInterface(Object(stdClass)) +#1 {main} +TypeError: Argument 1 passed to unloadedClass() must be an instance of I\Dont\Exist or null, integer given, called in %s on line 32 and defined in %s:5 +Stack trace: +#0 %s(32): unloadedClass(1) +#1 {main} +TypeError: Argument 1 passed to loadedClass() must be an instance of RealClass or null, integer given, called in %s on line 38 and defined in %s:16 +Stack trace: +#0 %s(38): loadedClass(1) +#1 {main} +TypeError: Argument 1 passed to loadedInterface() must implement interface RealInterface or be null, integer given, called in %s on line 44 and defined in %s:17 +Stack trace: +#0 %s(44): loadedInterface(1) +#1 {main} +TypeError: Argument 1 passed to callableF() must be callable or null, integer given, called in %s on line 52 and defined in %s:49 +Stack trace: +#0 %s(52): callableF(1) +#1 {main} +TypeError: Argument 1 passed to iterableF() must be iterable or null, integer given, called in %s on line 60 and defined in %s:57 +Stack trace: +#0 %s(60): iterableF(1) +#1 {main} +TypeError: Argument 1 passed to intF() must be of the type integer or null, object given, called in %s on line 68 and defined in %s:65 +Stack trace: +#0 %s(68): intF(Object(stdClass)) +#1 {main} +TypeError: Return value of returnUnloadedClass() must be an instance of I\Dont\Exist or null, instance of stdClass returned in %s:74 +Stack trace: +#0 %s(78): returnUnloadedClass() +#1 {main} +TypeError: Return value of returnLoadedClass() must be an instance of RealClass or null, instance of stdClass returned in %s:84 +Stack trace: +#0 %s(88): returnLoadedClass() +#1 {main} +TypeError: Return value of returnLoadedInterface() must implement interface RealInterface or be null, instance of stdClass returned in %s:94 +Stack trace: +#0 %s(98): returnLoadedInterface() +#1 {main} +TypeError: Return value of returnUnloadedClassScalar() must be an instance of I\Dont\Exist or null, integer returned in %s:104 +Stack trace: +#0 %s(108): returnUnloadedClassScalar() +#1 {main} +TypeError: Return value of returnLoadedClassScalar() must be an instance of RealClass or null, integer returned in %s:114 +Stack trace: +#0 %s(118): returnLoadedClassScalar() +#1 {main} +TypeError: Return value of returnLoadedInterfaceScalar() must implement interface RealInterface or be null, integer returned in %s:124 +Stack trace: +#0 %s(128): returnLoadedInterfaceScalar() +#1 {main} +TypeError: Return value of returnCallable() must be callable or null, integer returned in %s:134 +Stack trace: +#0 %s(138): returnCallable() +#1 {main} +TypeError: Return value of returnIterable() must be iterable or null, integer returned in %s:144 +Stack trace: +#0 %s(148): returnIterable() +#1 {main} +TypeError: Return value of returnInt() must be of the type integer or null, object returned in %s:154 +Stack trace: +#0 %s(158): returnInt() +#1 {main} +TypeError: Return value of returnMissingUnloadedClass() must be an instance of I\Dont\Exist or null, none returned in %s:164 +Stack trace: +#0 %s(167): returnMissingUnloadedClass() +#1 {main} +TypeError: Return value of returnMissingLoadedClass() must be an instance of RealClass or null, none returned in %s:173 +Stack trace: +#0 %s(176): returnMissingLoadedClass() +#1 {main} +TypeError: Return value of returnMissingLoadedInterface() must implement interface RealInterface or be null, none returned in %s:182 +Stack trace: +#0 %s(185): returnMissingLoadedInterface() +#1 {main} +TypeError: Return value of returnMissingCallable() must be callable or null, none returned in %s:191 +Stack trace: +#0 %s(194): returnMissingCallable() +#1 {main} +TypeError: Return value of returnMissingIterable() must be iterable or null, none returned in %s:200 +Stack trace: +#0 %s(203): returnMissingIterable() +#1 {main} +TypeError: Return value of returnMissingInt() must be of the type integer or null, none returned in %s:209 +Stack trace: +#0 %s(212): returnMissingInt() +#1 {main} diff --git a/Zend/tests/variadic/adding_additional_optional_parameter_error.phpt b/Zend/tests/variadic/adding_additional_optional_parameter_error.phpt index da96264609..4c6f36f10b 100644 --- a/Zend/tests/variadic/adding_additional_optional_parameter_error.phpt +++ b/Zend/tests/variadic/adding_additional_optional_parameter_error.phpt @@ -13,4 +13,4 @@ class MySQL implements DB { ?> --EXPECTF-- -Fatal error: Declaration of MySQL::query($query, int $extraParam = NULL, string ...$params) must be compatible with DB::query($query, string ...$params) in %s on line %d +Fatal error: Declaration of MySQL::query($query, ?int $extraParam = NULL, string ...$params) must be compatible with DB::query($query, string ...$params) in %s on line %d |
