在PHP5中,我应该使用Exceptions还是trigger_error / set_error_handler?

时间:2022-08-17 03:15:58

What are the pros/cons of doing either way. Is there One Right Way(tm) ?

做任何一种方式的优点/缺点是什么?有一条正确的方法(tm)?

9 个解决方案

#1


20  

If you want to use exceptions instead of errors for your entire application, you can do it with ErrorException and a custom error handler (see the ErrorException page for a sample error handler). The only downside to this method is that non-fatal errors will still throw exceptions, which are always fatal unless caught. Basically, even an E_NOTICE will halt your entire application if your error_reporting settings do not suppress them.

如果要为整个应用程序使用异常而不是错误,可以使用ErrorException和自定义错误处理程序(请参阅错误处理程序的ErrorException页面)。这种方法唯一的缺点是非致命错误仍会抛出异常,除非被捕获,否则这些异常总是致命的。基本上,如果您的error_reporting设置没有抑制它们,即使是E_NOTICE也会暂停整个应用程序。

In my opinion, there are several benefits to using ErrorException:

在我看来,使用ErrorException有几个好处:

  1. A custom exception handler will let you display nice messages, even for errors, using set_exception_handler.
  2. 使用set_exception_handler,自定义异常处理程序将允许您显示好消息,甚至是错误。
  3. It does not disrupt existing code in any way... trigger_error and other error functions will still work normally.
  4. 它不会以任何方式破坏现有代码...... trigger_error和其他错误函数仍然可以正常工作。
  5. It makes it really hard to ignore stupid coding mistakes that trigger E_NOTICEs and E_WARNINGs.
  6. 这使得忽略触发E_NOTICE和E_WARNING的愚蠢编码错误变得非常困难。
  7. You can use try/catch to wrap code that may generate a PHP error (not just exceptions), which is a nice way to avoid using the @ error suppression hack:

    您可以使用try / catch来包装可能生成PHP错误的代码(不仅仅是异常),这是一种避免使用@ error suppression hack的好方法:

    try {
        $foo = $_GET['foo'];
    } catch (ErrorException $e) {
        $foo = NULL;
    }
    
  8. You can wrap your entire script in a single try/catch block if you want to display a friendly message to your users when any uncaught error happens. (Do this carefully, because only uncaught errors and exceptions are logged.)

    如果要在发生任何未捕获的错误时向用户显示友好消息,可以将整个脚本包装在单个try / catch块中。 (请仔细执行此操作,因为只会记录未捕获的错误和异常。)

#2


8  

You should use exceptions in "Exceptional circumstances", that is when you call a method doFoo() you should expect it to perform, if for some reason doFoo is unable to do it's job then it should raise an exception.

你应该在“异常情况”中使用异常,也就是当你调用一个你应该期望它执行的方法doFoo()时,如果由于某种原因doFoo无法完成它的工作那么它应该引发异常。

A lot of old php code would take the approach of returning false or null when a failure has occured, but this makes things hard to debug, exceptions make this debugging much easier.

很多旧的PHP代码会在发生故障时采用返回false或null的方法,但这会使调试变得困难,异常会使调试变得更加容易。

For example say you had a method called getDogFood() which returned an array of DogFood objects, if you called this method and it returns null when something goes wrong how will your calling code be able to tell whether null was returned because there was an error or there is just no dog food available?

例如,假设你有一个名为getDogFood()的方法,它返回了一个DogFood对象数组,如果你调用了这个方法并且在出现问题时返回null,你的调用代码将如何判断是否返回了null,因为出现了错误还是没有狗食?

Regarding dealing with legacy code libraries that use php's inbuilt error logging, you can override the error logging with the set_error_handler() function, which you could use to then rethrow a generic Exception.

关于处理使用php内置错误日志记录的遗留代码库,您可以使用set_error_handler()函数覆盖错误日志记录,然后可以使用该函数重新抛出一般异常。

Now that you have all of your code throwing detailed exceptions, you are free to decide what to do with them, in some parts of your code you may wish to catch them and try alternative methods or you can log them using your own logging functions which might log to a database, file, email - whichever you prefer. In short - Exceptions are more flexible .

现在您已经将所有代码抛出了详细的异常,您可以*决定如何处理它们,在代码的某些部分中,您可能希望捕获它们并尝试其他方法,或者您可以使用自己的日志记录功能来记录它们。可能会记录到数据库,文件,电子邮件 - 无论您喜欢哪个。简而言之 - 例外更灵活。

#3


6  

I love the idea of using exceptions, but I often have third party libraries involved, and then if they don't use exceptions you end up with 3-4 different approaches to the problem! Zend uses exceptions. CakePHP uses a custom error handler, and most PEAR libraries use the PEAR::Error object.

我喜欢使用异常的想法,但我经常涉及第三方库,然后如果他们不使用异常,最终会有3-4种不同的方法解决问题! Zend使用例外。 CakePHP使用自定义错误处理程序,大多数PEAR库使用PEAR :: Error对象。

I which there WAS one true way in this regard. The custom error handlers route is probably the most flexible in this situation. Exceptions are a great idea though if you're either only using your own code, or using libraries that use them.

我在这方面有一个真正的方法。在这种情况下,自定义错误处理程序路由可能是最灵活的。如果您只使用自己的代码或使用使用它们的库,则例外是一个好主意。

Unfortunately in the PHP world we're still suffering from the refusal to die of PHP4, so things like exceptions, while they may represent best practise have been incredibly slow to catch on while everyone is still writing things to be able to work in both 4 and 5. Hopefully this debacle is now ending, though by the time it does, we'll have tensions between 6 and 5 instead...

