PHP 8.1.6 Released!

register_shutdown_function

(PHP 4, PHP 5, PHP 7, PHP 8)

register_shutdown_functionRegistriert eine Funktion zur Ausführung beim Skript-Abschluss

Beschreibung

register_shutdown_function(callable $callback, mixed ...$args): ?bool

Registriert ein callback, welches ausgeführt werden soll, sobald die Ausführung des Skripts endet oder wenn exit() aufgerufen wird.

register_shutdown_function() kann mehrmals hintereinander aufgerufen werden, und die Funktionen werden in derselben Reihenfolge aufgerufen, wie sie registriert wurden. Wenn exit() innerhalb einer registrierten Shutdown-Funktion aufgerufen wird, bricht die Ausführung vollständig ab und keine weiteren registrierten Shutdown-Funktionen werden ausgeführt.

Shutdown-Funktionen können außerdem selbst register_shutdown_function() aufrufen, um eine Shutdown-Funktion am Ende der Warteschlange hinzuzufügen.

Parameter-Liste

callback

Das Shutdown-Callback, welches registriert werden soll.

Die Shutdown-Callbacks werden als Teil der Anfrage ausgeführt, d. h. es ist möglich, Ausgaben zu senden und auf Ausgabepuffer zuzugreifen.

args

Hier können zusätzliche Parameter an die Shutdown-Funktion übergeben werden.

Rückgabewerte

Es wird kein Wert zurückgegeben.

Fehler/Exceptions

Wenn das übergebene Callback nicht aufrufbar ist, wird ein Fehler der Stufe E_WARNING erzeugt.

Beispiele

Beispiel #1 register_shutdown_function()-Beispiel

<?php
function shutdown()
{
    
// Das ist unsere Shutdown-Funktion, in welcher
    // wir noch letzte Anweisungen ausführen können
    // bevor die Ausführung beendet wird.

    
echo 'Skript erfolgreich ausgeführt'PHP_EOL;
}

register_shutdown_function('shutdown');
?>

Anmerkungen

Hinweis:

Das Arbeitsverzeichnis des Skripts kann sich bei manchen Webservern, z. B. Apache, innerhalb des Shutdown-Callbacks ändern.

Hinweis:

Shutdown-Funktionen werden nicht ausgeführt, wenn der Prozess mit einem SIGTERM- oder SIGKILL-Signal terminiert wurde. Ein SIGKILL kann zwar nicht abgefangen werden, aber dafür kann mittels pcntl_signal() ein Handler für SIGTERM registriert werden, der exit() für einen sauberen Abbruch verwendet.

Hinweis:

Shutdown-Funktionen laufen getrennt von der Zeit, die von max_execution_time gemessen wird. Das bedeutet, dass die Shutdown-Funktionen auch dann noch aufgerufen werden, wenn ein Prozess beendet wird, weil er zu lange läuft. Außerdem wird eine laufende Shutdown-Funktion nicht beendet, wenn währenddessen die max_execution_time abläuft.

Siehe auch

add a note add a note

User Contributed Notes 13 notes

up
233
jules at sitepointAASASZZ dot com
18 years ago
If your script exceeds the maximum execution time, and terminates thusly:

Fatal error: Maximum execution time of 20 seconds exceeded in - on line 12

The registered shutdown functions will still be executed.

I figured it was important that this be made clear!
up
73
http://livejournal.com/~sinde1/
16 years ago
If you want to do something with files in function, that registered in register_shutdown_function(), use ABSOLUTE paths to files instead of relative. Because when script processing is complete current working directory chages to ServerRoot (see httpd.conf)
up
21
emanueledelgrande ad email dot it
11 years ago
A lot of useful services may be delegated to this useful trigger.
It is very effective because it is executed at the end of the script but before any object destruction, so all instantiations are still alive.

Here's a simple shutdown events manager class which allows to manage either functions or static/dynamic methods, with an indefinite number of arguments without using any reflection, availing on a internal handling through func_get_args() and call_user_func_array() specific functions:

