Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:67277 Return-Path: Mailing-List: contact internals-help@lists.php.net; run by ezmlm Delivered-To: mailing list internals@lists.php.net Received: (qmail 50087 invoked from network); 2 May 2013 22:00:55 -0000 Received: from unknown (HELO lists.php.net) (127.0.0.1) by localhost with SMTP; 2 May 2013 22:00:55 -0000 Authentication-Results: pb1.pair.com header.from=adamjonr@gmail.com; sender-id=pass Authentication-Results: pb1.pair.com smtp.mail=adamjonr@gmail.com; spf=pass; sender-id=pass Received-SPF: pass (pb1.pair.com: domain gmail.com designates 209.85.220.180 as permitted sender) X-PHP-List-Original-Sender: adamjonr@gmail.com X-Host-Fingerprint: 209.85.220.180 mail-vc0-f180.google.com Received: from [209.85.220.180] ([209.85.220.180:48447] helo=mail-vc0-f180.google.com) by pb1.pair.com (ecelerity 2.1.1.9-wez r(12769M)) with ESMTP id 42/52-37535-512E2815 for ; Thu, 02 May 2013 18:00:54 -0400 Received: by mail-vc0-f180.google.com with SMTP id hv10so970910vcb.11 for ; Thu, 02 May 2013 15:00:50 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=mime-version:x-received:date:message-id:subject:from:to :content-type; bh=Jc5sjlqAu8hC9lcdo2qQWkLYD4pqR5dhgxahR5+B/YY=; b=rKu3xGlKRysWV6D7hLjmkejGrzo37GLDjsz6tQgjgieu7OMd/AQX2M1WhDiHY0Ppi3 bzW/i7qypZmZNWWV1OL24XrneU1+2cx0fbqWDC05hsqKvCJTzCWxP79d4opGTXvTSJew bwnFzcHqxr3LuxOxTRa2AGoWzd7x3DC9yA/T6RbTxkIyaul3tO0gqrkrvbUjO9i3yrnx NMXweSZMBa37xjWdQOSwPu7xxbfZWOV1f+fjxayRn8RTdl35tnt/dQGELJQ1eq0d6zBb buLgCY9UmkSqeD3v9FkjG/iaqrVbhQgXMS32OUhQ2U+HNfXLYK66PKwi7ZtuZ1IPKL/V ndyQ== MIME-Version: 1.0 X-Received: by 10.220.192.3 with SMTP id do3mr2880131vcb.16.1367532050500; Thu, 02 May 2013 15:00:50 -0700 (PDT) Received: by 10.220.157.5 with HTTP; Thu, 2 May 2013 15:00:50 -0700 (PDT) Date: Thu, 2 May 2013 18:00:50 -0400 Message-ID: To: "internals@lists.php.net" Content-Type: text/plain; charset=ISO-8859-1 Subject: A better error handling approach. From: adamjonr@gmail.com (Adam Jon Richardson) PHP currently has two separate approaches to handling errors: - Errors - Exceptions Both have their issues. Using and responding to errors requires that the returned value (if there is one) perform double duty as both a potential valid response AND, in the case of error, a flag that something went wrong. It's easy to forget to check that a particular call succeeded and specifically handle the error. I find myself constantly revisiting the documentation to ensure I know the specific error flag for functions, and performing post-hoc analysis of error logs to make sure I didn't miss an error flag that I would be better served by handling in the standard flow of my app. Using and responding to exceptions is a heavy-handed approach, as any particular exception can bring the entire application down. Additionally, the process of raising and catching exceptions loses context of the error, often requiring many different subclasses of exceptions to maintain the error state. Issues arise when the language constructs for exceptions are liberally used in situations that are not truly "exceptional," and where the the exception handling becomes a glorified goto. I've been programming in Go, and the ability to pass back multiple arguments, one of which is conventionally the error state, is wonderful. It's simple, clear, concise, and powerful. The code calling into the error-capable function knows the context and can handle errors appropriately according to the application requirements. In PHP, we could provide the ability to automatically pack up a comma-separated list of values as an array: return $var1, $var2; // returns [$var1, $var2]; And, we could provide the ability to automatically unpack an array into separate variables: $var1, $var2 = myFunction(); // same as list($var1, $var2) = myFunction(); This functionality would allow us to embrace the convention that an error is passed back as one of the return values: $dbh, $err = db\connect(); // check for error if ($err) { // handle db connection error } // carry on normally $dbh->query("blah blah blah"); The simplicity (just passing back values), clarity (the code to handle errors is proximal to the code that caused the error), and efficiency (not having to create bunches of exception subclasses to maintain context/information, and exceptions are expensive) of this approach is a beautiful thing. You can see an explanation of Go error handling here: http://blog.golang.org/2011/07/error-handling-and-go.html Concern 1: Isn't this just saving a few keystrokes? Allowing developers to pass back an array and then access the members of the array isn't the same thing, and we're not just saving a few keystrokes if this is implemented. Providing this ability promotes usage and clarity, and I'm confident Go would not have gotten developers to follow this convention if the syntax didn't facilitate the approach. I now write my Python code to handle errors in this same manner, taking advantage of its ability to handle comma-separated lists as tuples (something I didn't know about until recently, I must confess): http://stackoverflow.com/questions/423710/return-more-than-one-value-from-a-function-in-python Concern 2: Why don't you just use Python or Go? I really like using PHP for web development. Concern 3: Are you saying we should get rid of errors and exceptions? To be clear, errors have their place (maybe an extension failed to load, or a warning about usage of undeclared vars, etc.), and so do exceptions (for events that are truly "exceptional", that should cause a major revision to the branching/flow of the application and/or stop the application in its tracks if left unhandled.) Adam