php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Request #75215 Show error if script exits while an exception was being thrown
Submitted: 2017-09-17 03:45 UTC Modified: 2017-09-18 15:24 UTC
From: bkfake-php at yahoo dot com Assigned:
Status: Open Package: Scripting Engine problem
PHP Version: 7.0.23 OS: OSX
Private report: No CVE-ID: None
 [2017-09-17 03:45 UTC] bkfake-php at yahoo dot com
Description:
------------
exception handler is never called!
it appears to me that the exception itself causes the destruction of the object.. which calls exit. this somehow bypasses the exception handler.
yet, shutdown function is called!

also note: error_get_last() inside the shutdown function returns null.. this is usually where you can catch fatal error (including the fatal error: "uncaught exception").
Here the exception was completely swallowed and never reported


PHP's OOP destructor documentation includes this brief  
"Calling exit() in a destructor will prevent the remaining shutdown routines from executing."

a)  shutdown function was called, which seems to contradict documentation
b)  no mention of of exception handler... which seems like it should have been called before the destruction of the objects!

same behavior in 5.6 and 7.0



Test script:
---------------
<?php

class Test
{
    public function myMethod()
    {
        echo __METHOD__.'<br />';
        echo 'throwing exception<br />';
        throw new Exception('hello world?');
    }

    public function __destruct()
    {
        echo __METHOD__.'<br />';
        exit;
    }
}

class Wrapper
{
    public function doIt()
    {
        $test = new Test();
        $test->myMethod();
    }

    public function __destruct()
    {
        echo __METHOD__.'<br />';
    }
}

register_shutdown_function(function () {
    echo 'shutdown function<br />';
    echo 'error_get_last: '.json_encode(error_get_last()).'<br />';
});

set_exception_handler(function ($e) {
    echo 'exception handler: '.$e->getMessage().'<br />';
});

echo 'Main<br />';

$wrapper = new Wrapper();
$wrapper->doIt();


Expected result:
----------------
exception handler should be called?!

output should include "exception handler: hello world?"

Actual result:
--------------
exception not caught.  exception "swallowed" and script exits sans error with http 200

Test script outputs
  Main
  Test::myMethod
  throwing exception
  Test::__destruct
  shutdown function
  error_get_last: null
  Wrapper::__destruct


Patches

Pull Requests

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2017-09-17 07:13 UTC] requinix@php.net
-Status: Open +Status: Not a bug
 [2017-09-17 07:13 UTC] requinix@php.net
This behavior makes sense to me. Quoting the docs,

"The destructor method will be called as soon as there are no other references to a particular object,"
When the exception is thrown the call stack begins unraveling: first myMethod, then doIt. But when doIt exits, there are no more references to $test so its destructor is called. That destructor exit()s, so normal execution flow ends and shutdown begins. The exception didn't make it to the top of the stack for it to be uncaught.

"Calling exit() in a destructor will prevent the remaining shutdown routines from executing."
As the sentence immediately before that says, this applies to when a destructor is invoked during shutdown. That is not the case here - it's the opposite, in fact.
 [2017-09-17 15:05 UTC] bkfake-php at yahoo dot com
> When the exception is thrown the call stack begins unraveling: first myMethod, then doIt. But when doIt exits, there are no more references to $test so its destructor is called. That destructor exit()s, so normal execution flow ends and shutdown begins. The exception didn't make it to the top of the stack for it to be uncaught.

I would think that when the exception is throws, it should first go up the call stack trying to catch the exception.   
Only after the exception is caught (or missed) should it "deravel" the stack and begin unreferencing the objects..

If that simply isn't possible, it seems that there should be a fatal error:  "uncaught exception"

Note:  I'm not the bonehead that put an exit in a destructor..  I'm the monkey that tried to find why the page was exiting without throwing any error or exception (as it appears).
 [2017-09-17 15:59 UTC] requinix@php.net
-Summary: set_exception_handler callable not called on exception +Summary: Show error if script exits while an exception was being thrown -Status: Not a bug +Status: Open -Type: Bug +Type: Feature/Change Request -Package: *General Issues +Package: Scripting Engine problem
 [2017-09-17 15:59 UTC] requinix@php.net
> If that simply isn't possible,
What you're asking for is a way to keep the call stack in place and execute code at a different layer. That's not really an option.

> it seems that there should be a fatal error
Are you asking for PHP to issue a warning or error if the script exits while an exception was being thrown? I think that's a valid request. Not sure how it can be addressed, though.
 [2017-09-18 15:24 UTC] bkfake-php at yahoo dot com
Thumbs Up ?
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Fri Dec 06 10:01:28 2024 UTC