Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions UPGRADING
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,19 @@ PHP 8.6 UPGRADE NOTES
. It is no longer possible to clone variant objects, this is because
the cloning behaviour was ill defined.

- Core:
. Object destructors (__destruct) now run at the next VM safepoint (a
function call, loop back-edge, try-region boundary, or script end) rather
than synchronously when an object's last reference is released. Logical
death stays synchronous: a WeakReference reads null and a WeakMap entry is
gone as soon as the reference drops. Code that assumed a destructor ran
before the next statement in the same scope may observe its side effects
slightly later, and a destructor's stack trace now shows [internal
function] for the frame that triggered it instead of the releasing line.
An exception thrown from a destructor is raised at the safepoint and
remains catchable by the try/catch that was active when the object was
released.

- DOM:
. Properties previously documented as @readonly (e.g. DOMNode::$nodeType,
DOMDocument::$xmlEncoding, DOMEntity::$actualEncoding, ::$encoding,
Expand Down
3 changes: 2 additions & 1 deletion Zend/tests/ArrayAccess/bug41209.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -42,5 +42,6 @@ echo "Done\n";
Fatal error: Uncaught ErrorException: Undefined variable $id in %s:%d
Stack trace:
#0 %s(%d): env::errorHandler(2, 'Undefined varia...', '%s', %d)
#1 {main}
#1 %s(%d): cache->offsetExists(NULL)
#2 {main}
thrown in %s on line %d
1 change: 1 addition & 0 deletions Zend/tests/bitwise_not_precision_exception.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,5 @@ try {
}
?>
--EXPECT--
int(-1)
The float INF is not representable as an int, cast occurred
2 changes: 1 addition & 1 deletion Zend/tests/bug38220.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ A Object
)
func1(): 1
after call func1
before call func1
A::__destruct()
before call close
A Object
Expand All @@ -75,7 +76,6 @@ A Object
)
close(): 1
after call close
before call func1
A Object
(
[i] => 2
Expand Down
8 changes: 5 additions & 3 deletions Zend/tests/bug63206.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,10 @@ set_error_handler(function() {
$triggerNotice1++;
$triggerNotice2++;
?>
--EXPECT--
--EXPECTF--
Second handler
Internal handler

Warning: Undefined variable $triggerInternalNotice in %s on line %d
Second handler
Internal handler

Warning: Undefined variable $triggerInternalNotice in %s on line %d
2 changes: 1 addition & 1 deletion Zend/tests/bug70662.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,5 @@ var_dump($a);
--EXPECT--
array(1) {
["b"]=>
int(2)
int(1)
}
25 changes: 19 additions & 6 deletions Zend/tests/bug70785.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,32 @@ set_error_handler(function($no, $msg) {
throw new Exception($msg);
});

try {
function smart_branch() {
if ($a === null) { // ZEND_VM_SMART_BRANCH
undefined_function('Null');
return 'branch';
}
} catch (Exception $e) {
return 'no branch';
}

try {
function next_opcode() {
$c === 3; // ZEND_VM_NEXT_OPCODE
undefined_function();
return 'done';
}

try {
smart_branch();
} catch (Exception $e) {
echo $e->getMessage(), PHP_EOL;
}

try {
next_opcode();
} catch (Exception $e) {
echo $e->getMessage(), PHP_EOL;
}
echo "okey\n";
?>
okey
--EXPECT--
Undefined variable $a
Undefined variable $c
okey
11 changes: 6 additions & 5 deletions Zend/tests/bug72101.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -79,9 +79,10 @@ $foo->bar($a, $b, $c);
Fatal error: Uncaught Error: Class "DoesNotExists" not found in %s:%d
Stack trace:
#0 %s(%d): {closure:%s:%d}(2, 'MethodCallbackB...', '%s', 8)
#1 %sbug72101.php(%d): PHPUnit_Framework_MockObject_Stub_ReturnCallback->invoke(Object(PHPUnit_Framework_MockObject_Invocation_Static))
#2 %sbug72101.php(%d): PHPUnit_Framework_MockObject_Matcher->invoked(Object(PHPUnit_Framework_MockObject_Invocation_Static))
#3 %sbug72101.php(%d): PHPUnit_Framework_MockObject_InvocationMocker->invoke(Object(PHPUnit_Framework_MockObject_Invocation_Static))
#4 %sbug72101.php(%d): Mock_MethodCallbackByReference_7b180d26->bar(0, 0, 0)
#5 {main}
#1 %sbug72101.php(%d): MethodCallbackByReference->callback(0, 0, 0)
#2 %sbug72101.php(%d): PHPUnit_Framework_MockObject_Stub_ReturnCallback->invoke(Object(PHPUnit_Framework_MockObject_Invocation_Static))
#3 %sbug72101.php(%d): PHPUnit_Framework_MockObject_Matcher->invoked(Object(PHPUnit_Framework_MockObject_Invocation_Static))
#4 %sbug72101.php(%d): PHPUnit_Framework_MockObject_InvocationMocker->invoke(Object(PHPUnit_Framework_MockObject_Invocation_Static))
#5 %sbug72101.php(%d): Mock_MethodCallbackByReference_7b180d26->bar(0, 0, 0)
#6 {main}
thrown in %sbug72101.php on line %d
8 changes: 6 additions & 2 deletions Zend/tests/bug76534.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,12 @@ $x = "foo";
$y = &$x["2bar"];
?>
--EXPECTF--
Fatal error: Uncaught Exception: Illegal string offset "2bar" in %s:%d
Fatal error: Uncaught Error: Cannot create references to/from string offsets in %s:%d
Stack trace:
#0 {main}

Next Exception: Illegal string offset "2bar" in %s:%d
Stack trace:
#0 %s(%d): {closure:%s:%d}(2, 'Illegal string ...', '%s', 7)
#1 {main}
thrown in %sbug76534.php on line %d
thrown in %s on line %d
32 changes: 28 additions & 4 deletions Zend/tests/bug78598.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,31 @@ var_dump($my_var);

?>
--EXPECT--
int(0)
int(0)
int(0)
int(0)
array(1) {
[0]=>
string(3) "xyz"
}
array(1) {
[0]=>
array(1) {
[0]=>
array(1) {
[0]=>
string(3) "xyz"
}
}
}
array(1) {
["foo"]=>
string(3) "xyz"
}
array(1) {
["foo"]=>
array(1) {
["bar"]=>
array(1) {
["baz"]=>
string(3) "xyz"
}
}
}
18 changes: 15 additions & 3 deletions Zend/tests/bug79784.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,18 @@ var_dump($a);

?>
--EXPECT--
NULL
NULL
NULL
array(1) {
[""]=>
string(1) "x"
}
array(1) {
[""]=>
string(1) "x"
}
array(1) {
[""]=>
array(1) {
[""]=>
string(1) "x"
}
}
4 changes: 2 additions & 2 deletions Zend/tests/bug79793.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,15 @@ var_dump($ary);

?>
--EXPECT--
Undefined array key "foobar"
array(1) {
["foobar"]=>
int(1)
}
Undefined array key "foobarbaz"
Undefined array key "foobar"
array(2) {
["foobar"]=>
int(1)
["foobarbaz"]=>
int(1)
}
Undefined array key "foobarbaz"
2 changes: 1 addition & 1 deletion Zend/tests/closures/closure_031.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,5 @@ try {
}
?>
--EXPECT--
Warning: Undefined property: Closure::$a
NULL
Warning: Undefined property: Closure::$a
11 changes: 6 additions & 5 deletions Zend/tests/compound_assign_failure.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,16 @@ try {

set_error_handler(function($type, $msg) { throw new Exception($msg); });

function concat(&$a, $b) { $a .= $b; }

try {
$a = [];
$a .= "foo";
concat($a, "foo");
} catch (Throwable $e) { var_dump($a); }

try {
$a = "foo";
$a .= [];
concat($a, []);
} catch (Throwable $e) { var_dump($a); }

$x = new stdClass;
Expand Down Expand Up @@ -202,9 +204,8 @@ var_dump($x);
int(1)
int(1)
int(1)
array(0) {
}
string(3) "foo"
string(8) "Arrayfoo"
string(8) "fooArray"
object(stdClass)#%d (0) {
}
int(1)
Expand Down
4 changes: 2 additions & 2 deletions Zend/tests/concat/bug81705.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,5 @@ $my_var .= $GLOBALS["arr"];
var_dump($my_var);
?>
--EXPECT--
error
string(6) "aArray"
string(6) "aArray"
error
57 changes: 57 additions & 0 deletions Zend/tests/dtor_defer/catch_on_early_exit.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
--TEST--
Deferred destructor: a throwing destructor dropped in a try is caught by that try when the try is left via return/break/continue
--FILE--
<?php
class D {
public function __construct(public string $id) {}
public function __destruct() { throw new Exception("dtor {$this->id}"); }
}

function via_return() {
try {
$d = new D("r");
unset($d);
return "returned";
} catch (Exception $e) {
echo "return-case caught: {$e->getMessage()}\n";
return "caught";
}
}
var_dump(via_return());

function via_break() {
foreach ([1] as $v) {
try {
$d = new D("b");
unset($d);
break;
} catch (Exception $e) {
echo "break-case caught: {$e->getMessage()}\n";
}
}
return "done";
}
var_dump(via_break());

function via_continue() {
foreach ([1, 2] as $v) {
try {
$d = new D("c$v");
unset($d);
continue;
} catch (Exception $e) {
echo "continue-case caught: {$e->getMessage()}\n";
}
}
return "done";
}
var_dump(via_continue());
?>
--EXPECT--
return-case caught: dtor r
string(6) "caught"
break-case caught: dtor b
string(4) "done"
continue-case caught: dtor c1
continue-case caught: dtor c2
string(4) "done"
36 changes: 36 additions & 0 deletions Zend/tests/dtor_defer/exit_wins_over_throwing_dtor.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
--TEST--
Deferred destructor: exit() in a destructor wins over a throwing destructor in the same flush, either order
--FILE--
<?php
class Exiter {
function __destruct() {
echo "Exiter dtor\n";
exit(7);
}
}
class Thrower {
public $id;
function __construct(int $id) { $this->id = $id; }
function __destruct() {
echo "Thrower {$this->id} dtor\n";
throw new Exception("thrown {$this->id}");
}
}

register_shutdown_function(function () { echo "shutdown\n"; });

// Thrower deferred before Exiter, then Exiter: exit must win over the pending throw.
$t = new Thrower(1);
$t = null;
$e = new Exiter();
$e = null;

// A safepoint flushes the batch. exit(7) wins; no user code runs afterwards.
(function () {})();

echo "UNREACHABLE\n";
?>
--EXPECT--
Thrower 1 dtor
Exiter dtor
shutdown
32 changes: 32 additions & 0 deletions Zend/tests/dtor_defer/finally_body_dtor_composition.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
--TEST--
Deferred destructor: a destructor dropped in a finally body composes with a destructor exception pending from the protected block and is caught by the enclosing try
--FILE--
<?php
class D {
public function __construct(public string $id) {}
public function __destruct() { throw new Exception("dtor {$this->id}"); }
}
function f() {
try {
try {
$a = new D("try");
unset($a);
return "unreached";
} finally {
$b = new D("finally");
unset($b);
echo "finally body ran\n";
}
} catch (Exception $e) {
echo $e::class, ": ", $e->getMessage(), "\n";
echo "previous: ", $e->getPrevious()?->getMessage() ?? "none", "\n";
return "caught";
}
}
var_dump(f());
?>
--EXPECT--
finally body ran
Exception: dtor finally
previous: dtor try
string(6) "caught"
Loading
Loading