<?php
// managing the shutdown callback events:
class shutdownScheduler {
    private
$callbacks; // array to store user callbacks
   
   
public function __construct() {
       
$this->callbacks = array();
       
register_shutdown_function(array($this, 'callRegisteredShutdown'));
    }
    public function
registerShutdownEvent() {
       
$callback = func_get_args();
       
        if (empty(
$callback)) {
           
trigger_error('No callback passed to '.__FUNCTION__.' method', E_USER_ERROR);
            return
false;
        }
        if (!
is_callable($callback[0])) {
           
trigger_error('Invalid callback passed to the '.__FUNCTION__.' method', E_USER_ERROR);
            return
false;
        }
       
$this->callbacks[] = $callback;
        return
true;
    }
    public function
callRegisteredShutdown() {
        foreach (
$this->callbacks as $arguments) {
           
$callback = array_shift($arguments);
           
call_user_func_array($callback, $arguments);
        }
    }
   
// test methods:
   
public function dynamicTest() {
        echo
'_REQUEST array is '.count($_REQUEST).' elements long.<br />';
    }
    public static function
staticTest() {
        echo
'_SERVER array is '.count($_SERVER).' elements long.<br />';
    }
}
?>

A simple application:

<?php
// a generic function
function say($a = 'a generic greeting', $b = '') {
    echo
"Saying {$a} {$b}<br />";
}

$scheduler = new shutdownScheduler();

// schedule a global scope function:
$scheduler->registerShutdownEvent('say', 'hello!');

// try to schedule a dyamic method:
$scheduler->registerShutdownEvent(array($scheduler, 'dynamicTest'));
// try with a static call:
$scheduler->registerShutdownEvent('scheduler::staticTest');

?>

It is easy to guess how to extend this example in a more complex context in which user defined functions and methods should be handled according to the priority depending on specific variables.

Hope it may help somebody.
Happy coding!
up
8
RLK
13 years ago
Contrary to the the note that "headers are always sent" and some of the comments below - You CAN use header() inside of a shutdown function as you would anywhere else; when headers_sent() is false. You can do custom fatal handling this way:

<?php
ini_set
('display_errors',0);
register_shutdown_function('shutdown');

$obj = new stdClass();
$obj->method();

function
shutdown()
{
  if(!
is_null($e = error_get_last()))
  {
   
header('content-type: text/plain');
    print
"this is not html:\n\n". print_r($e,true);
  }
}
?>
up
24
ravenswd at gmail dot com
12 years ago
You may get the idea to call debug_backtrace or debug_print_backtrace from inside a shutdown function, to trace where a fatal error occurred. Unfortunately, these functions will not work inside a shutdown function.
up
12
pgl at yoyo dot org
12 years ago
You definitely need to be careful about using relative paths in after the shutdown function has been called, but the current working directory doesn't (necessarily) get changed to the web server's ServerRoot - I've tested on two different servers and they both have their CWD changed to '/' (which isn't the ServerRoot).

This demonstrates the behaviour:

<?php
function echocwd() { echo 'cwd: ', getcwd(), "\n"; }

register_shutdown_function('echocwd');
echocwd() and exit;
?>

Outputs:

cwd: /path/to/my/site/docroot/test
cwd: /

NB: CLI scripts are unaffected, and keep their CWD as the directory the script was called from.
up
11
alexyam at live dot com
10 years ago
When using php-fpm, fastcgi_finish_request() should be used instead of register_shutdown_function() and exit()

For example, under nginx and php-fpm 5.3+, this will make browsers wait 10 seconds to show output:

<?php
   
echo "You have to wait 10 seconds to see this.<br>";
   
register_shutdown_function('shutdown');
    exit;
    function
shutdown(){
       
sleep(10);
        echo
"Because exit() doesn't terminate php-fpm calls immediately.<br>";
    }
?>

This doesn't:

<?php
   
echo "You can see this from the browser immediately.<br>";
   
fastcgi_finish_request();
   
sleep(10);
    echo
"You can't see this form the browser.";
?>
up
5
dweingart at pobox dot com
16 years ago
I have discovered a change in behavior from PHP 5.0.4 to PHP 5.1.2 when using a shutdown function in conjunction with an output buffering callback.