遗憾的是在PHP世界我们仍然拒绝痛苦死PHP4的,所以像例外,虽然他们可能代表最佳实践已经流行开来,而每个人都还在写的东西能在同时有4工作慢得令人难以置信5.希望这个崩溃现在已经结束,但到了它的时候,我们将面临6到5之间的紧张局面......

/me holds head in hands...

/我掌握在手中......

#4


3  

It depends on the situation. I tend to use Exceptions when I am writing business logic/application internals, and trigger_error for Validator's and things of that sort.

这取决于实际情况。在编写业务逻辑/应用程序内部时,我倾向于使用异常,而对于Validator和类似的东西,我倾向于使用trigger_error。

The pro's of using Exceptions at the logic level is to allow your application to do in case of such an error. You allow the application to chose instead of having the business logic know how to present the error.

在逻辑级别使用Exceptions的专家是允许您的应用程序在出现此类错误时执行此操作。您允许应用程序选择而不是让业务逻辑知道如何呈现错误。

The pro's of using trigger_error for Validator's and things of that nature are, say,

例如,使用trigger_error for Validator和这种性质的东西的专家是

try {
    $user->login();
}  catch (AuthenticationFailureException $e) {
    set_error_handler("my_login_form_handler");
    trigger_error("User could not be logged in. Please check username and password and try again!");
} catch (PersistenceException $pe) { // database unavailable
    set_error_handler("my_login_form_handler"); 
    trigger_error("Internal system error. Please contact the administrator.");
}

where my_login_form_handler pretties up the string and places the element in a visible area above the login form.

其中my_login_form_handler将字符串放在一边,并将元素放在登录表单上方的可见区域中。

#5


3  

Obviously, there's no "One Right Way", but there's a multitude of opinions on this one. ;)

显然,没有“一种正确的方式”,但对此有很多意见。 ;)

Personally i use trigger_error for things the exceptions cannot do, namely notices and warnings (i.e. stuff you want to get logged, but not stop the flow of the application in the same way that errors/exceptions do (even if you catch them at some level)).

我个人使用trigger_error来处理异常无法做到的事情,即通知和警告(即你想要记录的东西,但不能像错误/异常那样停止应用程序的流程(即使你在某种程度上捕获它们) ))。

I also mostly use exceptions for conditions that are assumed to be non-recoverable (to the caller of the method in which the exception occurs), i.e. serious errors. I don't use exceptions as an alternative to returning a value with the same meaning, if that's possible in a non-convoluted way. For example, if I create a lookup method, I usually return a null value if it didn't find whatever it was looking for instead of throwing an EntityNotFoundException (or equivalent).

我还主要对假定为不可恢复的条件(对发生异常的方法的调用者)使用异常,即严重错误。我不使用异常作为返回具有相同含义的值的替代方法,如果这可能是非复杂的方式。例如,如果我创建一个查找方法,我通常会返回一个空值,如果它找不到它要查找的内容而不是抛出一个EntityNotFoundException(或等效的)。

So my rule of thumb is this:

所以我的经验法则是这样的:

  • As long as not finding something is a reasonable result, I find it much easier returning and checking for null-values (or some other default value) than handling it using a try-catch-clause.
  • 只要找不到合适的结果,我发现返回和检查空值(或其他一些默认值)要比使用try-catch子句处理它更容易。
  • If, on the other hand, not finding it is a serious error that's not within the scope of the caller to recover from, I'd still throw an exception.
  • 另一方面,如果没有发现它是一个严重的错误,不属于调用者的范围,我仍然会抛出异常。

The reason for throwing exceptions in the latter case (as opposed to triggering errors), is that exceptions are much more expressive, given that you use properly named Exception subclasses. I find that using PHP's Standard Library's exceptions is a good starting point when deciding what exceptions to use: http://www.php.net/~helly/php/ext/spl/classException.html

在后一种情况下抛出异常(而不是触发错误)的原因是异常更具表现力,因为您使用了正确命名的Exception子类。我发现在决定使用哪些例外时,使用PHP的标准库的例外是一个很好的起点:http://www.php.net/~helly/php/ext/spl/classException.html

You might want to extend them to get more semantically correct exceptions for your particular case, however.

但是,您可能希望扩展它们以获得针对特定情况的更具语义正确的异常。

#6


3  

Intro

In my personal experience, as a general rule, I prefer to use Exceptions in my code instead of trigger_error. This is mainly because using Exceptions is more flexible than triggering errors. And, IMHO, this is also beneficial not only for myself as for the 3rd party developer.

根据我的个人经验,作为一般规则,我更喜欢在我的代码中使用Exceptions而不是trigger_error。这主要是因为使用Exceptions比触发错误更灵活。而且,恕我直言,这不仅对我自己和第三方开发者也有好处。

  1. I can extend the Exception class (or use exception codes) to explicitly differentiate the states of my library. This helps me and 3rd party developers in handling and debugging the code. This also exposes where and why it can fail without the need for source code browsing.
  2. 我可以扩展Exception类(或使用异常代码)来明确区分我的库的状态。这有助于我和第三方开发人员处理和调试代码。这也揭示了它可以在不需要源代码浏览的情况下失败的地方和原因。
  3. I can effectively halt the execution of my Library without halting the execution of the script.
  4. 我可以有效地暂停我的库的执行而不会停止脚本的执行。
  5. The 3rd party developer can chain my Exceptions (in PHP > 5.3.*) Very useful for debugging and might be handy in handling situations where my library can fail due to disparate reasons.
  6. 第三方开发人员可以链接我的异常(在PHP> 5.3。*中)对于调试非常有用,并且可能在处理由于不同原因导致我的库失败的情况时很方便。

