Я сталкивался. Когда-то тоже ломал голову над этим вопросом, и не нашел однозначного ответа, потому что всякий способ имеет как сильные, так и слабые стороны. Пробовал разные варианты, включая велосипеды, возврат кода ошибки и даже возврат ассоциативных массивов типа {status, result}. Многие не рекомендовали бросать исключения, аргументируя тем, что исключение должно оставаться исключением, а не становиться бизнес-логикой (в том числе, когда параметры исключения передаются в его конструктор при его бросании, в зависимости от типа исключения). В целом же, на практике оказалось, что это достаточно удобно, уменьшает количество условий, проверок, код становится короче и читается проще, багов становится меньше. На скорости работы почти не отражается. В нескольких поздних проектах на php обработка ошибок модели была сделана похожим образом. При реализации rest-api на эту модель достаточно просто создаются контроллеры. Возможно у кого-то есть другой опыт и он поделится негативными впечатлениями от исключений, но после выбора такого подхода мне жалеть не приходилось. Так что, как разработчику, такой способ контроля ошибок вполне бы подошел.