The try-catch
PHP operator is very old, and we all know its syntax. But the confusing part is WHEN to use it. In what cases? In this tutorial, I will show practical examples to explain the answer.
Notice: this article is a try-catch
"practical summary", but if you want to dive deeper, we have a separate longer course Handling Exceptions and Errors in Laravel.
First Pair of Examples: Eloquent VS JSON Decode
Let me explain the try-catch
with two opposite examples.
Example 1: Eloquent. Take a look at this piece of code.
try { User::create($request->validated());} catch (Exception $e) { return redirect()->route('users.create') ->with('error', 'Operation failed: ' . $e->getMessage());}
It's a valid code in terms of syntax, but what is the probability of User::create()
throwing any Exception? Pretty low, right?
Also, if the data is invalid, it should be caught earlier, in the Validation phase.
Example 2: JSON. Compare it to this example from the Laravel framework core:
/** * Determine if a given value is valid JSON. * * @param mixed $value * @return bool */public static function isJson($value){ // ... some more code try { json_decode($value, true, 512, JSON_THROW_ON_ERROR); } catch (JsonException) { return false; } return true;}
Do you feel what is fundamentally different in this example? Two things:
- We cannot "trust" the
json_decode()
method because it was not created by us. We also can't trust the$value
because it may come from different user input. So, there's a high chance of an Exception happening. - Also, we want to specify what to do in case of that Exception: instead of showing the error on the screen, we tell that JSON is not recognized and return
false
. Then, whoever calls thatisJson()
method decides what to do next.
If you don't feel the difference, I will try to rephrase it.
Three MAIN Conditions to Use Try-Catch
Based on these examples above, here's how I would summarize, in what cases you should mostly use try-catch.
- You Call "Risky" Code: when your main code is an operation you don't fully control and is likely to throw an Exception. Examples: third-party APIs, external packages, filesystem operations.
- You've Already Validated Data: when the existing Laravel/PHP validation mechanism doesn't catch that Exception for you.
- You EXPECT the Exception: When you actually have a plan for what to do in case of that Exception, usually when catching a specific Exception.
In human analogy, it's like trying to drive from A to B without a map, with roughly knowing the route and the destination. Then, you TRY to drive there but prepare a plan B (insurance?) in case you get lost or crash somewhere.
I know, I know, maybe not the best analogy, but you get the idea :)
In other words, try-catch is used as an "insurance policy" in case of a higher risk of failure. That's why you should use it in specific cases when you actually need it. You wouldn't buy the accident insurance if you just go shopping near home, right?
What Do You Do in "catch"? 7+ Examples.
If you use try-catch
, you need to have a plan of what you do in case of Exception. So, it's time to look at more examples.
I've prepared a list of 7 different goals you may want to accomplish in case of exceptions happening.
The code examples come from the Laravel core framework itself. Let's learn from the best.
Goal 1. Return false
/NULL
or other "fallback" value
The most typical case I've found is when developers want to assign a default value to the method return, if something goes wrong. See this example:
src/Illuminate/Auth/Access/Gate.php:
class Gate implements GateContract{ // ... protected function methodAllowsGuests($class, $method) { try { $reflection = new ReflectionClass($class); $method = $reflection->getMethod($method); } catch (Exception) { return false; } if ($method) { $parameters = $method->getParameters(); return isset($parameters[0]) && $this->parameterAllowsGuests($parameters[0]); } return false; }
This method should return a bool
value, which may be true
only if the parameter is valid.
It returns false
in all the other cases:
- If the underlying
parameterAllowsGuests()
returnsfalse
- If the
$method
is empty - Or... if ANY Exception happens when getting that method
Also, that's an interesting example of so-called early return. So, the try-catch
mechanism doesn't necessarily have to cover the entire function; it may be used only in a specific part.
Another...