当前位置: 首页 > 工具软件 > PHP Insights > 使用案例 >

php die_PHP错误处理:再也不必说die()

唐裕
2023-12-01

php die

Introduction

介绍

This article is intended for those who are new to PHP error handling.  It addresses one of the most common problems that plague beginning PHP developers: effective error visualization.

本文适用于PHP错误处理新手 。 它解决了困扰新手PHP开发人员的最常见问题之一:有效的错误可视化。

PHP error handling is well-documented in the online man pages, but the documentation often eludes beginners, who are trying to learn PHP by copying examples they found on the internet.  Copying the code without understanding the code is an PHP错误处理在联机手册页中有详尽的文档介绍,但是该文档通常使初学者难以理解,他们试图通过复制在Internet上找到的示例来学习PHP。 在不了解代码的情况下复制代码是一种 antipractice, and there are so many bad PHP examples out there, it can sometimes be difficult to find good ones!  This article will help you get the most, quickly and easily, out of PHP's basic error handlers.  You can get excellent error information, informative and well-targeted, by just following a few simple examples.  So stop copying those obsolete internet examples, and instead make a few "teaching examples" for your own library.  By the time you've finished this article, you will have some great insights into how to diagnose the most common errors quickly and find good solutions. 反实践 ,并且那里有很多不好PHP示例,有时很难找到好的示例! 本文将帮助您快速,轻松地利用PHP的基本错误处理程序。 通过遵循一些简单的示例,您可以获得出色的错误信息,内容丰富且针对性强。 因此,请停止复制那些过时的Internet示例,而为您自己的库制作一些“教学示例”。 在完成本文时,您将对如何快速诊断最常见的错误以及找到好的解决方案有深刻的了解。

What's Covered Here

这里涵盖了什么

PHP has unlimited opportunities for errors, but in practice only a few things are needed to get good diagnostics.  You need to be able to see the errors in PHP and you need to be able to see the errors in the PHP extensions, like MySQLi.  These require some PHP settings, and a little bit of code to call out the errors in the extensions.  This article will show how to get PHP to report the errors and how to get the extensions to report their errors, too.

PHP具有无限的出错机会,但实际上,只需几件事即可获得良好的诊断信息。 您需要能够查看PHP中的错误,并且需要能够看到PHP扩展(例如MySQLi)中的错误。 这些需要一些PHP设置,以及一些代码来指出扩展中的错误。 本文将展示如何使PHP报告错误,以及如何使扩展报告错误。

PHP Won't Help You if You Won't Help Yourself!

如果您不自助,PHP不会帮助您!

PHP has a long history of trying to be "easy to use."  One of the early strategies for ease of use was, some might say, a bit misguided.  That early strategy was to produce as little error information as possible.  Many error conditions produced nothing more than a Notice-level message.  But the Notice-level messages were suppressed in the standard PHP installation.

PHP长期以来一直试图变得“易于使用”。 某些人可能会说,易于使用的早期策略之一是被误导了。 早期的策略是产生尽可能少的错误信息。 许多错误情况只产生

This had the unfortunate effect of letting PHP scripts fail silently at run time, or fail silently and intermittently when the script relied on an undefined variable, a condition that could occur because of a typographical error.  Today we know better, and many of those early silent failures are accompanied by warnings.  But not all of them are warned.  You have to tell PHP that you want to know about the errors.  You do that with error_reporting() and a few associated settings.

不幸的是,使PHP脚本在运行时静默失败,或者在脚本依赖未定义变量时静默或间歇性失败,这种情况可能是由于印刷错误所致。 今天,我们更加了解了,许多早期的无声故障都伴随着警告。 但并非所有人都得到警告。 您必须告诉PHP您想知道有关错误的信息。 您可以使用error_reporting()和一些关联的设置来实现。

Settings for Development and Deployment

开发和部署设置

For most PHP applications you want these settings in the development environment.  We are telling PHP to report all the errors, write them into the error_log file, and display them in the browser viewport.

