PHP exception handling interview questions, with answers
PHP's error handling has changed a great deal since PHP 5. Most fatal errors are now thrown as Error objects that code can catch, PHP 8 turned many warnings into exceptions, and the exception hierarchy has two separate branches. Interviewers ask how that hierarchy works, how to design custom exceptions, and how to handle failures without hiding them.
The answers below cover try, catch and finally, the Exception and Error branches, custom exceptions, catching several types, finally, chaining and error suppression, with code run on PHP 8.5. Then take the free PHP diagnostic — ten questions across every PHP topic in the bank — to see which of these you can explain but not yet predict.
The questions, with answers
1.How does exception handling work in PHP?
In short: Code that may fail runs in try; a thrown exception jumps to the first catch whose type matches; finally runs in every case.
throw new Exception("bad") stops the current code and unwinds the call stack until a try block with a matching catch clause is found. The catch receives the exception object, whose getMessage, getCode, getFile, getLine and getTrace methods describe the failure. A finally block runs after the try and any catch, whether an exception occurred or not, so it suits cleanup such as releasing a lock. If no catch matches anywhere, PHP ends the script with a fatal Uncaught error. Catch blocks are tried in order, so specific types must come before general ones.
try { throw new Exception("bad"); } catch (Exception $e) { echo $e->getMessage(); } finally { echo " / done"; } // bad / done
2.What is the difference between Exception and Error in PHP?
In short: Both implement Throwable; Exception is for failures application code expects to handle, while Error covers engine errors such as undefined functions and type errors.
Since PHP 7 the throwable hierarchy has two branches under the Throwable interface. Exception and its subclasses, such as RuntimeException and InvalidArgumentException, are for conditions that application code throws and expects to handle. Error and its subclasses, such as TypeError, ValueError, ArithmeticError and DivisionByZeroError, are thrown by the engine for what used to be fatal errors, such as calling an undefined function, as below. catch (Exception $e) does not catch an Error; catch (Throwable $e) catches both, which suits top-level handlers.
try { null_fn(); } catch (Error $e) { echo get_class($e); } // Error
3.How do you create a custom exception class in PHP?
In short: Extend Exception, or one of its subclasses, so callers can catch the specific failure by type.
A custom exception is a class that extends Exception or a more specific subclass, such as RuntimeException or DomainException. Even an empty class, class NoStock extends Exception {}, is useful, because callers can catch that type and let others pass. A custom exception can add properties and a constructor to carry details, such as the product that is out of stock, and a library usually gives all its exceptions a common base class or marker interface so users can catch everything it throws at once.
class NoStock extends Exception {} try { throw new NoStock("pen"); } catch (NoStock $e) { $m = $e->getMessage(); echo "out of $m"; } // out of pen
4.How do you catch several exception types in one catch block in PHP?
In short: List the types separated by |, as in catch (TypeError | DivisionByZeroError $e), available since PHP 7.1.
When different exceptions need the same handling, a multi-catch clause names them all, separated by a pipe, instead of repeating identical catch blocks. The caught variable then holds whichever type was thrown, so get_class or instanceof can still tell them apart. Since PHP 8.0 the variable can be omitted when the handler does not use it, as in catch (TimeoutException), which reads as an intentional choice. Types listed together should not be related by inheritance, since the parent alone would already cover the child.
try { intdiv(1, 0); } catch (TypeError | DivisionByZeroError $e) { echo "math"; } // math
5.When does a finally block run in PHP?
In short: Always after the try block and any catch, whether the try finished normally, threw, or returned early.
finally runs on every path out of a try block: after it completes normally, after a catch handles an exception, when an exception escapes uncaught, and even when the try block executes a return. In the code, return "try" is evaluated first, then the finally block prints cleanup, and only then does the function hand back its value, so cleanup appears before try. That makes finally the right place to close files, release locks and restore state, because an early return or an exception cannot skip it.
function save() { try { return "try"; } finally { echo "cleanup "; } } echo save(); // cleanup try
6.How do you chain exceptions in PHP?
In short: Pass the original exception as the third constructor argument, $previous; getPrevious then returns it, preserving the root cause.
When a low-level exception should be reported as a higher-level one, such as a PDOException becoming a RepositoryException, the new exception can wrap the old: new LogicException("high", 0, $low). The original stays reachable through getPrevious, so logs and error pages can show the whole chain from the high-level message down to the root cause. Losing the original exception while rethrowing is a common way to make failures hard to diagnose. The second argument is the exception code, an integer that is 0 unless the application uses codes.
$low = new Exception("low"); $high = new LogicException( "high", 0, $low); $p = $high->getPrevious(); echo $high->getMessage(); echo " <- ", $p->getMessage(); // high <- low
7.Why should you avoid the @ error-suppression operator in PHP?
In short: @ hides warnings for the expression it prefixes, which also hides real problems; ?? or an explicit check handles missing values cleanly.
Prefixing an expression with @ silences the warnings and notices it would raise, so @$missing["key"] returns null without complaint. It does not handle anything: the underlying problem remains, and a real bug in the same expression is hidden too. It also has a small performance cost. Since PHP 8, @ no longer silences fatal errors, and custom error handlers still receive the suppressed errors. For missing variables, keys and properties, the null coalescing operator ?? gives the same null without hiding anything else, as the second line shows.
$v = @$missing["key"]; var_dump($v); // NULL $w = $missing["key"] ?? null; var_dump($w); // NULL
How the diagnostic asks it
One question from the PHP bank, exactly as a sitting would show it. The bank has 3 on errors & exceptions and 30 across PHP.
What does this PHP code print?
try { echo intdiv(1, 0); } catch (Exception $e) { echo "exception"; } catch (Error $e) { echo get_class($e); }
- 1exception
- 2A warning, then 0
- 3DivisionByZeroErrorcorrect
- 4INF
PHP 7 split throwables into two trees under the Throwable interface: Exception, for errors application code expects to handle, and Error, for internal problems such as type errors and arithmetic errors. intdiv(1, 0) throws DivisionByZeroError, a subclass of ArithmeticError and therefore of Error, not of Exception, so the first catch does not match and the second prints the class name. exception assumes every throwable is an Exception. A warning and 0, or INF, describe PHP 7's behaviour for the / operator; since PHP 8, dividing by zero with / throws too. catch (Throwable $e) catches both trees.
Measure it
Reading answers tells you what’s true. A diagnostic tells you what you get wrong.
10 PHP questions across its topics, easy to hard, about fifteen minutes. You get a readiness figure with the arithmetic shown, the topics you missed named, and a practice set sized for today. Free: 1 diagnostic a month and 15 problems a day. No card.