And I can do all this without imposing how he should handle my library failures. (ie: creating complex error handling functions). He can use a try catch block or just use an generic exception handler

我可以做到这一切,而不会强加他应该如何处理我的库故障。 (即:创建复杂的错误处理函数)。他可以使用try catch块或只使用通用异常处理程序

Note:

注意:

Some of these points, in essence, are also valid for trigger_error, just a bit more complex to implement. Try catch blocks are really easy to use and very code friendly.

实质上,其中一些要点对于trigger_error也有效,实现起来要复杂一些。尝试catch块非常容易使用,非常友好。


Example

I think this is an example might illustrate my point of view:

我认为这是一个例子可以说明我的观点:

class HTMLParser {
    protected $doc;
    protected $source = null;
    public $parsedHtml;
    protected $parseErrors = array();
    public function __construct($doc) {
        if (!$doc instanceof DOMDocument) {
            // My Object is unusable without a valid DOMDOcument object
            // so I throw a CriticalException
            throw new CriticalException("Could not create Object Foo. You must pass a valid DOMDOcument object as parameter in the constructor");
        }
        $this->doc = $doc;
    }

    public function setSource($source) {
        if (!is_string($source)) {
            // I expect $source to be a string but was passed something else so I throw an exception
            throw new InvalidArgumentException("I expected a string but got " . gettype($source) . " instead");
        }
        $this->source = trim($source);
        return $this;
    }

    public function parse() {
        if (is_null($this->source) || $this->source == '') {
            throw new EmptyStringException("Source is empty");
        }
        libxml_use_internal_errors(true);
        $this->doc->loadHTML($this->source);
        $this->parsedHtml = $this->doc->saveHTML();
        $errors = libxml_get_errors();
        if (count($errors) > 0) {
            $this->parseErrors = $errors;
            throw new HtmlParsingException($errors[0]->message,$errors[0]->code,null,
                $errors[0]->level,$errors[0]->column,$errors[0]->file,$errors[0]->line);
        }
        return $this;
    }

    public function getParseErrors() {
        return $this->parseErrors;
    }

    public function getDOMObj() {
        return clone $this->doc;
    }
}

Explanation

In the constructor I throw a CriticalException if the param passed is not of type DOMDocument because without it my library will not work at all.

在构造函数中,如果传递的param不是DOMDocument类型,则抛出一个CriticalException,因为如果没有它,我的库将根本不起作用。

(Note: I could simply write __construct(DOMDocument $doc) but this is just an example).

(注意:我可以简单地编写__construct(DOMDocument $ doc),但这只是一个例子)。

In setsource() method I throw a InvalidArgumentException if the param passed is something other than a string. I prefer to halt the library execution here because source property is an essential property of my class and an invalid value will propagate the error throughout my library.

在setsource()方法中,如果传递的参数不是字符串,则抛出InvalidArgumentException。我更喜欢在这里暂停库执行,因为source属性是我的类的基本属性,无效值将在我的库中传播错误。

The parse() method is usually the last method invoked in the cycle. Even though I throw a XmlParsingException if libXML finds a malformed document, the parsing is completed first and the results usable (to an extent).

parse()方法通常是循环中调用的最后一个方法。即使我在libXML找到格式错误的文档时抛出XmlParsingException,也会首先完成解析并且结果可用(在某种程度上)。


Handling the example library

Here's an example how to handle this made up library:

以下是如何处理这个组成库的示例:

$source = file_get_contents('http://www.somehost.com/some_page.html');
try {
    $parser = new HTMLParser(new DOMDocument());
    $parser->setSource($source)
           ->parse();
} catch (CriticalException $e) {
    // Library failed miserably, no recover is possible for it.
    // In this case, it's prorably my fault because I didn't pass
    // a DOMDocument object.
    print 'Sorry. I made a mistake. Please send me feedback!';
} catch (InvalidArgumentException $e) {
    // the source passed is not a string, again probably my fault.
    // But I have a working parser object. 
    // Maybe I can try again by typecasting the argument to string
    var_dump($parser);
} catch (EmptyStringException $e) {
    // The source string was empty. Maybe there was an error
    // retrieving the HTML? Maybe the remote server is down?
    // Maybe the website does not exist anymore? In this case,
    // it isn't my fault it failed. Maybe I can use a cached
    // version?
    var_dump($parser);
} catch (HtmlParsingException $e) {
    // The html suplied is malformed. I got it from the interwebs
    // so it's not my fault. I can use $e or getParseErrors() 
    // to see if the html (and DOM Object) is usable
    // I also have a full functioning HTMLParser Object and can
    // retrieve a "loaded" functioning DOMDocument Object
    var_dump($parser->getParseErrors());
    var_dump($parser->getDOMObj());
}
$var = 'this will print wether an exception was previously thrown or not';
print $var;

You can take this further and nest try catch blocks, chain exceptions, run selective code following a determined exception chain path, selective logging, etc...

您可以进一步采取这种做法并嵌套try catch块,链异常,在确定的异常链路径后运行选择性代码,选择性记录等等......

As a side note, using Exceptions does not mean that the PROGRAM execution will halt, it just means that the code depending of my object will be bypassed. It's up to me or the 3rd party developer to do with it as he pleases.

