A finally block that returns swallows the exception

The return expression is evaluated before finally runs, and the value is not handed to the caller until afterwards — so a finally that returns wins, silently.

function f(): int
{
    try {
        throw new RuntimeException('lost');
    } finally {
        return 2;      // the exception is gone. no trace, no log.
    }
}

// what finally is for:
try {
    $lock->acquire();

    return $this->work();
} finally {
    $lock->release();
}

A return inside finally discards both the original return value and any exception in flight, which turns a crash into a silently wrong result. Several static analysers flag it and most coding standards forbid it, for exactly this reason. Keeping the block to cleanup only — release, close, unlock — is what makes it predictable, and anything else in there is worth a second look.