41

In PHP, I sometimes catch some exceptions with try/catch :

try {
    ...
} catch (Exception $e) {
    // Nothing, this is normal
}

With that kind of code, I end up with the variable $e that is created for nothing (lots of resources), and PHP_MD (PHP Mess Detector) creates a warning because of an unused variable.

yivi
  • 23,845
  • 12
  • 64
  • 89
Matthieu Napoli
  • 42,736
  • 37
  • 154
  • 239
  • 3
    An exception should not be treated as "normal" - either it's an exception or not. What's throwing the exceptions? – John Parker Jan 27 '11 at 18:21
  • I'm testing that the model is throwing an exception when it should. So I have empty catch block because I just want to test that the exception was thrown. – Matthieu Napoli Jan 28 '11 at 14:03

7 Answers7

16

Starting with PHP 8, it is possible to use a non-capturing catch.

This is the relevant RFC, which was voted favourably 48-1.

Now it will be possible to do something like this:

try {
    readFile($file);
} catch (FileDoesNotExist) {
    echo "File does not exist";
} catch (UnauthorizedAccess) {
    echo "User does not have the appropriate permissions to access the file";
    log("User attempted to access $file");
}

With this, for some edge cases where the exception details are not relevant and exception type already provides all the necessary context, it will be possible to catch the exception without creating a new variable.

MAChitgarha
  • 2,189
  • 2
  • 19
  • 30
yivi
  • 23,845
  • 12
  • 64
  • 89
14

You can with PHP 8 @see

PHP 5,7

No, but you can unset it.

try {
    ...
} catch (Exception $e) {
    // Nothing, this is normal
    unset($e);
}

If it is PHPMD causing this issue then you can suppress the warning.

PHPMD suppress-warnings

class Bar {
    /**
     * This will suppress UnusedLocalVariable
     * warnings in this method
     *
     * @SuppressWarnings(PHPMD.UnusedLocalVariable)
     */
    public function foo() {

        try {
            ...
        } catch (Exception $e) {
            // Nothing, this is normal
            unset($e);
        }
    }
}

I'm assuming you are only catching the exception because you need to not because you want to. With PHP 5,7 you have to use a catch if you want to use try and if you use a catch you have to declare a variable.

TarranJones
  • 3,420
  • 1
  • 31
  • 46
7

That's the whole point of exceptions - you can have multiple different catch blocks to catch any exceptions you'd want to handle. The exception's data has to be assigned somewhere, hence the variable. You could just do something like unset($e) inside the catch block if you really don't want to see those warnings... or disable the warnings (generally a bad idea).

Marc B
  • 340,537
  • 37
  • 382
  • 468
7

No.

In any case, it's generally a bad idea to catch an exception and do nothing; exceptions exist precisely to force you to handle the exceptional circumstance (otherwise execution is aborted), so it's comprehensible the language doesn't facilitate such a use case.

Artefacto
  • 90,634
  • 15
  • 187
  • 215
  • 5
    At the same time, it is generally a bad idea to throw an exception when you probably just need a status code. If exceptions were actually exceptional we wouldn't see so many useless try/catch blocks. In particular, a lot of network utilities throw exceptions whenever there is a network issue, which breaks encapsulation and doesn't really help the programmer. A network problem shouldn't exceptional when you are a network utility, you should be able to handle it internally. – Roger Halliburton Jan 27 '11 at 20:09
7

I disagree fundamentally with Marc B's and Artefacto's answers. There are cases where ommitting the catch is better or even the only option. Especially when using external libraries (where you have no control over what exceptions are thrown) and/or async operations.

For example:

I want to create a file only if it doesn't exist yet. I'm using an external I/O library. Imagine it has File::exists($fileName) and File::create($fileName) methods.

Option 1 (if ommitting the catch was possible):

try {
    File::create($fileName);
}
// Go on with the rest of the code.

Option 2 (without try/catch):

if (!File::exists($fileName))
    File::create($fileName);

Here, option 1 is perfectly valid, since option 2 has two important issues:

  1. If multiple threads are running and going through this code section at the same time, it could be that thread A first checks if the file exists. Next, thread B checks if the file exists. They both find that it doesn't exist. Thread A creates the file. Thread B then attempts to create it again and throws an exception even though you're using the if check.
  2. It's very likely that the library itself already performs the !File::exists($fileName) check. Therefore you're wasting a call that is already made.

Note that if File::create throws other exceptions that might be unexpected it would be good to catch those.

Conclusion

Stating that something is never a good idea, is almost never a good idea. There are always exceptions (hehe) to the rule. Like any convention or design pattern, it's just a rule of thumb meant to help less experienced developers make the right decision.

Wouter Florijn
  • 2,181
  • 1
  • 18
  • 35
  • You should at least log that exception occurred. Not doing anything in catch blocks creates 'black holes' in your code - something is not working and you don't know why - and there is no way for you to trace it other than running debugger line by line until problem occurs. – superrafal Jan 23 '19 at 17:40
  • 2
    @superrafal that's not the case in my example at all. I know exactly what exception is thrown, and want to ignore it and move on. Why would I need to log every time something harmless and predictable happens? – Wouter Florijn Jan 28 '19 at 23:12
0

Yes, you can do it since PHP 8.0. If you want to catch all exceptions you can use Throwable.

try {
    ...
} catch (Exception) {
    // Exception
} catch (Throwable) {
    //All other classes implementing Throwable interface
}
Jsowa
  • 4,188
  • 4
  • 23
  • 35
-3

Exceptions are not only used for exceptional circumstances.

This scenario actually uses exceptions to make sure the user is logged out. At this point in the script it's very resource expensive to figure out what data should be pruned so it's actually faster to just prune it all and catch the exceptions.

        try {
        GDS::$DB->exec('DELETE FROM sessions WHERE session_id = ' . session_id());
        GDS::$DB->exec('DELETE FROM sessions WHERE user_id = ' . $this->data['user_id']);
    } catch(PDOException $ex) {}
    session_regenerate_id(true);
    setcookie('bis_[user_id]', 0, time() - 1, null, null, false, true);
    setcookie('bis_[session_start]', 0, time() - 1, null, null, false, true);
    setcookie('bis_[session_time]', 0, time() - 1, null, null, false, true);