Who the hell is this guy? Ed van Beinum Arsing about with PHP for about 6 years @edvanbeinum http://www.edvanbeinum.com https://joind.in/talk/view/4959 Slides: http://bit.ly/ed-loves-exceptions 2
The 5 most important questions you have about Exceptions ★ What the hell is an Exception, really? ★ When should I throw an Exception? ★ Is there any PHP-specific craziness I should know about? ★ Why don’t some folk like Exceptions and what are the alternatives? ★ Are there any best practices when using Exceptions? 4
Where did they come from? Upon failure, functions could do one of three things ★ output parameters ★ set a global error variable ★ return a value 6 What the hell is an Exception, really?
The problems with return values ★ How do you differentiate between normal values and error values? ★ (AKA the Semipredicate Problem) ★ No stacktrace, no message, no context ★ Dealing with multiple function calls soon gets messy ★ Violates Command Query Separation 7
Can I get a definition? “Exceptions are specific means by which code can pass along errors or exceptional events to the code that called it” Code Complete 2, Steve McConnell 9 What the hell is an Exception, really? an alternative channel
I would hear this a lot “Exceptions are for unexpected events” The Pragmatic Programmer, Hunt & Thomas 10 What the hell is an Exception, really? throw new ZombiesErruptFromSidewalkException;
Let’s try that again “Exceptions are for incorrect circumstances” Just Now, Me 11 What the hell is an Exception, really? throw new BicycleOnSidewalkException;
Robustness v Correctness ★ Correctness is it better that the application returns correct data ★ Robustness is it better that the application carries on functioning 13 When should I throw an Exception?
Not enough Context Can we fix it? Yes. // Snippet from Zend_Rest_Client public function setUri($uri) { if ($uri instanceof Zend_Uri_Http) { $this->_uri = $uri; } else { $this->_uri = Zend_Uri::factory($uri); } return $this; } 14 When should I throw an Exception?
Not enough Context Can we fix it? No. // Snippet from Zend_Rest_Client private function _prepareRest($path) { // Get the URI object and configure it if (!$this->_uri instanceof Zend_Uri_Http) { throw new Zend_Rest_Client_Exception('URI object must be set before performing call'); } } 15 When should I throw an Exception?
// Snippet from Zend_Rest_Client public function setUri($uri) { if ($uri instanceof Zend_Uri_Http) { $this->_uri = $uri; } elseif ( ! is_numeric($uri)) { $this->_uri = Zend_Uri::factory($uri); } else { throw new Zend_Rest_Client_Exception('URI must be instance of Zend_Uri_Http or a String'); } } Are we losing Context? Are we passing on an error down the call chain? 16 When should I throw an Exception? // Snippet from Zend_Rest_Client public function setUri($uri) { if ($uri instanceof Zend_Uri_Http) { $this->_uri = $uri; } else { $this->_uri = Zend_Uri::factory($uri); } }
Are Exceptions being used for flow control? “...ask yourself “Will this code still run if I remove all the exception handlers?” If the answer is “no” then you maybe exceptions are being used in non- exceptional circumstances” The Pragmatic Programmer try { $this->getUser(); } catch (UserNotLoggedInException $e) { $this->redirect('/login'); } 17 When should I throw an Exception?
Terminate? “Am I prepared to end the program?” Exceptional Ruby, Avdi Grimm 18 When should I throw an Exception? ★ Uncaught exceptions will terminate your program
PHP: Errors v Exceptions Oh PHP is quirky. And bears defecate in wooded areas. ★ It has Exceptions ★ It has return codes 23 Is there any PHP-specific craziness I need to know about?
PHP: Errors v Exceptions One more thing... ★ If there are problems with POST upload... $_FILES['fileFieldName']['error']; 25 Is there any PHP-specific craziness I need to know about?
As a rule of thumb ★ Exceptions are thrown by ★ Us the programmer ★ The newer PHP5 components (PDO, DateTime, Sqlite, etc) ★ Errors are ‘triggered’ by the older procedural PHP core functions ★ Return values are returns from core functions when a non-exceptional event occurs 27 Is there any PHP-specific craziness I need to know about?
How to deal with Errors There are many functions that allow the programmer to interact with Errors set_error_handler('newErrorHandler'); restore_error_handler(); 28 Is there any PHP-specific craziness I need to know about?
protected function _loadFileErrorHandler($errNo, $errStr, $errFile, $errLine) { $this->_errorStr = $errStr; } protected function _parseIniFile($filename) { set_error_handler(array($this, '_loadFileErrorHandler')); restore_error_handler(); if ($this->_errorStr !== null) { throw new Zend_Config_Exception($this->_errorStr); } } 29 Is there any PHP-specific craziness I need to know about? $iniArray = parse_ini_file($filename, true); How Zend Framework deals with Errors
Other PHP ‘fun’ die(); exit(); If you post a tutorial on the internet about how to connect to a database you simply must use this. Please stop. ★ No context other than the string it was passed ★ Terminates immediately ★ Better to use Exceptions 30 Is there any PHP-specific craziness I need to know about?
The Suppression Operator // something might go wrong but I don't know what to do about it @$zombie->reanimate(); ★ The Suppression Operator sets ERROR_REPORTING to 0 executes the given function then reverts ERROR_REPORTING to its previous setting. ★ If a fatal Error occurs during the suppressed function, the program will terminate with no indication why. 33 Is there any PHP-specific craziness I need to know about?
SPL Exceptions Woo! But we forgot to document them. Exception LogicException BadFunctionCallException BadMethodCallException DomainException InvalidArgumentException LengthException OutOfRangeException RuntimeException OutOfBoundsException OverflowException RangeException UnderflowException UnexpectedValueException 34 Is there any PHP-specific craziness I need to know about?
Potential Problems ★ Invisible in the source code PHP has no throws keyword we must rely on @throws annotation or code inspection 36 Why not Exceptions and what are the alternatives?
Potential Problems ★ Create more paths through a function More complexity = more bugs "An Exception represents an immediate nonlocal transfer of control - it's a kind of cascading goto" The Pragmatic Programmer 37 Why not Exceptions and what are the alternatives?
Good Enough data If your application requires robustness over correctness then return 'good enough' data ★ Closest legal value ★ The next/previous piece of valid data ★ Neutral value 41 Why not Exceptions and what are the alternatives?
No-Raise API “In most cases the caller should determine how to handle an error not the the callee” The Practice of Programming, Kernighan & Pike 43 Why not Exceptions and what are the alternatives?
No-Raise API PHP’s cURL library does this. $ch = curl_init(); curl_setopt( $ch, CURLOPT_URL, "http://en.wikipedia.org/wiki/Zombie" ); $result = curl_exec($ch); $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch); if ($httpCode == 418) { throw new TeapotException(); } 44 Why not Exceptions and what are the alternatives?
Design By Contract Came from Eiffel DbC allows the programmer to define what is correct circumstances ★ pre-conditions: must be true for routine to work correctly ★ post-conditions: will be true after routine has worked correctly 46 Why not Exceptions and what are the alternatives?
So what about PHP? ★ PHP has an assert() function since PHP4 class Human{} class Zombie{} function eliminate($target) { assert('$target instanceof Zombie'); } eliminate(new Human); ★ But... it uses errors. Yuck. // PHP Warning: assert(): Assertion "$target instanceof Zombie" failed in zombie.php on line 6 47 Why not Exceptions and what are the alternatives?
So what about PHP? Checkout Stuart Herbert's ContractLib ★ No eval'ed strings ★ Throws Exceptions https://github.com/stuartherbert/ContractLib 48 Why not Exceptions and what are the alternatives?
Empty Catch block Either a problem in try {} block: ★ Why is it throwing an Exception for an unexceptional circumstance? Or a problem in the catch(): ★ Why doesn’t it handle the Exception? 50 Are there best practices when using Exceptions?
Subclassing Exceptions What’s the point? ★ Add context ★ You catch an Exception based on class ★ Not solely reliant on the Exception's message to provide information ★ Avoid namespace clashes if two libraries both throw \exception() 51 Are there best practices when using Exceptions?
Subclassing try { $olfactoryLib->detectBrains(); $motionLib->stumbleForward(); } catch (Exception $e) { // wait, which library threw that? } 52 Are there best practices when using Exceptions?
Subclassing try { $olfactoryLib->detectBrains(); $motionLib->stumbleForward(); } catch (OlfactoryLib_BrainsNotFoundException $e) { // rotate 90 degrees, retry } catch (MotionLib_ShoppingMallDoorBarricadedException $e) { // groan, press up against glass and wait } 53 Are there best practices when using Exceptions?
Appropriate Abstraction Level Watch out, it is quite easy to expose implementation details through Exceptions try { $human->getBrains(); } catch (FileNotFoundException $e) { error_log($e->getMessage()); } 54 Are there best practices when using Exceptions?
Finally... Exceptions: ★ Alternative communication channel for incorrect circumstances Before throwing them: ★ 'Are you prepared to end the program?' The crazy world of PHP failure handling Think about the alternatives Best practices 55
Further Reading Exceptional Ruby - Avdi Grimm Code Complete 2 - Steve McConnell The Pragmatic Programmer - Hunt & Thomas The Practice of Programming - Kernighan & Pike Exceptional PHP : Introduction To Exceptions - Brandon Savage How to use SPL Exception Classes - Jani Hartikainen Exceptions - Joel Spolsky Should a failed function return a value or throw an exception? - Jani Hartikainen Error codes or Exceptions? Why is Reliable Software so Hard? - Damien Katz Exception Best Practices in PHP 5.3 - Ralph Schindler 57
Further Reading Pear2 Exception Policy Comparing ContractLib to PHP's assert() - Stuart Herbert Design by Contract in PHP with Assertions - Luke Maciak Return False with prudence - David Winterbottom What are the principles guiding your exception handling policy? - Stackoverflow Effiel Presentations 58