This question: Best way to return status flag and message from a method in Java is similar to mine, however I would do it in PHP, not Java (which could make a slight difference here).
The problem:
There's a method that can have either a successful outcome (this may change to be more successful ones) or a "problematic" one. The latter means the operation failed, but it is also important to know why. Imagine a method of an Authentication class:
public function login($name, $password)
{
if (successful_authentication)
{
report success
}
else
{
report failure, explain why (e.g. wrong name/pass, user banned)
}
}
It would be trivial to return true and false for success and failure, but how to report the cause of failure?
Possible solutions:
Return true on success and a string on failure with an error code indicating the problem: with PHP it's possible this way to have nice clean blocks as follows:
$loginStatus = $auth->login('name', 'pass');
if ($loginStatus === true)
{
doSomething();
}
else
{
if ($loginStatus == 'wrong_login_data')
...
elseif ($loginStatus == 'banned')
...
// or with an array full of error messages:
echo $erroMessages[$loginStatus];
}
Return a general status (state) object: very elegant solution and also future-proof (no problem if the number of statuses varies or later additional data should be returned), maybe the best one:
$loginStatus = $auth->login('name', 'pass')
if ($loginStatus->isSuccess)
...
else
echo $errorMessages[$loginStatus->errorCode]; // $errorMessages as by the previous example
Either of the above two, but not with plain string but class constants:
$loginStatus = $auth->login('name', 'pass')
if ($loginStatus->isSuccess)
...
elseif ($loginStatus->errorCode == Auth::ERR_USER_BANNED)
...
With this it would be unnecessary to explain the error codes in the documentation and would feel more "natural" as well (at least for me).
The question:
What would you use (of the above ones or any other solution)? What have been proven on the long run to be a good way?
Thank you in advance!
This is how PEAR has been doing it for as long as I can remember. So this is a tried and tested method.
class LoginError {
private $reason;
public function __construct($reason)
{
$this->reason = $reason;
}
public function getReason()
{
return $this->reason;
}
}
function isError($response)
{
return ($response instanceof LoginError);
}
public function login($name, $password)
{
if (successful_authentication)
{
return true;
}
else
{
return new LoginError('The password is incorrect');
}
}
$loginStatus = login('name', 'pass');
if (!isError($loginStatus))
{
doSomething();
}
else
{
echo $loginStatus->getReason();
}
Throw an exception. If checking the return value is required, then any failure to do so will allow unauthorized logins. Failure to check for an exception will blow the whole thing up, which seems preferable in this case.
In less critical spots if I was doing a check against an object that already existed I might just return the result code and have a separate function to retrieve the message, but I wouldn't go out of my way to make something into an object just to use that technique. Otherwise I'd go with a status object containing the result code and message.
I would go with a variation of your "Return a general status (state) object" where the state is described by your auth object.
So $auth->login('name', 'pass') is a simple bool, and $auth->getState() is an enum or string (intended for end user perhaps) describing the state.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With