When should I use Exception, InvalidArgumentException or UnexpectedValueException?
I don't know the real different between them as I always used Exception.
Different exceptions just give you more granularity and control over how you catch and handle exceptions.
Consider a class where you are doing many things - e.g. getting input data, validating input data and then saving it somewhere. You might decide that if the wrong or empty arguments are passed to the get() method, you might throw an InvalidArgumentException. When validating, if something is out of the ordinary or doesn't match up you could throw an UnexpectedValueException. If something totally unexpected happens you could throw a standard Exception.
This becomes useful when you are catching, as you can handle different types of exceptions in different ways. For example:
class Example
{
public function get($requiredVar = '')
{
if (empty($requiredVar)) {
throw new InvalidArgumentException('Required var is empty.');
}
$this->validate($requiredVar);
return $this->process($requiredVar);
}
public function validate($var = '')
{
if (strlen($var) !== 12) {
throw new UnexpectedValueException('Var should be 12 characters long.');
}
return true;
}
public function process($var)
{
// ... do something. Assuming it fails, an Exception is thrown
throw new Exception('Something unexpected happened');
}
}
In the above example class, when calling it you could catch multiple types of exceptions like so:
try {
$example = new Example;
$example->get('hello world');
} catch (InvalidArgumentException $e) {
var_dump('You forgot to pass a parameter! Exception: ' . $e->getMessage());
} catch (UnexpectedValueException $e) {
var_dump('The value you passed didn\'t match the schema... Exception: ' . $e->getMessage());
} catch (Exception $e) {
var_dump('Something went wrong... Message: ' . $e->getMessage());
}
In this case you get an UnexpectedValueException like this: string(92) "The value you passed didn't match the schema... Exception: Var should be 12 characters long.".
It should also be noted that these exception classes all end up extending from Exception anyway, so if you don't define special handlers for the InvalidArgumentException or others then they will be caught by Exception catchers anyway. So really, why not use them?
Related
So i'm trying to learn about exceptions. And i've come accross something people often do , but dont really explain why they do it and how it works. Maybe this is something that speaks for itself but I still dont get it, I apologize if this question might come over as a bad question.
Basically this is the code I'm working with:
catch(Exception $e) {
echo 'Message: ' .$e->getMessage();
}
What is $e where is this variable defined. I have an idea.
What i'm thinking is that you're assigning the exception object to the variable $e but i'm not sure. Shouldnt it be catch (Exception = $e) ?
It works pretty much the same as function parameters:
function foo(Bar $bar) { ... }
You use a type hint Bar followed by the parameter name $bar, and that declares the variable.
In the case of try..catch, that declaration happens in catch:
catch (Exception $e) { ... }
This uses the type hint Exception, which here is used to specify which kinds of exceptions the catch is supposed to catch. You can limit the catch to specific kinds of exceptions and/or define multiple different catch blocks for different kinds of exceptions. The exception itself is then available in the variable $e. You can use any arbitrary variable name here, just as for function parameters.
Uhm, now that i think about it, i have always considered the Exception $e to be the input for the catch() call.
As far as i know, you are not defining $e, as it is already thrown, you are just passing it to the catch() block, as you would do with a function name($input){}
In this code
catch(Exception $e) {
echo 'Message: ' .$e->getMessage();
}
The keyword Exception is the type for the parameter $e.
In PHP Exception is the base exception class that all exceptions derive from so that catch block is a catch-all for all exceptions.
i.e. You might want multiple handlers for different exception types before the catch-all:
try {
someOperation($parameter);
} catch(DatabaseException $e) {
echo 'Database Exception: ' .$e->getMessage();
} catch(Exception $e) {
echo 'General Exception: ' .$e->getMessage();
}
Here is my code:
try {
if ( condition 1 ) {
throw;
} else {
// do something
}
// some code here
if ( condition 2 ){
throw;
}
} catch (Exception $e) {
echo "something is wrong";
}
As you see, my catch block has its own error message, And that message is a constant. So really I don't need to pass a message when I use throw like this:
throw new Exception('error message');
Well can I use throw without anything? I just need to jump into catch block.
Honestly writing an useless error message is annoying for me.
As you know my current code has a syntax error: (it referring to throw;)
Parse error: syntax error, unexpected ';' in {path}
message parameter is optional in the Exception constructor. So if you don't have/want to put - just don't:
throw new Exception;
But you still must throw an instance of the Exception class (or a class that extends it), since it is a part of the php language syntax.
If you want all your exceptions to have the same message, you can extend it and define the message in your class:
class AmbiguousException extends Exception {
public function __construct($message = 'Something is wrong.', $code = 0, Exception $previous = null) {
parent::__construct($message, $code, $previous);
}
}
Then:
throw new AmbiguousException();
You can use the below throw everytime you need.
throw new Exception();
and catch will remain same as your code.
As stated in the PHP manual:
The thrown object must be an instance of the Exception class or a subclass of Exception. Trying to throw an object that is not will result in a PHP Fatal Error.
You can throw an exception without any message:
throw new Exception();
Perhaps something to help you from duplicating the same exception is as follows:
$e = new Exception('something is wrong');
try {
throw $e;
} catch (Exception $ex) {
echo $ex->getMessage();
}
You can create an instance with default message and then throw that instance.
$Exception = new Exception("some error message!");
try {
throw $Exception;
} catch (Exception $ex) {
var_dump($ex);
}
You cannot use the throw keyword on its own. However, you can use throw new Exception(); without specify the $message parameter, because it'll just fallback to the default message. Check out the Exceptions section in the PHP manual: http://php.net/manual/en/language.exceptions.extending.php
I have a problem where I want to catch all exception except descendants of my custom exception.
Maybe bad design, but here it is (Simplified and names changed, but the code is quite accurate):
function doStuff()
{
try {
// code
if (something) {
// manually throw an exception
throw StuffError("Something is bad.");
}
// a third-party code, can throw exceptions
LibraryClass::arcaneMagic();
} catch (Exception $e) {
throw new StuffError("Error occured while doing stuff: "
. $e->getMessage());
}
}
/** My custom exception */
class StuffError extends Exception
{
function __construct($msg) {
parent::__construct('StuffError: ' . $msg);
}
}
However, the issue here is that I don't want the try-catch to intercept the manually throws StuffError. Or, seamlessly rethrow it or something.
As it is now, I'd get:
StuffError: Error occured while doing stuff: StuffError: Something is bad.
I want just:
StuffError: Something is bad.
How would I do it?
You can have multiple catch clauses, and the first one that matches will be the one that runs. So you could have something like this:
try {
do_some_stuff();
}
catch (StuffError $e) {
throw $e;
}
catch (Exception $e) {
throw new StuffError(Error occurred while doing stuff: " . $e->getMessage());
}
But you might want to rethink wrapping stuff like this. It obscures the real cause of the error. For one thing, you lose the stack trace. But it also complicates error handling, since now someone can't differentiate exception types the way you're trying to do, short of trying to parse the exception message (which is rather an anti-pattern in itself).
I might be misinterpreting you, but I think this is what you're looking for:
...
} catch (Exception $e) {
if (get_class($e) == 'StuffError' || is_subclass_of($e, 'StuffError')) {
throw $e;
} else {
throw new StuffError("Error occured while doing stuff: "
. $e->getMessage());
}
}
...
Replace your catch statement with the code above. It checks to see if the exception is a StuffError or a child class of StuffError. I'm still very confused at why you would need to throw a StuffError exception after you catch, but maybe that's just some weirdness coming from translating/cleaning your code.
Since a short period of time I'm working with Try Catch in PHP. Now, every time a new error is thrown you get a fatal error on the screen, this isn't really user friendly so I was wondering if there's a way to give the user a nice message like an echo instead of a fatal error.
This is the code I have now:
public static function forceNumber($int){
if(is_numeric($int)){
return $int;
} else {
throw new TypeEnforcerException($int.' must be a number');
}
}
public function setStatus($status) {
try {
$this->status = TypeEnforcer::forceInt($status);
} catch (TypeEnforcerException $e) {
throw new Exception($e->getMessage());
} catch (Exception $e) {
throw new Exception($e->getMessage());
}
}
This is best solved with a frontend controller that is able to catch all uncatched exceptions:
<?php
require('bootstrap.php');
try {
$controllerService->execute($request);
} catch (Exception $e) {
$controllerService->handleControllerException($e);
}
You can then write code to return the internal server error because an exception signals an exceptional case so it normally is an 500 internal server error. The user must not be interested what went wrong other than it just didn't work out and your program crashed.
If you throw exceptions to give validation notices you need to catch those in a different layer (and you're probably doing it wrong if you use exceptions for that).
Edit: For low-level functions, because PHP is loosely typed, if a function expects and int, cast to intDocs:
public static function forceNumber($int){
$int = (int) $int;
return $int;
}
this will actually force the integer. In case the cast is not possible to do (e.g. $int it totally incompatible) PHP will throw the exception for you.
The example is a bit akward because by the method's name you use it to validate some number and provide an error if not (here wrongly with an exception). Instead you should do some validation. If you expect wrong input, it's not an exceptional case when wrong input is provided, so I would not use exceptions for that.
I am trying to understand what the best approach would be to handle Exceptions in the following scenario:
I have a class employee:
class employee extends person {
private $salary;
private $baseSalary = 6.5;
function __construct($f, $m, $l, $a,$fsalary=0){
if(!is_numeric($fsalary)){
throw new Exception("Age supplied is not a number", 114);
}
parent::__construct($f, $m, $l, $a);
$this->salary=$fsalary;
}
function GetDetails(){
return parent::GetName().
"<br/>".
$this->salary;
}
function __toString(){
return $this->GetDetails();
}
}
And using this:
try{
if(!$f = new employee("Sarah", "Sebastian", "Pira", "abc")){
throw new Exception();
}
else {
echo $f;
}
}
catch (Exception $e){
echo "<br/>";
echo var_dump($e);
}
Now I would think it would be a good idea to throw an exception in the class and then use just one catch block in all the scripts that would be using an employee object - But this doesn't seem to work - I need to have a try catch block within the class - Is this the correct way of looking at this?
Thanks
I think what you're saying is that you want to do something like this:
try {
class Employee extends Person {
// ...blah blah...
}
}
catch(Exception $e) {
// handle exception
}
...and then be able to insantiate it in other classes, without explicitly catching any exceptions:
// try { << this would be removed
$employee = new Employee();
// }
// catch(Exception $e) {
// (a whole bunch of code to handle the exception here)
// }
You can't do that, because then the try/catch block in the class will only catch any exceptions that occur when defining the class. They won't be caught when you try to instantiate it because your new Employee line is outside the try/catch block.
So really, your problem is that you want to be able to re-use a try/catch block in multiple places without re-writing the code. In that case, your best solution is to move the contents of the catch block out to a separate function that you can call as necessary. Define the function in the Employee class file and call it like this:
try {
$employee = new Employee();
$employee->doSomeStuff();
$employee->doMoreStuffThatCouldThrowExceptions();
}
catch(Exception $e) {
handle_employee_exception($e);
}
It doesn't get rid of the try/catch block in every file, but it does mean that you don't have to duplicate the implementation of the exception-handling all the time. And don't define handle_employee_exception as an instance method of the class, do it as a separate function, otherwise it will cause a fatal error if the exception is thrown in the constructor because the variable won't exist.
You should read more about Exceptions in PHP.
You can handle exceptions within the methods of the class, sure. But you should rethink how you want to do this and... why.
Good practice is also creating own exception class, so you are able to distinguish exceptions thrown by your module / class from the exceptions thrown by something else. It looks like that (see more):
class EmployeeModule_Exception extends Exception {}
and when it comes to throwing exception:
// the second parameter below is error code
throw new EmployeeModule_Exception('some message', 123);
Catching is similar, only the below example will catch only your module's exceptions:
try {
// some code here
} catch (EmployeeModule_Exception $e) {
// display information about exception caught
echo 'Error message: ' . $e->getMessage() . '<br />';
echo 'Error code: ' . $e->getCode();
}