Can you use try/catch to control logic?

← Can you use try/catch to control logic?

Ashterix

docs: English JsonRpcBundle docs, REST and MCP Bundle sections, package cards

en/articles/from-tg/architecture/try-catch.md new file +55 −0

Can you use try/catch to control logic?

A reader's question
  1. Can you use try catch to control logic? I've been using it so far, but today I came across a claim that it's not a good practice.
  2. How resource-intensive are nested try catch blocks? I read that try catch itself is "cheap", but throw requires a lot of resources. Is that true?

1. Can you use try/catch to control logic?

Yes, you can, and it's a perfectly workable approach. The question here isn't "right/wrong", but which philosophy is closer to you and what fits a particular architecture.

In fact, it's a very holy-war topic.

There's a camp that says "exceptions are only for exceptional situations", and there's a camp that calmly uses them as a flow control mechanism. And both approaches get along just fine.

Personally, I think it's a matter of convenience, not an absolute truth. The object-oriented approach is more convenient for me. IMHO, if code reads better, the approach has a right to exist.

An example:

try {
    $code = $repo->getByUrl($url);
} catch (NotFoundException) {
    $code = $this->generateAndSave($url);
}

In this situation it works naturally and clearly: "not there? create it". There's nothing wrong with catching a specific exception and doing fallback logic.

Problems start only when an exception is used instead of a plain if in the simplest places, or when a repository starts throwing exceptions where returning null is expected. But that's a question of code design.

2. Is throw really expensive?

Yes, that's true.

try/catch by itself costs almost nothing. You can even nest them — the overhead is negligible, but throw is expensive, because PHP generates a backtrace and creates a full-fledged Exception object, which eats CPU.

So:

  • If throw happens rarely — it's not a problem at all.
  • If "not found" becomes a normal execution path (often), then it's worth considering whether it's simpler to return null or a Result object — purely from a performance standpoint.

But even here everything depends on the context. If the load is small, the difference doesn't matter at all.

To sum up my position

  • You can use try/catch for logic. It's not a bad practice in itself, it's a matter of taste, style and team.
  • If code reads better, I'm always for it.
  • try/catch is cheap, throw is more expensive, but in real projects it rarely becomes a bottleneck.

If it's convenient for you and fits the architecture, keep using it.


First published in Ukrainian in the Telegram channel “Created to die” on November 14, 2025.