对于大多数PHP应用程序,您需要在开发环境中进行这些设置。 我们告诉PHP报告所有错误,将它们写入error_log文件,并在浏览器视口中显示它们。

<?php
error_reporting(E_ALL);
ini_set('log_errors', TRUE);
ini_set('error_log', 'error_log');
ini_set('display_errors', TRUE);

For most PHP applications you want these settings in the deployed (production) environment

对于大多数PHP应用程序,您需要在已部署(生产)环境中进行这些设置

<?php
error_reporting(E_ALL);
ini_set('log_errors', TRUE);
ini_set('error_log', 'error_log');
ini_set('display_errors', FALSE);

See the difference?  The deployed environment does not display the errors, but it still logs them.

看到不同? 部署的环境不会显示错误,但仍会记录错误。

What happens when there is an error in the deployed application?  You will probably get the "white screen of death,"

部署的应用程序中出现错误时会发生什么? 您可能会得到“死亡白屏”,

depending on the exact location of the error.  But no matter what appears in the browser viewport, you will still get the error_log information, so you can investigate the error after the fact.

取决于错误的确切位置。 但是,无论浏览器视口中出现什么内容,您仍然会获得error_log信息,因此您可以在事后调查错误。

Error Suppression: A Symptom of Bad Error Handling

错误抑制:错误处理错误的征兆

Perhaps you have seen something like this in a PHP code sample.

也许您已经在PHP代码示例中看到了类似的内容。

<?php
@mysql_query( ... );

To the trained eye, that is scary.  See the @ ("at-sign") prepended to the function name?  It's the error suppression operator.  And it's like dog poop.  It is out of place wherever you find it.  Here is what one PHP veteran says on the PHP web site. 

对训练有素的人来说,这是@ (“ at-sign”)吗? 它是错误抑制运算符 。 这就像狗屎。 无论您在哪里找到它,它都是不合适的。 这是一位PHP老手在PHP网站上所说的。

Error suppression should be avoided if possible as it doesn't just suppress the error that you are trying to stop, but will also suppress errors that you didn't predict would ever occur. This will make debugging a nightmare.

如果可能,应该避免错误抑制,因为它不仅会抑制您试图停止的错误,而且还会抑制您没有预料到的错误。 这将使调试成为一场噩梦。

If you ever find the @ operator in a sample of PHP code, expect to find a prominent explanation in the associated comments.  And if you don't find that explanation, you might want to skip over the example.  It's likely that the example came from a novice programmer.  There may be other errors lurking in the code, too.

如果您在PHP代码示例中找到@运算符,则希望在相关注释中找到醒目的解释。 而且,如果找不到该说明,则可能要跳过该示例。 该示例可能来自新手程序员。 代码中还可能存在其他错误。

Obscure Error Messages: Another Symptom of Bad Error Handling

模糊的错误消息:错误处理错误的另一种症状

Poor error handling is a code smell that can be fairly obvious to the trained eye.  It is a code smell because it can leave you frustrated as you see your script fail in a way that tells you nothing about the cause or remedy.  One common symptom of inadequate error handling may be the white screen of death.  Another common symptom is a meaningless message like "Query failed" or "Cannot connect."  These are problematic conditions because they don't tell you anything about what went wrong or where it went wrong.  Debugging a script without any meaningful message is like poking about in a dark room - you might hit something, but it's hard to know what's in there.

错误的错误处理是一种代码臭味 ,对于受过训练的眼睛来说可能是相当明显的。 这是一种代码味道,因为它会使您感到沮丧,因为您看到脚本失败时,不会以任何方式告诉您原因或补救措施。 错误处理不足的一种常见症状可能是死亡白屏。 另一个常见症状是无意义的消息,例如“查询失败”或“无法连接”。 这些都是有问题的情况,因为它们不会告诉您任何错误或错误发生的地方。 在没有任何有意义的消息的情况下调试脚本就像在黑暗的房间里闲逛一样-您可能会碰到一些东西,但是很难知道其中有什么。

