@@ -219,31 +219,43 @@ impl ClassBuilder {
219219
220220 zend_fastcall ! {
221221 extern fn constructor<T : RegisteredClass >( ex: & mut ExecuteData , _: & mut Zval ) {
222- let Some ( ConstructorMeta { constructor, .. } ) = T :: constructor( ) else {
223- PhpException :: default ( "You cannot instantiate this class from PHP." . into( ) )
224- . throw( )
225- . expect( "Failed to throw exception when constructing class" ) ;
226- return ;
227- } ;
228-
229- let this = match constructor( ex) {
230- ConstructorResult :: Ok ( this) => this,
231- ConstructorResult :: Exception ( e) => {
232- e. throw( )
222+ use crate :: zend:: try_catch;
223+ use std:: panic:: AssertUnwindSafe ;
224+
225+ // Wrap the constructor body with try_catch to ensure Rust destructors
226+ // are called if a bailout occurs (issue #537)
227+ let catch_result = try_catch( AssertUnwindSafe ( || {
228+ let Some ( ConstructorMeta { constructor, .. } ) = T :: constructor( ) else {
229+ PhpException :: default ( "You cannot instantiate this class from PHP." . into( ) )
230+ . throw( )
231+ . expect( "Failed to throw exception when constructing class" ) ;
232+ return ;
233+ } ;
234+
235+ let this = match constructor( ex) {
236+ ConstructorResult :: Ok ( this) => this,
237+ ConstructorResult :: Exception ( e) => {
238+ e. throw( )
239+ . expect( "Failed to throw exception while constructing class" ) ;
240+ return ;
241+ }
242+ ConstructorResult :: ArgError => return ,
243+ } ;
244+
245+ let Some ( this_obj) = ex. get_object:: <T >( ) else {
246+ PhpException :: default ( "Failed to retrieve reference to `this` object." . into( ) )
247+ . throw( )
233248 . expect( "Failed to throw exception while constructing class" ) ;
234249 return ;
235- }
236- ConstructorResult :: ArgError => return ,
237- } ;
238-
239- let Some ( this_obj) = ex. get_object:: <T >( ) else {
240- PhpException :: default ( "Failed to retrieve reference to `this` object." . into( ) )
241- . throw( )
242- . expect( "Failed to throw exception while constructing class" ) ;
243- return ;
244- } ;
245-
246- this_obj. initialize( this) ;
250+ } ;
251+
252+ this_obj. initialize( this) ;
253+ } ) ) ;
254+
255+ // If there was a bailout, re-trigger it after Rust cleanup
256+ if catch_result. is_err( ) {
257+ unsafe { crate :: zend:: bailout( ) ; }
258+ }
247259 }
248260 }
249261
0 commit comments