In PHP 5.0.4 (and earlier versions I believe) the shutdown function is called after the output buffering callback.

In PHP 5.1.2 (not sure when the change occurred) the shutdown function is called before the output buffering callback.

Test code:
<?php
function ob_callback($buf) {
   
$buf .= '<li>' . __FUNCTION__ .'</li>';
    return
$buf;
}

function
shutdown_func() {
    echo
'<li>' . __FUNCTION__ .'</li>';
}

ob_start('ob_callback');
register_shutdown_function('shutdown_func');
echo
'<ol>';
?>

PHP 5.0.4:

1. ob_callback
2. shutdown_func

PHP 5.1.2:

1. shutdown_func
2. ob_callback
up
3
sts at mail dot xubion dot hu
18 years ago
If you need the old (<4.1) behavior of register_shutdown_function you can achieve the same with "Connection: close" and "Content-Length: xxxx" headers if you know the exact size of the sent data (which can be easily caught with output buffering).
An example:
<?php
header
("Connection: close");
ob_start();
phpinfo();
$size=ob_get_length();
header("Content-Length: $size");
ob_end_flush();
flush();
sleep(13);
error_log("do something in the background");
?>

The same will work with registered functions.
According to http spec, browsers should close the connection when they got the amount of data specified in Content-Length header. At least it works fine for me in IE6 and Opera7.
up
1
kenneth dot kalmer at gmail dot com
16 years ago
I performed two tests on the register_shutdown_function() to see under what conditions it was called, and if a can call a static method from a class. Here are the results:

<?php
/**
* Tests the shutdown function being able to call a static methods
*/
class Shutdown
{
    public static function
Method ($mixed = 0)
    {
       
// we need absolute
       
$ap = dirname (__FILE__);
       
$mixed = time () . " - $mixed\n";
       
file_put_contents ("$ap/shutdown.log", $mixed, FILE_APPEND);
    }
}
// 3. Throw an exception
register_shutdown_function (array ('Shutdown', 'Method'), 'throw');
throw new
Exception ('bla bla');

// 2. Use the exit command
//register_shutdown_function (array ('Shutdown', 'Method'), 'exit');
//exit ('exiting here...')

// 1. Exit normally
//register_shutdown_function (array ('Shutdown', 'Method'));
?>

To test simply leave one of the three test lines uncommented and execute. Executing bottom-up yielded:

1138382480 - 0
1138382503 - exit
1138382564 - throw

HTH
up
-1
Anonymous
3 years ago
warning: in addition to SIGTERM and SIGKILL, the shutdown functions won't run in response to SIGINT either. (observed on php 7.1.16 on windows 7 SP1 x64 + cygwin  and php 7.2.15 on Ubuntu 18.04)
up
1
raat1979 at gmail dot com
5 years ago
I wanted to set the exit code for a CLI application from a shutdown function by using a class property,

Unfortunataly (as per manual)  "If you call exit() within one registered shutdown function, processing will stop completely and no other registered shutdown functions will be called." 

As a result if I call exit in my shutdown function I will break other shutdown functions (like one that logs fatal errors to syslog) 

However! (as per manual)  "Multiple calls to register_shutdown_function() can be made, and each will be called in the same order as they were registered."

As luck would have it you are also able to register a shutdown function from within a shutdown function (at least in PHP 7.0.15 and 5.6.30)

in other words if you register a shutdown function inside a shutdown function it is appended to the shutdown function queue.

<?php
class SomeApplication{
    private
$exitCode = null;
       
    public function
__construct(){
       
register_shutdown_function(function(){
        echo
"some registered shutdown function";
           
register_shutdown_function(function(){
                echo
"last registered shutdown function";
               
// one might even consider another register shutdown_function if one expects other shutdown functions to do the same... 
               
exit($this->exitCode === null ? 0 : $this->exitCode);
            });
        });
    }
}
?>
up
0
jawsper at aximax dot nl
12 years ago
Something found out during testing:

the ini auto_append_file will be included BEFORE the registered function(s) will be called.
To Top