PHP 8.0: New ValueError Error Exception

Version8.0
TypeNew Feature

\ValueError is a new Exception type that extends \Exception class, and from PHP 8.0, you will be seeing lots of them! \ValueError exception is thrown when a value encountered is of correct type, but it cannot be used to continue the operation.

What about other exceptions?

PHP already has exceptions such as \InvalidArgumentException, \OutOfRangeException and \LengthException exceptions that convey a more precise error message.

However, exceptions is the keyword here: The new \ValueError exception extends \Error, instead of \Exception. While you can throw \ValueError exceptions in user-land code, PHP core functions will throw \ValueError exceptions except for a few specific cases (such as sprintf() function throwing \ArgumentCountError exceptions instead of the legacy Warning: sprintf(): Too few arguments warning).

Throwable
  ├── Error
  │     ├── TypeError
  │     ├── ValueError
  │
  └── Exception
        ├── LogicException
                ├── DomainException
                ├── InvalidArgumentException
                ├── LengthException
                └── OutOfRangeException

This is a simplified chart of PHP core \Error and \Exception. You can take a look at full PHP Exception hierarchy in this post.

From PHP 8.0 and forward, \ValueError errors will be thrown when the value passed to a function is of a valid type, but is not valid for the operation.

Examples

  • strpos() attempting to set a offset longer than the haystack length

    Before PHP 8.0:

    $a = strpos("s", "small", 16);
    // Warning: strpos(): Offset not contained in string in ... on line ...
    var_dump($a);
    // bool(false)

    From PHP 8.0

    $a = strpos("s", "small", 16);
    // Uncaught ValueError: Offset not contained in string in ...:...

  • range() with non-positive steps

    Before PHP 8.0:

    $a = range(1, 2, 0);
    // Warning: range(): step exceeds the specified range in ... on line ...
    var_dump($a);
    // bool(false)

    From PHP 8.0

    $a = range(1, 2, 0);
    // Uncaught ValueError: Step exceeds the specified range ...:...

  • array_rand() with an empty array

    Before PHP 8.0:

    $a = array_rand(array(), 0);
    // Warning: array_rand(): Array is empty in ... on line ...
    var_dump($a);
    // NULL

    From PHP 8.0

    $a = array_rand(array(), 0);
    // Uncaught ValueError: Array is empty in ...:...

But why?

The new \ValueError exception is introduced as part of the major change Internal function warnings now throw TypeError and ValueError exceptions, where you can find detailed information.

Polyfill

It is possible to polyfill this exception class by simply declaring a user-land class with the same name.

if (!class_exists('\ValueError')) {
    class ValueError extends \Error {
    }    
}

Note that this will not make internal PHP functions throw \ValueError exceptions when appropriate. However, if you have user-land code that needs to throw \ValueError exceptions, it is now possible with the polyfill.

Backwards compatibility impact

\ValueError is a new class, and unless you have user-land implementations, there should be no BC impact.


RFC Class introductionIndividual changes