On the other hand, good error handling is like turning on the lights.

另一方面,良好的错误处理就像打开灯。

The first and most common mistake is using die().  PHP die() is functionally equivalent to exit(), but die() is seen more frequently in PHP code examples.  It terminates the script, and optionally produces a message of the user's choice.  Here is an example that produces a nearly meaningless error message and terminates the script.

第一个也是最常见的错误是使用die() 。 PHP die()在功能上等效于exit() ,但是die()在PHP代码示例中更常见。 它终止脚本,并有选择地生成用户选择的消息。 这是一个产生几乎没有意义的错误消息并终止脚本的示例。

<?php
$link = mysqli_connect($db_host, $db_user, $db_word, $db_name) or die('Cannot connect to database');

Here is another example that shows the same poor strategy.

这是另一个显示相同策略的示例。

<?php
$result = mysqli_query($link, 'SELECT * FROM myTable') or die('Query failed');

These examples illustrate bad error handling because

这些示例说明了错误的错误处理,因为

1. They terminate the script, even when it may not be necessary;

1.即使脚本可能没有必要,它们也会终止脚本;

2. They give no indication of where the failure occurred;

2.他们没有指出发生故障的位置;

3. They give no indication of why the failure occurred.

3.他们没有说明失败发生的原因。

A Quick Upgrade to Better Error Handling

快速升级到更好的错误处理

What's a better solution than die()?  It's trigger_error().

有什么比die()更好的解决方案? 这是trigger_error()

When trigger_error() is used with appropriate diagnostic functions, you can get much better information without even trying

当trigger_error()与适当的诊断功能一起使用时,您甚至无需尝试就可以获得更好的信息。

1. You don't have to terminate the script unless you want to;

1.除非您愿意,否则不必终止脚本;

2. You automatically get the path information and line numbers showing where the error occurred;

2.您将自动获得显示错误发生位置的路径信息和行号;

3. You automatically get an indication of why the failure occurred.

3.您会自动获得故障发生原因的指示。

Now that you know about trigger_error() what should you do?  Scan your code library for every instance of a call to exit() or die() and make yourself a project to change these to trigger_error() in each and every case that trigger_error() can possibly be used!  Some good examples follow.

既然您知道了trigger_error(),该怎么办? 扫描代码库,以查找对exit()或die()的每个调用实例,并使自己成为一个项目,以便在每种可能使用trigger_error()的情况下将其更改为trigger_error()! 以下是一些很好的例子。

Digging Deeper - Getting Meaningful Help from PHP Extensions

深入探讨-从PHP扩展中获得有意义的帮助

Almost all PHP functions return some value, and smart programmers know to test these return values.  However many of the outdated examples on the internet do not test the return values, but instead blindly use the results, often with potentially disastrous consequences.  A particularly common example seems to arise when using the MySQL database extensions. (Note: the MySQL extension has been removed from PHP, but the terrible code examples still litter the internet!)

几乎所有PHP函数都返回一些值,而精明的程序员知道可以测试这些返回值。 但是,Internet上许多过时的示例并未测试返回值,而是盲目使用结果,通常会带来潜在的灾难性后果。 使用MySQL数据库扩展时,似乎会出现一个特别常见的示例。 (注意: MySQL扩展已从PHP中删除 ,但是可怕的代码示例仍然乱丢了互联网!)

When you upgrade from MySQL to MySQLi, you've got a great opportunity to upgrade your error handling.  Here's that earlier connect example with improved error handling:

从MySQL升级到MySQL

<?php
$link = mysqli_connect($db_host, $db_user, $db_word, $db_name);
if (!$link)
{
    $err
    = 'MySQLi Error: '
    . mysqli_connect_errno()
    . ' '
    . mysqli_connect_error()
    ;
    trigger_error($err, E_USER_ERROR);
}

When a connect failure occurs you will get a message something like this:

发生连接失败时,您将收到以下消息:

Fatal error: MySQLi Error: 1045 Access denied for user ''@'localhost' (using password: NO) in /path/to/script.php on line ...