作为旁注,使用Exceptions并不意味着PROGRAM执行将停止,它只是意味着将绕过依赖于我的对象的代码。这取决于我或第三方开发人员随时随地使用它。

#7


2  

The idea of exception is elegant and makes the error handling process so smooth. but this only applies when you have appropriate exception classes and in team development, one more important thing is "standard" exceptions. so if you plan to use exceptions, you'd better first standardize your exception types, or the better choice is to use exceptions from some popular framework. one other thing that applies to PHP (where you can write your code object orienter combined with structural code), is that if you are writing your whole application using classes. If you are writing object oriented, then exceptions are better for sure. after all I think your error handling process will be much smoother with exception than trigger_error and stuff.

异常的想法很优雅,使错误处理过程如此顺利。但这仅适用于您有适当的异常类并且在团队开发中,更重要的是“标准”异常。因此,如果您计划使用异常,最好先标准化异常类型,或者更好的选择是使用某些流行框架中的异常。另一个适用于PHP的东西(你可以编写你的代码对象orienter结合结构代码),如果你使用类编写整个应用程序。如果您正在编写面向对象,那么异常肯定会更好。毕竟我认为你的错误处理过程会比trigger_error和stuff更加顺畅。

#8


1  

The Exceptions are the modern and robust way of signaling an error condition / an exceptional situation. Use them :)

异常是发出错误情况/异常情况的现代且可靠的方式。使用它们 :)

#9


-2  

Using exceptions are not a good idea in the era of 3rd party application integration.

在第三方应用程序集成时代,使用异常并不是一个好主意。

Because, the moment you try to integrate your app with something else, or someone else's app with yours, your entire application will come to a halt the moment a class in some 3rd party plugin throws an exception. Even if you have full fledged error handling, logging implemented in your own app, someone's random object in a 3rd party plugin will throw an exception, and your entire application will stop right there.

因为,当您尝试将应用程序与其他应用程序或其他人的应用程序集成在一起时,您的整个应用程序将在某个第三方插件中的类引发异常时停止。即使你有完整的错误处理,在你自己的应用程序中实现日志记录,第三方插件中某人的随机对象将抛出异常,你的整个应用程序将停在那里。

EVEN if you have the means in your application to make up for the error of that library you are using....

即使您的应用程序中有手段来弥补您正在使用的库的错误....

A case in example may be a 3rd party social login library which throws an exception because the social login provider returned an error, and kills your entire app unnecessarily - hybridauth, by the way. So, There you have an entire app, and there you have a library bringing in added functionality for you - in this case, social login - and even though you have a lot of fallback stuff in the case a provider does not authenticate (your own login system, plus like 20 or so other social login providers), your ENTIRE application will come to a grinding halt. And you will end up having to change the 3rd party library to work around these issues, and the point of using a 3rd party library to speed up development will be lost.

示例中的案例可能是第三方社交登录库,它会引发异常,因为社交登录提供程序返回了错误,并且不必要地杀死整个应用程序 - 顺便说一下,hybridauth。那么,你有一个完整的应用程序,你有一个库为你带来了额外的功能 - 在这种情况下,社交登录 - 即使你有很多后备的东西,提供商不认证(你自己的登录系统,再加上20个左右的其他社交登录提供商),您的整个应用程序将停止运行。并且您最终将不得不更改第三方库以解决这些问题,并且使用第三方库加速开发的重点将会丢失。

This is a serious design flaw in regard to philosophy of handling errors in PHP. Lets face it - under the other end of most of applications developed today, there is a user. Be it an intranet user, be it a user over internet, be it a sysadmin, it does not matter - there is generally a user.

对于PHP中处理错误的哲学而言,这是一个严重的设计缺陷。让我们面对它 - 在今天开发的大多数应用程序的另一端,有一个用户。无论是内联网用户,无论是互联网上的用户,还是系统管理员,都无所谓 - 通常都是用户。

And, having an application die on your face without there being anything you can do at that point other than to go back to a previous page and have a shot in the dark regarding what you are trying to do, as a user, is bad, bad practice from development side. Not to mention, an internal error which only the developers should know due to many reasons (from usability to security) being thrown on the face of a user.

并且,有一个应用程序死在你的脸上没有任何你可以做的事情,除了回到上一页并在黑暗中拍摄你想要做的事情,作为一个用户,是坏的,发展方面的不良做法。更不用说,只有开发人员应该知道的内部错误由于许多原因(从可用性到安全性)被抛到用户的脸上。

As a result, im going to have to just let go of a particular 3rd party library (hybridauth in this case) and not use it in my application, solely for that reason. Despite the fact that hybridauth is a very good library, and apparently a lot of good effort have been spent on it, with a phletora of capabilities.

因此,我将不得不放弃特定的第三方库(在这种情况下是hybridauth)而不是在我的应用程序中使用它,仅仅是因为这个原因。尽管hybridauth是一个非常好的库,并且显然已经花费了很多精力,并且具有功能上的phletora。

Therefore, you should refrain from using exceptions in your code. EVEN if the code you are doing right now, is the top level code that will run your application, and not a library, it is possible that you may want to include all or part of your code in other projects, or have to integrate parts or entirety of it with other code of yours or 3rd party code. And if you used exceptions, you will end up with the same situation - entire applications/integrations dying in your face even if you have proper means to handle whatever issue a piece of code provides.

因此,您应该避免在代码中使用异常。即使您现在正在执行的代码是运行应用程序的*代码,而不是库,您可能希望将全部或部分代码包含在其他项目中,或者必须集成部件或其全部与您的其他代码或第三方代码。如果你使用异常,你将会遇到同样的情况 - 即使你有适当的方法处理一段代码提供的任何问题,整个应用程序/集成也会在你的脸上消失。

