44

When should I use InvalidArgumentException and when UnexpectedValueException? They look the same to me.

Note that one extends LogicException and the other one extends RuntimeException, so the difference shouldn't be so subtle IMO.

outis
  • 75,655
  • 22
  • 151
  • 221
ChocoDeveloper
  • 14,160
  • 26
  • 79
  • 117

3 Answers3

33

Looking closely at the descriptions on the manual pages:

InvalidArgumentException

Exception thrown if an argument is not of the expected type.

(The description was Exception thrown if an argument does not match with the expected value. until mid-2014, but was changed when PHP 5.6 got introduced)

UnexpectedValueException

Exception thrown if a value does not match with a set of values. Typically this happens when a function calls another function and expects the return value to be of a certain type or value[,] not including arithmetic or buffer related errors.

From this, we can conclude that InvalidArgumentException is intended to check types of arguments passed to a function, while UnexpectedValueException is intended to verify values vs valid value sets, possibly during the internal computations of a function (e.g. values returned from other functions).

Note that checking the values of arguments is kind of gray area here; arguably, since InvalidArgumentException extends LogicException, it should only handle situations which should lead directly to a fix in your code. Since throwing an exception in case of out-of-range input values can be a completely expected runtime behaviour, this leaves UnexpectedValueException (which extends RuntimeException) as the only candidate in such cases.

outis
  • 75,655
  • 22
  • 151
  • 221
  • 1
    http://php.net/manual/en/class.invalidargumentexception.php It says `type`, not value – R Sun Jul 13 '17 at 07:12
  • @SiteTester: Looks like the manual page was updated sometime in April 2013, after this answer was posted. Earlier versions (https://web.archive.org/web/20130317022714/http://php.net/InvalidArgumentException) had "value". – outis Aug 02 '17 at 21:44
  • @outis FWIW, pre-5.6 docs actually had a completely different, and IMVHO equally confusing/unclear wording. A real pity we still don't have a clear, extensive and well-documented set of common exceptions in SPL as of 2019... –  Oct 27 '19 at 21:48
20

I guess the largest difference is "argument" vs "value".

The way I see it is that InvalidArgumentException is for (passed) arguments, whereas UnexpectedValueException applies to (returned) values. Also there's a subtle but important difference between "invalid" and "unexpected" - which also explains why the first is LogicException and the second a RuntimeException.

For example: say i've got a function that utilizes the Twitter-api called: getLastMessageDate($userid): You pass a (numeric) user-id and it returns the date of the last message of that user as yyyy-mm-dd string.

Now, suppose I call this function with a string as argument instead of a number. At this point I can call an InvalidArgumentException, because the provided argument is invalid for this function. These checks can be done by logic - because a variable is either numeric or it is not. Therefore it's a LogicException.

However, the return value of a function may not be verifiable by logic - especially when you're dealing with (third-party) dynamic content. Because you can never know exactly what your function is going to return. (if you would, this would arguably render your function useless.)

So, this time I call my function with a (valid) user-id and my function gets the date of the last message of that user. With this date I would like to do something, like some formatting.

Now imagine the guys at Twitter did something wrong and instead of my expected yyyy-mm-dd date-string, I get an empty string or a different string saying 'blaaaa'. At this point, i can throw an UnexpectedValueException.

I can't say that this value is "Invalid" - I asked for a string and I got a string. But it is however not the "kind of string" i was expecting: therefore Unexpected ValueException.

Hope this clears something up. This is my first post - so far I've learned that writing down what's in my head isn't the easiest thing (also English is not my native language).

bartvanraaij
  • 323
  • 1
  • 8
  • _italic_ _"At this point I can call an InvalidArgumentException, because the provided argument is invalid for this function"_ You could also throw an UnexpectedValueException as you were expecting an integer but got an unexpected type (string). – rafark Dec 13 '19 at 02:56
15

My understanding is that InvalidArgumentException, being a LogicException, should be used if you check an argument against a fixed list of possible value ranges. For example, checking if user entered data contains only numbers. The program logic can be expected to handle these value ranges.

UnexpectedValueException, being a RuntimeException (errors that can only be found on runtime / cannot be detected at compile time), would be used for Exceptions that occur outside of foreseeable and specified input ranges (possibly as a last resort after the "logic" checks above).

The key to answering this question might be the Unexpected... in UnexpectedValueException. Unexpected means there is no handling for this value in the program logic. Invalid, on the other hand, suggests that this value has been handled.

ax.
  • 58,560
  • 8
  • 81
  • 72
  • 3
    +1. I typically find myself using `UnexpectedValueExpection` in the `default` case of `switch` statements (e.g. for the state in a FSM), which are supposed to handle a finite set of possible values. – FtDRbwLXw6 Sep 19 '12 at 15:48
  • @drrcknlsn, If the switched variable is derived from an argument though, you should also add an `InvalidArgumentException` check above the `switch` statement. – Pacerier Aug 03 '15 at 08:06
  • @drrcknlsn I think a `DomainException` would be even more suitable for that. – bzeaman Nov 14 '15 at 10:34
  • 1
    +0 - the docs clearly say (and the change made the things even clearer) that IAEx is about *type*, not *value*. A such, doing a check vs *a fixed list of possible value ranges* is an ab-use of this exception ATM. –  Oct 09 '18 at 09:59