From 4a1a5c8545fe64575be6800fdcde35f9c4af95c9 Mon Sep 17 00:00:00 2001 From: Riddhesh Sanghvi Date: Tue, 29 Sep 2026 14:16:22 +0530 Subject: [PATCH] fix(site): keep the fatal-error rollback working on PHP 8.5 On PHP 8.5 ReflectionMethod::setAccessible() is deprecated. Shutdown_Handler::cleanup() called it before shut_down_function() read error_get_last(), so the E_DEPRECATED (recorded even though error_reporting masks it) replaced the fatal error, the E_ERROR check never matched, and a site create that died with a fatal error left its webroot, containers, volumes, network, database, user and hosts entry behind. Call setAccessible() only before PHP 8.1, where it is still needed (it has no effect since 8.1), and read error_get_last() first in cleanup() and pass it to shut_down_function(), so no notice emitted later in the shutdown path can replace the fatal error. --- src/helper/Shutdown_Handler.php | 9 +++++++-- src/helper/class-ee-site.php | 8 ++++++-- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/src/helper/Shutdown_Handler.php b/src/helper/Shutdown_Handler.php index db032575..a0bb5ed3 100644 --- a/src/helper/Shutdown_Handler.php +++ b/src/helper/Shutdown_Handler.php @@ -13,9 +13,14 @@ class Shutdown_Handler { * @param array $site_command having Site_Command object. */ public function cleanup( $site_command ) { + // Read it first: any later notice, even a masked one, replaces the fatal in error_get_last(). + $error = error_get_last(); $reflector = new \ReflectionObject( $site_command[0] ); $method = $reflector->getMethod( 'shut_down_function' ); - $method->setAccessible( true ); - $method->invoke( $site_command[0] ); + // A no-op since PHP 8.1 and deprecated in 8.5. + if ( PHP_VERSION_ID < 80100 ) { + $method->setAccessible( true ); + } + $method->invoke( $site_command[0], $error ); } } diff --git a/src/helper/class-ee-site.php b/src/helper/class-ee-site.php index cd9f01de..cb4e4a8b 100644 --- a/src/helper/class-ee-site.php +++ b/src/helper/class-ee-site.php @@ -2395,11 +2395,15 @@ private function ngrok_curl( $get_url = true, $refresh = false ) { /** * Shutdown function to catch and rollback from fatal errors. + * + * @param array|null $error The error_get_last() result, read before anything else in the shutdown path. */ - protected function shut_down_function() { + protected function shut_down_function( $error = null ) { + if ( null === $error ) { + $error = error_get_last(); + } $logger = \EE::get_file_logger()->withName( 'site-command' ); - $error = error_get_last(); // Check if the $this->site_data is set and it is array and $this->site_data['site_url'] is set. if ( isset( $this->site_data ) && is_array( $this->site_data ) && isset( $this->site_data['site_url'] ) ) {