#1


20  

If you want to use exceptions instead of errors for your entire application, you can do it with ErrorException and a custom error handler (see the ErrorException page for a sample error handler). The only downside to this method is that non-fatal errors will still throw exceptions, which are always fatal unless caught. Basically, even an E_NOTICE will halt your entire application if your error_reporting settings do not suppress them.

如果要为整个应用程序使用异常而不是错误,可以使用ErrorException和自定义错误处理程序(请参阅错误处理程序的ErrorException页面)。这种方法唯一的缺点是非致命错误仍会抛出异常,除非被捕获,否则这些异常总是致命的。基本上,如果您的error_reporting设置没有抑制它们,即使是E_NOTICE也会暂停整个应用程序。

In my opinion, there are several benefits to using ErrorException:

在我看来,使用ErrorException有几个好处:

  1. A custom exception handler will let you display nice messages, even for errors, using set_exception_handler.
  2. 使用set_exception_handler,自定义异常处理程序将允许您显示好消息,甚至是错误。
  3. It does not disrupt existing code in any way... trigger_error and other error functions will still work normally.
  4. 它不会以任何方式破坏现有代码...... trigger_error和其他错误函数仍然可以正常工作。
  5. It makes it really hard to ignore stupid coding mistakes that trigger E_NOTICEs and E_WARNINGs.
  6. 这使得忽略触发E_NOTICE和E_WARNING的愚蠢编码错误变得非常困难。
  7. You can use try/catch to wrap code that may generate a PHP error (not just exceptions), which is a nice way to avoid using the @ error suppression hack:

    您可以使用try / catch来包装可能生成PHP错误的代码(不仅仅是异常),这是一种避免使用@ error suppression hack的好方法:

    try {
        $foo = $_GET['foo'];
    } catch (ErrorException $e) {
        $foo = NULL;
    }
    
  8. You can wrap your entire script in a single try/catch block if you want to display a friendly message to your users when any uncaught error happens. (Do this carefully, because only uncaught errors and exceptions are logged.)

    如果要在发生任何未捕获的错误时向用户显示友好消息,可以将整个脚本包装在单个try / catch块中。 (请仔细执行此操作,因为只会记录未捕获的错误和异常。)

#2


8  

You should use exceptions in "Exceptional circumstances", that is when you call a method doFoo() you should expect it to perform, if for some reason doFoo is unable to do it's job then it should raise an exception.

你应该在“异常情况”中使用异常,也就是当你调用一个你应该期望它执行的方法doFoo()时,如果由于某种原因doFoo无法完成它的工作那么它应该引发异常。

A lot of old php code would take the approach of returning false or null when a failure has occured, but this makes things hard to debug, exceptions make this debugging much easier.

很多旧的PHP代码会在发生故障时采用返回false或null的方法,但这会使调试变得困难,异常会使调试变得更加容易。

For example say you had a method called getDogFood() which returned an array of DogFood objects, if you called this method and it returns null when something goes wrong how will your calling code be able to tell whether null was returned because there was an error or there is just no dog food available?

例如,假设你有一个名为getDogFood()的方法,它返回了一个DogFood对象数组,如果你调用了这个方法并且在出现问题时返回null,你的调用代码将如何判断是否返回了null,因为出现了错误还是没有狗食?

Regarding dealing with legacy code libraries that use php's inbuilt error logging, you can override the error logging with the set_error_handler() function, which you could use to then rethrow a generic Exception.

关于处理使用php内置错误日志记录的遗留代码库,您可以使用set_error_handler()函数覆盖错误日志记录,然后可以使用该函数重新抛出一般异常。

Now that you have all of your code throwing detailed exceptions, you are free to decide what to do with them, in some parts of your code you may wish to catch them and try alternative methods or you can log them using your own logging functions which might log to a database, file, email - whichever you prefer. In short - Exceptions are more flexible .

现在您已经将所有代码抛出了详细的异常,您可以*决定如何处理它们,在代码的某些部分中,您可能希望捕获它们并尝试其他方法,或者您可以使用自己的日志记录功能来记录它们。可能会记录到数据库,文件,电子邮件 - 无论您喜欢哪个。简而言之 - 例外更灵活。

#3


6  

I love the idea of using exceptions, but I often have third party libraries involved, and then if they don't use exceptions you end up with 3-4 different approaches to the problem! Zend uses exceptions. CakePHP uses a custom error handler, and most PEAR libraries use the PEAR::Error object.

我喜欢使用异常的想法,但我经常涉及第三方库,然后如果他们不使用异常,最终会有3-4种不同的方法解决问题! Zend使用例外。 CakePHP使用自定义错误处理程序,大多数PEAR库使用PEAR :: Error对象。

I which there WAS one true way in this regard. The custom error handlers route is probably the most flexible in this situation. Exceptions are a great idea though if you're either only using your own code, or using libraries that use them.

我在这方面有一个真正的方法。在这种情况下,自定义错误处理程序路由可能是最灵活的。如果您只使用自己的代码或使用使用它们的库,则例外是一个好主意。

Unfortunately in the PHP world we're still suffering from the refusal to die of PHP4, so things like exceptions, while they may represent best practise have been incredibly slow to catch on while everyone is still writing things to be able to work in both 4 and 5. Hopefully this debacle is now ending, though by the time it does, we'll have tensions between 6 and 5 instead...

