The best place to start is the PHP manual page on Exceptions.
Exceptions are a mechanism of mandatory error handling - rather than setting a flag that subsequent code must actively check, throwing an exception aborts all running code until it reaches a matching catch block. If no catch block is found, the entire script exits.
catch blocks match using the same logic as the instanceof operator - you name a class or interface, and the exception must be the same class, a sub-class, or implement that interface. You then give a variable name - in your example $e, but it can be any name you like - and PHP assigns the exception to that variable and runs the content of the catch block.
Creating an exception is the same as creating any other object - you use the new operator. Once created, they can have properties and methods, including a default set which includes getMessage() and getCode(), which return values which were passed when originally constructed. Their special behaviour happens when you use the throw keyword.
So, the code you've shown:
- Runs some code that might throw an exception (
new PDO(...))
- Catches any exception matching
instanceof PDOException
- Looks up the "message" and "code" on that exception object
- Creates a new
PDOException object
- Throws that new exception
The result on its own is pretty much useless - in particular, steps 4 and 5 can be replaced by throw $e, which essentially means "I've looked at this exception, but decided it's still a problem; carry on looking for another matching catch block". That's occasionally useful if you want to do something between steps 3 and 4, such as logging or cleanup.
As pointed out in another answer it does remove the backtrace, which might otherwise expose credentials. That would be better handled by setting zend.exception_ignore_args=true in your PHP configuration. PHP 8.2 will also have a new facility that automatically hides certain parameters in backtraces.