处理 php 页面错误的最佳方法?

现在我的页面看起来像这样:

Right now my pages look something like this:

if($_GET['something'] == 'somevalue')
{
    $output .= 'somecode';

    // make a DB query, fetch a row
    //...
    $row = $stmt->Fetch(PDO::ASSOC);

    if($row != null)
    {
        $output .= 'morecode';

        if(somethingIsOK())
        {
            $output .= 'yet more page output';
        }
        else
        {
            $error = 'something is most definitely not OK.';
        }
    }
    else
    {
        $error = 'the row does not exist.';
    }
}
else
{
    $error = 'something is not a valid value';
}

if($error == '') // no error
{
    //display $output on page
}
else // an error
{
    // display whatever error occurred on the page
}

我做事的方式有效,但对于可能显而易见的事情来说非常繁琐和乏味:假设我在代码中间的某个地方调用了一个函数,或者想要检查一个变量的值,或者验证一个数据库查询返回了一个有效的结果,如果失败我想输出一个错误?我将不得不制作另一个 if/else 块并将所有代码移动到新的 if 块中.这似乎不是一种聪明的做事方式.

The way I'm doing things works, but it's very cumbersome and tedious for what is probably obvious: suppose that I call a function somewhere in the middle of my code, or want to check the value of a variable, or verify a DB query returned a valid result, and if it fails I want to output an error? I would have to make another if/else block and move all of the code inside the new if block. This doesn't seem like a smart way of doing things.

我一直在阅读有关 try/catch 的文章,并且一直在考虑将我的所有代码放在一个 try 语句中,然后让代码按顺序运行而没有任何 if/else 块,如果某些事情失败则抛出异常.从我读过的内容来看,这将停止执行并使其直接跳转到 catch 块(就像失败的 if 语句将转到 else 块一样),然后我可以在那里输出错误消息.但这是可接受的或标准的做法吗?

I have been reading about try/catch and have been thinking of putting all of my code inside a try statement, then let the code run sequentially without any if/else blocks and if something fails just throw an exception. From what I've read, that would halt the execution and make it jump straight to the catch block (just as a failed if statement will go to the else block), where I could then output the error message. But is that an acceptable or standard practice?

在构建和输出 HTML 页面的 php 应用程序中,处理错误的最佳方式是什么?我不想死在一个空白屏幕上,因为这对用户非常不友好,而是想在页面正文中输出一条消息,仍然允许显示页眉和页脚.

What's the best way of handling errors, fatal or not, in a php application that builds and outputs an HTML page? I don't want to just die with a blank screen, as that would be very user un-friendly, but instead want to output a message in the body of the page, still allowing the header and footer to show.

感谢您的建议!

推荐答案

有很多方法可以解决这个问题,坦率地说,没有一种方法本质上是正确的".

There are a lot of ways that you can deal with this and frankly none of them is intrinsically 'right'.

您必须自己决定哪种方法对您来说更舒服" - 这始终取决于偏好(尽管您应该避免使用某些技术并且有充分的理由).

You will have to decide for yourself, which method is more 'comfortable' for you - it's always a mater of preferences (although there are certain techniques you should avoid and for good reasons).

这在很大程度上取决于您如何拆分逻辑,但是我倾向于将所有可以返回非致命错误的代码包含在函数中,并使用所述函数的返回值来指示存在错误.

It will highly depend on how you split your logic, however I tend to enclose all code that can return non-fatal errors inside a function, and use a return value of said function to indicate there was an error.

对于致命错误,我倾向于使用异常(使用try-catch 块).

For fatal errors I tend to use exceptions (with try-catch blocks).

现在澄清一下:

  • 非致命错误是您可以恢复的错误 - 这意味着即使出现问题,仍有一些代码可以执行并生成一些有价值的输出.例如,如果您想使用NTP 协议获取当前时间,但服务器没有响应,您可以决定使用本地time 功能并仍然显示一些有价值的数据给用户.
  • 致命错误是一种您无法恢复的错误 - 意味着发生了非常糟糕的事情,您唯一能做的就是告诉您的用户页面无法执行原来的操作被要求做.例如,如果您从数据库中获取一些数据并遇到 SQL Exception - 则不会显示任何有价值的数据,您只能将此通知给用户.
  • A non-fatal error is an error that you can recover from - meaning that even though something went wrong, there is still some code that can be executed and generate some valuable output. For example if you wanted to get current time using NTP protocol, but the server didn't respond, you can decide to use local time function and still display a some valuable data to the user.
  • A fatal error is an error that you would not be able to recover from - meaning that something really bad happened and the only thing you can do is tell your user that page cannot do what it was asked to. For example if you were fetching some data from your database and got SQL Exception - there is no valuable data to be shown and you can only inform the user of this.