致命错误:MySQLi错误:1045在行/path/to/script.php中对用户``@'localhost'(使用密码:NO)的访问被拒绝...

MySQL Error: 1045 Access denied for user, and you will links to a variety of helpful resources! 有用的资源

If you wanted to get a little fancy, you could even set up the Google search in advance!

如果您想花点时间,甚至可以提前设置Google搜索!

<?php
$link = mysqli_connect($db_host, $db_user, $db_word, $db_name);
if (!$link)
{
    $msg
    = 'MySQLI Error: '
    . mysqli_connect_errno()
    . ' '
    . mysqli_connect_error()
    ;
    $err
    = '<a target="_blank" href="https://www.google.com/#q='
    . urlencode($msg)
    . '">'
    . htmlentities($msg)
    . '</a>'
    ;
    trigger_error($err, E_USER_ERROR);
}

You will see the same message as before, but it will come primed with a clickable link to the helpful resources.

您将看到与以前相同的消息,但是将带有指向可帮助资源的可单击链接,以进行填充。

How about the queries?  You can use the same strategy, but you need to call different error functions.

查询怎么样? 您可以使用相同的策略,但是需要调用不同的错误函数。

<?php
$sql = 'SELECT Error';
$result = mysqli_query($link, $sql);
if (!$result)
{
    $msg
    = 'MySQLI Error: '
    . mysqli_errno($link)
    . ' '
    . mysqli_error($link)
    ;
    $err
    = '<a target="_blank" href="https://www.google.com/#q='
    . urlencode($msg)
    . '">'
    . htmlentities($msg)
    . '</a>'
    . " SQL: $sql"
    ;
    trigger_error($err, E_USER_ERROR);
}

A Bonus: Trigger_Error() is Extensible!

奖励:Trigger_Error()是可扩展的!

All by itself, trigger_error() is a great improvement over die(), but that's not all.  Trigger_error() can be used in conjunction with the built-in error handler, or with a user defined function that has been set as the new error handler.  It's beyond the scope of this article, but you might want to read about set_error_handler() if you want more advanced functionality.  There is also ErrorException, but I have not personally found a good use for it yet.

就其本身而言,trigger_error()是对die()的一项重大改进,但这还不是全部。 Trigger_error()可以与内置错误处理程序一起使用,也可以与已设置为新错误处理程序的用户定义函数一起使用。 这超出了本文的范围,但是如果您想要更多高级功能,则可能需要阅读有关set_error_handler()的信息 。 还有ErrorException ,但是我个人还没有找到很好的用途。

Finding and Reading the Error Logs

查找和读取错误日志

Whether your application is in development or already deployed, the error_log file is a valuable resource.  In my PHP installation, the error_log file is only created if an error has occurred.  It may be appended to, if there are successive errors.  Going through a lot of server directories to look for error_log can be a laborious task, but we can automate it.  I use a script like this one to walk through the web directory tree.  It finds and displays the error_log files and gives me a push-button link to remove the error_log.

无论您的应用程序是开发中的还是已经部署的,error_log文件都是宝贵的资源。 在我PHP安装中,仅在发生错误时才创建error_log文件。 如果存在连续错误,可以将其附加。 遍历许多服务器目录以查找error_log可能是一项艰巨的任务,但我们可以使其自动化。 我使用这样的脚本浏览Web目录树。 它查找并显示error_log文件,并提供了一个按钮链接来删除error_log。

<?php // /find_error_log.php
/**
 * Put this script in the web root or other top-level directory
 *
 * Traverse this directory and all directories of the web tree
 * Show and optionally delete the error log files
 *
 * http://php.net/manual/en/class.recursivedirectoryiterator.php#85805
 */
ob_start();
error_reporting( E_ALL );
ini_set( 'display_errors', TRUE );
ini_set( 'log_errors',     TRUE );


// START IN THE CURRENT DIRECTORY
$path = realpath(getcwd());
$plen = strlen($path);