遗憾的是在PHP世界我们仍然拒绝痛苦死PHP4的,所以像例外,虽然他们可能代表最佳实践已经流行开来,而每个人都还在写的东西能在同时有4工作慢得令人难以置信5.希望这个崩溃现在已经结束,但到了它的时候,我们将面临6到5之间的紧张局面......

/me holds head in hands...

/我掌握在手中......

#4


3  

It depends on the situation. I tend to use Exceptions when I am writing business logic/application internals, and trigger_error for Validator's and things of that sort.

这取决于实际情况。在编写业务逻辑/应用程序内部时,我倾向于使用异常,而对于Validator和类似的东西,我倾向于使用trigger_error。

The pro's of using Exceptions at the logic level is to allow your application to do in case of such an error. You allow the application to chose instead of having the business logic know how to present the error.

在逻辑级别使用Exceptions的专家是允许您的应用程序在出现此类错误时执行此操作。您允许应用程序选择而不是让业务逻辑知道如何呈现错误。

The pro's of using trigger_error for Validator's and things of that nature are, say,

例如,使用trigger_error for Validator和这种性质的东西的专家是

try {
    $user->login();
}  catch (AuthenticationFailureException $e) {
    set_error_handler("my_login_form_handler");
    trigger_error("User could not be logged in. Please check username and password and try again!");
} catch (PersistenceException $pe) { // database unavailable
    set_error_handler("my_login_form_handler"); 
    trigger_error("Internal system error. Please contact the administrator.");
}

where my_login_form_handler pretties up the string and places the element in a visible area above the login form.

其中my_login_form_handler将字符串放在一边,并将元素放在登录表单上方的可见区域中。

#5


3  

Obviously, there's no "One Right Way", but there's a multitude of opinions on this one. ;)

显然,没有“一种正确的方式”,但对此有很多意见。 ;)

Personally i use trigger_error for things the exceptions cannot do, namely notices and warnings (i.e. stuff you want to get logged, but not stop the flow of the application in the same way that errors/exceptions do (even if you catch them at some level)).

我个人使用trigger_error来处理异常无法做到的事情,即通知和警告(即你想要记录的东西,但不能像错误/异常那样停止应用程序的流程(即使你在某种程度上捕获它们) ))。

I also mostly use exceptions for conditions that are assumed to be non-recoverable (to the caller of the method in which the exception occurs), i.e. serious errors. I don't use exceptions as an alternative to returning a value with the same meaning, if that's possible in a non-convoluted way. For example, if I create a lookup method, I usually return a null value if it didn't find whatever it was looking for instead of throwing an EntityNotFoundException (or equivalent).

我还主要对假定为不可恢复的条件(对发生异常的方法的调用者)使用异常,即严重错误。我不使用异常作为返回具有相同含义的值的替代方法,如果这可能是非复杂的方式。例如,如果我创建一个查找方法,我通常会返回一个空值,如果它找不到它要查找的内容而不是抛出一个EntityNotFoundException(或等效的)。

So my rule of thumb is this:

所以我的经验法则是这样的:

  • As long as not finding something is a reasonable result, I find it much easier returning and checking for null-values (or some other default value) than handling it using a try-catch-clause.
  • 只要找不到合适的结果,我发现返回和检查空值(或其他一些默认值)要比使用try-catch子句处理它更容易。
  • If, on the other hand, not finding it is a serious error that's not within the scope of the caller to recover from, I'd still throw an exception.
  • 另一方面,如果没有发现它是一个严重的错误,不属于调用者的范围,我仍然会抛出异常。

The reason for throwing exceptions in the latter case (as opposed to triggering errors), is that exceptions are much more expressive, given that you use properly named Exception subclasses. I find that using PHP's Standard Library's exceptions is a good starting point when deciding what exceptions to use: http://www.php.net/~helly/php/ext/spl/classException.html

在后一种情况下抛出异常(而不是触发错误)的原因是异常更具表现力,因为您使用了正确命名的Exception子类。我发现在决定使用哪些例外时,使用PHP的标准库的例外是一个很好的起点:http://www.php.net/~helly/php/ext/spl/classException.html

You might want to extend them to get more semantically correct exceptions for your particular case, however.

但是,您可能希望扩展它们以获得针对特定情况的更具语义正确的异常。

#6


3  

Intro

In my personal experience, as a general rule, I prefer to use Exceptions in my code instead of trigger_error. This is mainly because using Exceptions is more flexible than triggering errors. And, IMHO, this is also beneficial not only for myself as for the 3rd party developer.

根据我的个人经验,作为一般规则,我更喜欢在我的代码中使用Exceptions而不是trigger_error。这主要是因为使用Exceptions比触发错误更灵活。而且,恕我直言,这不仅对我自己和第三方开发者也有好处。

  1. I can extend the Exception class (or use exception codes) to explicitly differentiate the states of my library. This helps me and 3rd party developers in handling and debugging the code. This also exposes where and why it can fail without the need for source code browsing.
  2. 我可以扩展Exception类(或使用异常代码)来明确区分我的库的状态。这有助于我和第三方开发人员处理和调试代码。这也揭示了它可以在不需要源代码浏览的情况下失败的地方和原因。
  3. I can effectively halt the execution of my Library without halting the execution of the script.
  4. 我可以有效地暂停我的库的执行而不会停止脚本的执行。
  5. The 3rd party developer can chain my Exceptions (in PHP > 5.3.*) Very useful for debugging and might be handy in handling situations where my library can fail due to disparate reasons.
  6. 第三方开发人员可以链接我的异常(在PHP> 5.3。*中)对于调试非常有用,并且可能在处理由于不同原因导致我的库失败的情况时很方便。

