PHP: Hypertext Preprocessor (original) (raw)

register_shutdown_function

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

register_shutdown_function — Register a function for execution on shutdown

Description

Multiple calls to register_shutdown_function() can be made, and each will be called in the same order as they were registered. If you call exit() within one registered shutdown function, processing will stop completely and no other registered shutdown functions will be called.

Shutdown functions may also call register_shutdown_function() themselves to add a shutdown function to the end of the queue.

Parameters

callback

The shutdown callback to register.

The shutdown callbacks are executed as the part of the request, so it's possible to send output from them and access output buffers.

args

It is possible to pass parameters to the shutdown function by passing additional parameters.

Return Values

No value is returned.

Examples

Example #1 register_shutdown_function() example

<?php function shutdown() { // This is our shutdown function, in // here we can do any last operations // before the script is complete.echo 'Script executed with success', PHP_EOL; }register_shutdown_function('shutdown'); ?>

Notes

Note:

The working directory of the script can change inside the shutdown function under some web servers, e.g. Apache.

Note:

Shutdown functions will not be executed if the process is killed with a SIGTERM or SIGKILL signal. While you cannot intercept a SIGKILL, you can use pcntl_signal() to install a handler for a SIGTERM which uses exit() to end cleanly.

Note:

Shutdown functions run separately from the time tracked bymax_execution_time. That means even if a process is terminated for running too long, shutdown functions will still be called. Additionally, if the max_execution_time runs out while a shutdown function is running it will not be terminated.

See Also

Found A Problem?

jules at sitepointAASASZZ dot com

21 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!

`

http://livejournal.com/~sinde1/

19 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)

emanueledelgrande ad email dot it

14 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:

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[]=this->callbacks[] = this>callbacks[]=callback; return true; } public function callRegisteredShutdown() { foreach ($this->callbacks as $arguments) { callback=arrayshift(callback = array_shift(callback=arrayshift(arguments); call_user_func_array($callback, $arguments); } } // test methods: public function dynamicTest() { echo '_REQUEST array is '.count($_REQUEST).' elements long.
'; } public static function staticTest() { echo '_SERVER array is '.count($_SERVER).' elements long.
'; } } ?>

A simple application:

"; }$scheduler = new shutdownScheduler();// schedule a global scope function: $scheduler->registerShutdownEvent('say', 'hello!');// try to schedule a dyamic method: scheduler−>registerShutdownEvent(array(scheduler->registerShutdownEvent(array(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!

`

pgl at yoyo dot org

15 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:

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.

`

ravenswd at gmail dot com

15 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.

RLK

16 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:

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); } } ?>

`

jawsper at aximax dot nl

15 years ago

`Something found out during testing:

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

`

alexyam at live dot com

13 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:

"; register_shutdown_function('shutdown'); exit; function shutdown(){ sleep(10); echo "Because exit() doesn't terminate php-fpm calls immediately.
"; } ?>

This doesn't:

"; fastcgi_finish_request(); sleep(10); echo "You can't see this form the browser."; ?>

`

dweingart at pobox dot com

19 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 .= '

  • ' . FUNCTION .'
  • ';
    return $buf;
    }

    function

    shutdown_func() {
    echo '

  • ' . FUNCTION .'
  • ';
    }ob_start('ob_callback');
    register_shutdown_function('shutdown_func');
    echo '

      ';
      ?>

      PHP 5.0.4:

      1. ob_callback
      2. shutdown_func

      PHP 5.1.2:

      1. shutdown_func
      2. ob_callback

      `

      Anonymous

      6 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)

      kenneth dot kalmer at gmail dot com

      19 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:

      mixed=time()."−mixed = time () . " - 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

      `

      sts at mail dot xubion dot hu

      21 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:

      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.`

      josh at joshstrange dot com

      1 year ago

      `> Shutdown functions run separately from the time tracked by max_execution_time. That means even if a process is terminated for running too long, shutdown functions will still be called. Additionally, if the max_execution_time runs out while a shutdown function is running it will not be terminated.

      This does not appear to be true in our testing, specifically "Additionally, if the max_execution_time runs out while a shutdown function is running it will not be terminated". For example:

      i<40;i < 40; i<40;i++) { echo "Run 1: $i\n"; while(1) { elapsed=time()−elapsed = time() - elapsed=time()start; if($elapsed > $i) { break; } } } });?>

      This will print out:

      Run 1: 0
      Run 1: 1
      Run 1: 2
      Run 1: 3
      Run 1: 4
      Run 1: 5

      Then it will die with:

      Execution took longer than 5 seconds, sent SIGTERM and terminated

      If you register multiple shutdown functions and an earlier one exceeds the execution time the later ones will not be run.

      If you need your shutdowns to have unlimited time (like the docs suggest it works) one solution might be to register a shutdown function like this early in your code:

      So that you give yourself unlimited time in your subsequent shutdown functions.

      See an example here: https://www.tehplayground.com/wJLtMi3Z5c1sTi9Y (Note, 5 seconds is the max you can set on this website. If you remove the first shutdown function you it will be killed after 3 seconds).

      `

      raat1979 at gmail dot com

      8 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.

      exitCode === null ? 0 : $this->exitCode); }); }); } } ?>

      `