Print PHP running call stack from outside the PHP

2019-05-21 09:22发布

问题:

Is there any runtime stack trace feature in PHP, by a given PID of it? (For whom also write Java, I mean jstack.)

I got few PHP background process that they are freeze once a while on some unknown lines. I can simply kill them all and restart but that don't prevent it happen again.

Is there a API able to spy the stack and tell? like the jstack utility provided from JDK?

回答1:

You have a few options in terms of debugging unknown errors.

  • The first method is easy, but requires a PHP extension to be installed.
  • The second method offers a more difficult hands-on approach, but is definitely worth it if you're into the low-level inner-workings of the PHP interpreter. Also, this will require linux and PHP to be configured with --enable-debug.
  • The third and, in my personal opinion the easiest, method doesn't require the use of any external programs or added PHP extensions.

  1. Xdebug

    • This is a PHP extension you can install and have available for any site/page.
    • A quick-list of features from the website:
      • Automatic stack trace upon error
      • Function call logging
      • Display features such as enhanced var_dump() output and code coverage information.
    • If you see yourself needing to debug your scripts a lot, this one might be the best option. The prettier-display of errors is also a good thumbs-up in my book.

  2. Use gdb to run the file that crashes and analyze the backtrace.

    • This is an intermediate-to-advanced approach that requires PHP to be configured with --enable-debug, a linux machine running Apache, and a strong desire/ability to understand the way software works on a lower-level.
    • Run gdb with Apache:
      gdb /usr/lib/httpd
    • Then, you have two options.:
      • Run apache as a server and load the file through a browser, as normal:
        (gdb) run -X
        ... now, in your browser - access the page that crashes as normal and switch back to gdb: (gdb) backtrace
        ... the full backtrace will be printed
      • Or, use gdb to run the script itself:
        (gdb) run /path/to/the/script.php
        (gdb) backtrace
        ... the full backtrace will be printed
    • For more gdb info, check out the quick-reference guide.

  3. Create a custom error handler that prints the stack trace when an error is thrown.

    • To be sure to catch all errors, you can catch Errors, Exceptions, and PHP's Shutdown events.
    • To debug a single page, it's as simple as creating a function to handle the error and then pasting that function into the top of the page you're having issues on. One step further, I have an "error handling" class that's in a separate file and just include it whenever needed (simplified-version below). You can tweak each method to suit your display needs, or even handle errors on a per-error-number basis!
    • Then, to use this, just add require('ErrorHandler.php'); to the top of your page and it should auto-register itself to handle any errors. Be sure to update the include-path to point to the actual file, of course.

ErrorHandler.php:

<?php
class ErrorHandler {
    public static function captureError($err_no, $message, $file, $line) {
        echo '<strong>Error (#' . $err_no . '):</strong> ' . $message . ' in ' . $file . ' on line #' . $line . '<br />';
        debug_print_backtrace();
    }

    public static function captureException($exception) {
        echo '<pre>' . print_r($exception, true) . '</pre>';
    }

    public static function captureShutdown() {
        if (($error = error_get_last()) !== null) {
            debug_print_backtrace();
        }
    }
}
set_error_handler(array('ErrorHandler', 'captureError'));
set_exception_handler(array('ErrorHandler', 'captureException'));
register_shutdown_function(array('ErrorHandler', 'captureShutdown'));
?>