And I can do all this without imposing how he should handle my library failures. (ie: creating complex error handling functions). He can use a try catch block or just use an generic exception handler

我可以做到这一切,而不会强加他应该如何处理我的库故障。 (即:创建复杂的错误处理函数)。他可以使用try catch块或只使用通用异常处理程序

Note:

注意:

Some of these points, in essence, are also valid for trigger_error, just a bit more complex to implement. Try catch blocks are really easy to use and very code friendly.

实质上,其中一些要点对于trigger_error也有效,实现起来要复杂一些。尝试catch块非常容易使用,非常友好。


Example

I think this is an example might illustrate my point of view:

我认为这是一个例子可以说明我的观点:

class HTMLParser {
    protected $doc;
    protected $source = null;
    public $parsedHtml;
    protected $parseErrors = array();
    public function __construct($doc) {
        if (!$doc instanceof DOMDocument) {
            // My Object is unusable without a valid DOMDOcument object
            // so I throw a CriticalException
            throw new CriticalException("Could not create Object Foo. You must pass a valid DOMDOcument object as parameter in the constructor");
        }
        $this->doc = $doc;
    }

    public function setSource($source) {
        if (!is_string($source)) {
            // I expect $source to be a string but was passed something else so I throw an exception
            throw new InvalidArgumentException("I expected a string but got " . gettype($source) . " instead");
        }
        $this->source = trim($source);
        return $this;
    }

    public function parse() {
        if (is_null($this->source) || $this->source == '') {
            throw new EmptyStringException("Source is empty");
        }
        libxml_use_internal_errors(true);
        $this->doc->loadHTML($this->source);
        $this->parsedHtml = $this->doc->saveHTML();
        $errors = libxml_get_errors();
        if (count($errors) > 0) {
            $this->parseErrors = $errors;
            throw new HtmlParsingException($errors[0]->message,$errors[0]->code,null,
                $errors[0]->level,$errors[0]->column,$errors[0]->file,$errors[0]->line);
        }
        return $this;
    }

    public function getParseErrors() {
        return $this->parseErrors;
    }

    public function getDOMObj() {
        return clone $this->doc;
    }
}

Explanation

In the constructor I throw a CriticalException if the param passed is not of type DOMDocument because without it my library will not work at all.

在构造函数中,如果传递的param不是DOMDocument类型,则抛出一个CriticalException,因为如果没有它,我的库将根本不起作用。

(Note: I could simply write __construct(DOMDocument $doc) but this is just an example).

(注意:我可以简单地编写__construct(DOMDocument $ doc),但这只是一个例子)。

In setsource() method I throw a InvalidArgumentException if the param passed is something other than a string. I prefer to halt the library execution here because source property is an essential property of my class and an invalid value will propagate the error throughout my library.

在setsource()方法中,如果传递的参数不是字符串,则抛出InvalidArgumentException。我更喜欢在这里暂停库执行,因为source属性是我的类的基本属性,无效值将在我的库中传播错误。

The parse() method is usually the last method invoked in the cycle. Even though I throw a XmlParsingException if libXML finds a malformed document, the parsing is completed first and the results usable (to an extent).

parse()方法通常是循环中调用的最后一个方法。即使我在libXML找到格式错误的文档时抛出XmlParsingException,也会首先完成解析并且结果可用(在某种程度上)。


Handling the example library

Here's an example how to handle this made up library:

以下是如何处理这个组成库的示例:

$source = file_get_contents('http://www.somehost.com/some_page.html');
try {
    $parser = new HTMLParser(new DOMDocument());
    $parser->setSource($source)
           ->parse();
} catch (CriticalException $e) {
    // Library failed miserably, no recover is possible for it.
    // In this case, it's prorably my fault because I didn't pass
    // a DOMDocument object.
    print 'Sorry. I made a mistake. Please send me feedback!';
} catch (InvalidArgumentException $e) {
    // the source passed is not a string, again probably my fault.
    // But I have a working parser object. 
    // Maybe I can try again by typecasting the argument to string
    var_dump($parser);
} catch (EmptyStringException $e) {
    // The source string was empty. Maybe there was an error
    // retrieving the HTML? Maybe the remote server is down?
    // Maybe the website does not exist anymore? In this case,
    // it isn't my fault it failed. Maybe I can use a cached
    // version?
    var_dump($parser);
} catch (HtmlParsingException $e) {
    // The html suplied is malformed. I got it from the interwebs
    // so it's not my fault. I can use $e or getParseErrors() 
    // to see if the html (and DOM Object) is usable
    // I also have a full functioning HTMLParser Object and can
    // retrieve a "loaded" functioning DOMDocument Object
    var_dump($parser->getParseErrors());
    var_dump($parser->getDOMObj());
}
$var = 'this will print wether an exception was previously thrown or not';
print $var;

You can take this further and nest try catch blocks, chain exceptions, run selective code following a determined exception chain path, selective logging, etc...

您可以进一步采取这种做法并嵌套try catch块,链异常,在确定的异常链路径后运行选择性代码,选择性记录等等......

As a side note, using Exceptions does not mean that the PROGRAM execution will halt, it just means that the code depending of my object will be bypassed. It's up to me or the 3rd party developer to do with it as he pleases.

作为旁注,使用Exceptions并不意味着PROGRAM执行将停止,它只是意味着将绕过依赖于我的对象的代码。这取决于我或第三方开发人员随时随地使用它。

#7


2  