使用函数返回作为处理非致命问题的一个很好的例子是一个函数试图在页面上显示某个文件的内容当这不是页面的主要目标时(例如,您将有一个功能可以在每一页上显示从文本文件中获取的徽章 - 我知道这有点牵强,但请耐心等待).

A good example of using function-returns as a way of dealing with non-fatal problems would be a function that is trying to display content of some file on the page when this is not the main objective of the page (for example you would have a function that displays badges, fetched from a text file, on every single page - I know that this is far fetched but bear with me).

function getBadge($file){
    $f = fopen($file,'r');
    if(!$f){
        return null;
    }
    .. do some processing ..
    return $badges;
}

$badges = getBadges('badges.txt');
if(!$badges){
    echo "Cannot display badges.";
} else {
    echo $badges;
}
.. carry on doing whatever page should be doing ..

事实上,fopen 函数本身就是一个例子——它将返回.

In fact, the function fopen itself is an example of this - it will return.

成功时返回文件指针资源,错误时返回 FALSE.

Returns a file pointer resource on success, or FALSE on error.

<小时>

致命错误(使用异常 - try-catch)

当您有一些需要执行的代码,因为它正是用户想要的(例如从数据库中读取所有新闻并将它们显示给用户),您可以使用异常.让我们举一个简单的例子 - 一个用户访问了他的个人资料并想查看他收到的所有消息(现在假设它们以纯文本形式存储).你可能有这样的功能:


Fatal-Errors (using exceptions - try-catch)

When you have some piece of code that needs to be executed because it's exactly what the user wanted (for example reading all news from database and displaying them to the user), you could use exceptions. Let's take a simple example - a user visited his profile and wanted to see all the messages he's got (let's assume, for now, that they are stored in plain text). You might have a function like:

function getMessages($user){
    $messages = array();
    $f = fopen("messages_$user.txt","r");
    if(!$f){
        throw new Exception("Could not read messages!");
    }
    ... do some processing ...
    return $messages;
}

并像这样使用它:

try{
    ..do some stuff..
    $messages = getMessages($_SESSION['user'])); //assuming you store username in $_SESSION
    foreach($messages as $msg){
        echo $msg."<br/>";
    }
} catch(Exception $e){
    echo "Sorry, there was an error: ".$e->getMessage();
}

现在这可能会派上用场,如果您有一个可以执行所有其他代码的顶级"脚本.这意味着,例如,在您的 index.php 中,您只需:

Now this could come in handy, if you had a 'top-level' script that would execute all the other code. That means that, for example, in your index.php you would just have:

try{
    .. execute some code, perform some functions ..
} catch(Exception $e){
    echo "Sorry, there was an error: ".$e->getMessage();
}

不要过度使用异常!

无论您做什么,都不要使用异常来检查可以从中恢复的内容.阅读关于另一个问题(完全归功于给 Anton Gogolev 一个很好的解释,以及其他回答者)解释为什么会这样.

Do not overuse exceptions!

Whatever you do, never use exceptions as a way to check something you can recover from. Have a read on another question(full credit goes to Anton Gogolev for a very good explanation on this, as well as other answer-ers) as to why this is the case.

现在,没有比尝试多种方法并看看什么对您有好处更好的方法来学习如何处理错误了.您可能会发现以下内容很有用:

Now there is no better way to learn how to deal with errors than to try several things and see what is good for you. You might find the below useful:

  • W3School 关于 PHP 异常处理
  • 错误处理简短教程(类似于我的函数返回方法)
  • 有关 PHP 错误处理的详尽教程 - 包括使用 trigger_error() 函数,我没有提到它,因为我不使用它,也不太了解它,但显然它真的很有用.这是一本特别好的读物.
  • W3School on PHP Exception handling
  • Short tutorial on error handling(similar to my function-returns method)
  • Extensive tutorial on PHP error handling - including using trigger_error() function, which I haven't mentioned because I don't use it and don't know much about it, but apparently it's really useful. This is a particularly good read.

希望这有帮助:)

相关文章