Reputation: 501
I have backend project in which there's own "parent-to-all exception" exists, something like this (also I have InvalidArgumentException derived from this exception):
class CaliException extends \Exception {
private $caliCode;
public function __construct(string $message = "", string $caliCode = self::UNDEFINED_CODE,
int $code = 0, Throwable $previous = null) {
parent::__construct($message, $code, $previous);
$this->caliCode = $caliCode;
}
function getCaliCode(): string {
return $this->caliCode;
}
}
It's clear from code above, that purpose of custom class is ability to keep string codes. Why do I need string codes? Because I have HTTP API which works in the following way:
So there's a problem. System above produces code like this:
class UsernameFormatException extends InvalidArgumentException {
public const USERNAME_FORMAT_UNDEFINED_CODE = "DM:USERCA:0001";
public function __construct(string $message = "", string $calistoCode = self::USERNAME_FORMAT_UNDEFINED_CODE,
int $code = 0, \Throwable $previous = null) {
parent::__construct($message, $calistoCode, $code, $previous);
}
}
class PasswordFormatException extends InvalidArgumentException {
public const PASSWORD_FORMAT_UNDEFINED_CODE = "DM:USERCA:0002";
public function __construct(string $message = "", string $calistoCode = self::PASSWORD_FORMAT_UNDEFINED_CODE,
int $code = 0, \Throwable $previous = null) {
parent::__construct($message, $calistoCode, $code, $previous);
}
}
class InvalidLastActivityTimestampException extends InvalidArgumentException {
public const INVALID_TIMESTAMP = "DM:USERCA:0003";
public function __construct(string $message = "", string $calistoCode = self::INVALID_TIMESTAMP,
int $code = 0, \Throwable $previous = null) {
parent::__construct($message, $calistoCode, $code, $previous);
}
}
class InvalidCreationTimestampException extends InvalidArgumentException {
public const INVALID_TIMESTAMP = "DM:USERCA:0004";
public function __construct(string $message = "", string $calistoCode = self::INVALID_TIMESTAMP,
int $code = 0, \Throwable $previous = null) {
parent::__construct($message, $calistoCode, $code, $previous);
}
}
As seen, for each invalid-argument-case I create new CaliException
-derived exception. I consider it as not cool. Is it good? How can I improve the code?
Bonus question: I read that I should throw \InvalidArgumentException
when it's a programmer's mistake, so an exception must be not caught. But in my code there's no \InvalidArgumentException
only my own version of this. Is it acceptable in the context of best practices and so on? And how to distinguish when it's a programmer's mistake and when it's mistake of user (invalid user input)? (After all, any invalid values passed to a function are invalid inputs relatively to this function)
Upvotes: 1
Views: 789
Reputation: 58444
From your description it seem that you are actually making something like a REST API. Or at least something inspired by that concept.
The thing about exceptions of InvalidArgumentException
is that, someone passed you 2nd or 3rd hand knowledge. Those exceptions must be caught, but not at domain entity or service layers. Instead, you catch them at the point .. well .. bootstrap-level, where you render a "pretty error json" response with all the headers and status codes.
As for your original question. Yes, having very specific exceptions is OK. Though, I would recommend instead of PasswordFormatException
to name it MalformedPassword
. Basically, ditche the *Exeception
suffix, for the same reason as you do not have class UserClass
suffix - it is worthless, PHP has namespaces now (since 2005 .. I think).
This is just a quick'n'drunk comment. I am not even sure it answers your question.
Upvotes: 1