The idea of exception is elegant and makes the error handling process so smooth. but this only applies when you have appropriate exception classes and in team development, one more important thing is "standard" exceptions. so if you plan to use exceptions, you'd better first standardize your exception types, or the better choice is to use exceptions from some popular framework. one other thing that applies to PHP (where you can write your code object orienter combined with structural code), is that if you are writing your whole application using classes. If you are writing object oriented, then exceptions are better for sure. after all I think your error handling process will be much smoother with exception than trigger_error and stuff.

异常的想法很优雅,使错误处理过程如此顺利。但这仅适用于您有适当的异常类并且在团队开发中,更重要的是“标准”异常。因此,如果您计划使用异常,最好先标准化异常类型,或者更好的选择是使用某些流行框架中的异常。另一个适用于PHP的东西(你可以编写你的代码对象orienter结合结构代码),如果你使用类编写整个应用程序。如果您正在编写面向对象,那么异常肯定会更好。毕竟我认为你的错误处理过程会比trigger_error和stuff更加顺畅。

#8


1  

The Exceptions are the modern and robust way of signaling an error condition / an exceptional situation. Use them :)

异常是发出错误情况/异常情况的现代且可靠的方式。使用它们 :)

#9


-2  

Using exceptions are not a good idea in the era of 3rd party application integration.

在第三方应用程序集成时代,使用异常并不是一个好主意。

Because, the moment you try to integrate your app with something else, or someone else's app with yours, your entire application will come to a halt the moment a class in some 3rd party plugin throws an exception. Even if you have full fledged error handling, logging implemented in your own app, someone's random object in a 3rd party plugin will throw an exception, and your entire application will stop right there.

因为,当您尝试将应用程序与其他应用程序或其他人的应用程序集成在一起时,您的整个应用程序将在某个第三方插件中的类引发异常时停止。即使你有完整的错误处理,在你自己的应用程序中实现日志记录,第三方插件中某人的随机对象将抛出异常,你的整个应用程序将停在那里。

EVEN if you have the means in your application to make up for the error of that library you are using....

即使您的应用程序中有手段来弥补您正在使用的库的错误....

A case in example may be a 3rd party social login library which throws an exception because the social login provider returned an error, and kills your entire app unnecessarily - hybridauth, by the way. So, There you have an entire app, and there you have a library bringing in added functionality for you - in this case, social login - and even though you have a lot of fallback stuff in the case a provider does not authenticate (your own login system, plus like 20 or so other social login providers), your ENTIRE application will come to a grinding halt. And you will end up having to change the 3rd party library to work around these issues, and the point of using a 3rd party library to speed up development will be lost.

示例中的案例可能是第三方社交登录库,它会引发异常,因为社交登录提供程序返回了错误,并且不必要地杀死整个应用程序 - 顺便说一下,hybridauth。那么,你有一个完整的应用程序,你有一个库为你带来了额外的功能 - 在这种情况下,社交登录 - 即使你有很多后备的东西,提供商不认证(你自己的登录系统,再加上20个左右的其他社交登录提供商),您的整个应用程序将停止运行。并且您最终将不得不更改第三方库以解决这些问题,并且使用第三方库加速开发的重点将会丢失。

This is a serious design flaw in regard to philosophy of handling errors in PHP. Lets face it - under the other end of most of applications developed today, there is a user. Be it an intranet user, be it a user over internet, be it a sysadmin, it does not matter - there is generally a user.

对于PHP中处理错误的哲学而言,这是一个严重的设计缺陷。让我们面对它 - 在今天开发的大多数应用程序的另一端,有一个用户。无论是内联网用户,无论是互联网上的用户,还是系统管理员,都无所谓 - 通常都是用户。

And, having an application die on your face without there being anything you can do at that point other than to go back to a previous page and have a shot in the dark regarding what you are trying to do, as a user, is bad, bad practice from development side. Not to mention, an internal error which only the developers should know due to many reasons (from usability to security) being thrown on the face of a user.

并且,有一个应用程序死在你的脸上没有任何你可以做的事情,除了回到上一页并在黑暗中拍摄你想要做的事情,作为一个用户,是坏的,发展方面的不良做法。更不用说,只有开发人员应该知道的内部错误由于许多原因(从可用性到安全性)被抛到用户的脸上。

As a result, im going to have to just let go of a particular 3rd party library (hybridauth in this case) and not use it in my application, solely for that reason. Despite the fact that hybridauth is a very good library, and apparently a lot of good effort have been spent on it, with a phletora of capabilities.

因此,我将不得不放弃特定的第三方库(在这种情况下是hybridauth)而不是在我的应用程序中使用它,仅仅是因为这个原因。尽管hybridauth是一个非常好的库,并且显然已经花费了很多精力,并且具有功能上的phletora。

Therefore, you should refrain from using exceptions in your code. EVEN if the code you are doing right now, is the top level code that will run your application, and not a library, it is possible that you may want to include all or part of your code in other projects, or have to integrate parts or entirety of it with other code of yours or 3rd party code. And if you used exceptions, you will end up with the same situation - entire applications/integrations dying in your face even if you have proper means to handle whatever issue a piece of code provides.

因此,您应该避免在代码中使用异常。即使您现在正在执行的代码是运行应用程序的*代码,而不是库,您可能希望将全部或部分代码包含在其他项目中,或者必须集成部件或其全部与您的其他代码或第三方代码。如果你使用异常,你将会遇到同样的情况 - 即使你有适当的方法处理一段代码提供的任何问题,整个应用程序/集成也会在你的脸上消失。