// THE ERROR LOG FILE NAME - REVERSED BECAUSE IT IS AT THE END OF THE PATH STRING
$error_log = ini_get('error_log');
$error_log = basename($error_log);
$error_log = strrev($error_log);

// IF THERE IS A POST-METHOD REQUEST TO DELETE THIS ERROR LOG
if (!empty($_POST['error_log']))
{
    // MAKE SURE WE ONLY UNLINK THE ERROR LOG FILE
    $test = strrev($_POST['error_log']);
    if (strpos($test, $error_log) === 0)
    {
        @unlink($path . $_POST['error_log']);
        echo '<h3>' . $_POST['error_log'] . ' Discarded</h3>';
    }
}


// COLLECT THE DIRECTORY INFORMATION OBJECTS
$objs = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($path), RecursiveIteratorIterator::SELF_FIRST);


// ITERATE OVER THE OBJECTS
foreach($objs as $name => $obj)
{
    // PROCESS THE ERROR LOG ONLY
    $test = strrev($name);
    if (strpos($test, $error_log) === 0)
    {
        // CREATE A DELETE BUTTON FOR THIS ERROR LOG
        $name = substr($name, $plen);
        $form = <<<EOD
<form method="post" style="margin:0; padding:0; display:inline;!important">
<b>$name</b>
<input type="submit" value="Discard?" />
<input type="hidden" name="error_log" value="$name" />
</form>
EOD;
        echo $form;

        // SHOW THE CONTENTS OF THIS ERROR LOG
        echo '<pre>';
        print_r(file_get_contents($path . $name));
        echo PHP_EOL . '********** EOF **********';
        echo '</pre>' . PHP_EOL;
    }
}


// IF THERE ARE NO ERROR LOG(S)
$out = ob_get_contents();
if (empty($out)) echo '<h3>Good News! No error_log found.</h3>';


// SHOW THE GIT BRANCH
$root = '.git/HEAD';
$text = @file_get_contents($root);
if ($text)
{
    $text = explode(DIRECTORY_SEPARATOR, $text);
    $text = array_slice($text, 2);
    $name = implode(DIRECTORY_SEPARATOR, $text);
    echo PHP_EOL . "On Git branch: $name" . PHP_EOL;
}
else
{
    echo PHP_EOL . "On Git branch: UNKNOWN" . PHP_EOL;
}

echo '<a href="' . $_SERVER['REQUEST_URI'] . '">Run Again</a>?' . PHP_EOL;

// SCRIPT TERMINATION WILL FLUSH THE OUTPUT BUFFER TO THE CLIENT BROWSER

Checking Your PHP Settings

检查您PHP设置

In case you're wondering about what PHP settings are in play, you can find everything by running this little script, shown here in its entirety.  It produces a lot of output, but with a browser search you can find the "good stuff."  You might try running this and checking the output for "error" to see what your settings are.

如果您想知道正在使用什么PHP设置,可以通过运行此小脚本来找到所有内容,此处完整显示。 它产生大量输出,但是通过浏览器搜索,您可以找到“好东西”。 您可以尝试运行此命令并检查输出中的“错误”,以查看设置是什么。

<?php phpinfo();

Conclusion

结论

An enormous volume of PHP code has been propagated with die() when a more reasonable code set would use trigger_error() instead.  This article has shown how to upgrade your code, and why you never want to use die() again.

当更合理的代码集使用trigger_error()代替时,die()传播了大量PHP代码。 本文介绍了如何升级代码,以及为什么您再也不想使用die()了。

If you find that this article has been helpful, please click the “thumb’s up” button below. Doing so lets the E-E community know what is valuable for E-E members and provides direction for future articles. Thanks!

如果您发现本文对您有所帮助,请单击下面的“竖起大拇指”按钮。 这样做可以使EE社区了解对EE成员有价值的内容,并为以后的文章提供指导。 谢谢!

翻译自: https://www.experts-exchange.com/articles/29115/PHP-Error-Handling-Never-Say-die-Again.html

php die

 类似资料: