我很难理解如何设计代码的错误处理部分。我最近问过一个类似的问题,我应该怎么做returning server error codes to the user, eg. 404 errors。我了解到我应该从应用程序的当前部分处理错误;看起来很简单。
但是,当我无法处理链中当前链接的错误时,我该怎么办?例如,我可能有一个用于管理身份验证的类。其中一种方法可能是createUser($username, $password)
。 编辑: 此方法将返回用户ID或用户对象。在该函数中,我需要确定用户名是否已存在。如果这是真的,我该如何提醒调用代码呢?返回null而不是用户对象是一种方法。但是,我怎么知道导致错误的原因呢?
我应该如何处理错误,以致调用代码可以轻松找出导致错误的原因?是否存在通常用于此类情况的设计模式?
编辑:我忘了提及:我正在使用PHP。
已解决:虽然很多人认为在这种情况下不应使用例外,但我得出结论认为这是最好的解决方案。
首先,除了例外之外,没有简单,优雅的替代方案。 (我认为如果没有内置于该语言的系统,就不可能......已经内置了异常。)
其次,回应“例外情况只应用于特殊情况,这不是一个”论点:"When I call getFoo(), I actually expect to get a Foo. If I don't get it, it's by definition an exceptional event."(通过,pkainulainen)
答案 0 :(得分:3)
有一些常见的模式:
1。抛出exception。
2。返回NULL或FALSE并设置传入的错误引用。 E.g。
function createUser($user, $password, &$error)
{
//...
// You could use any type of object here. This is just a simple example.
if(uniqueKeyFailure)
{
$error = new UserAlreadyExists();
return NULL;
}
//..
}
可以这样称呼:
$userCreateError = NULL;
$res = createUser($user, $pass, $userCreateError);
if($res === NULL)
{
// do something with $userCreateError
}
3。返回NULL或FALSE并提供get last错误(例如curl_error)。
我建议1或2.人们避免用户输入等“普通”错误的异常的主要原因是性能。关于此问题有相当多的讨论,例如Performance of try-catch in php。
我不推荐3,因为它不可重入。
答案 1 :(得分:1)
我经常通过在一些域对象(比如用户)中粘贴我的验证来处理这种事情。
例如:
<?PHP
$user->name = 'Joe';
$user->password = 'secret';
//try to save the user.
if (! $user->save()){
$errors = $user->getMessages();
// ... do something with error messages
}else{
//the user object set it's own ID.
$id = $user->id;
}
现在,很多东西都在用户背后抽象。那里可能有整个宇宙的物体,但这取决于你。
这里更大的问题是:为什么世界上你会有一个认证类创建用户?创建用户对象可能超出了身份验证的范围。
让authenticate($username,$password)
之类的方法返回类型为'user'的对象(代表刚认证的用户)可能是明智的,但即使这样也有点混乱。< / p>
相反,请考虑以下内容:
<?PHP
$auth = new AuthService();
$u = new User();
$u->username='Joe';
$u->password='secret';
$authResult = $auth->authenticate($user);
if ($authResult->success){
//$user has properties set as a side effect.
}else{
//find out why it failed.
$errors = $authResult->getErrors();
}
当然,这要求您为AuthService :: authenticate()定义某种结果值类以进行填充和返回。但至少你最终得不到有时会返回布尔值的方法,有时会返回对象等等。
答案 2 :(得分:0)
您可以返回在全局头文件中定义的整数,其名称如DUPLICATE_USER或INVALID_PASSWORD或适合您的用法。然后调用函数可以根据全局头声明轻松检查这些返回码,以确定发生了什么类型的错误。
答案 3 :(得分:0)
这必须以下列方式完成 -
创建一个错误对象,其中包含错误代码,错误文本和引发错误的方法。
传回错误对象。
你可以抛出异常,但异常是昂贵的
编辑 - 基于OP的编辑。在这种情况下,您将不得不抛回异常对象。
创建一个包含错误代码,错误描述,类名,方法名的异常类。抛回异常。
答案 4 :(得分:0)
如果您控制方法的返回类型,您还可以更改其签名以返回类似具有ErrorDescription属性和UserID或User对象属性的OperationResult对象。
答案 5 :(得分:0)
最简单的方法:如果验证通过则返回NULL,如果失败则返回错误消息。防止需要生成错误类或异常。也是表现最好的。
例如
function numeric($input) {
if (!is_numeric($input)) return 'Must be numeric.';
return NULL;
}
function usernameavailable($input) {
//query database....
if ($result) return 'Username already taken, please choose another one.';
return NULL;
}
您也可以使用带参数的函数:
function length($input, $min, $max) {
if (strlen($input) < $min) return "Must be longer than $min characters.";
if (strlen($input) > $max) return "Must be shorter than $max characters.";
return NULL;
}
验证整个表单中的每个元素非常容易。只需遍历所有元素,调用该元素的所有验证函数并收集错误字符串(如果有)。如果没有错误字符串,则所有用户输入都有效。
我强烈反对其他一个答案提出的建议。无效的用户输入不是例外的,不需要例外或错误。它只是一个预期的用例,必须以最简单的方式处理。
使用此方法,您可以非常轻松地构建Form类,并简单地使用参数作为验证函数来实例化元素。您还可以对其进行扩展,以包括将异步请求发送到完全相同的PHP验证函数的AJAX验证。
我的框架示例:
$Form = new AjaxForm();
$Form->add(new TextBox('Username', 'usernameavailable|length[3,12]'));
$Form->add(new SubmitButton());
只有三行,我创建了一个功能齐全的表单,包括客户端和服务器端验证。当然所有细节都取决于你,但我仍然认为应该预期无效的用户输入而不是特殊的。
答案 6 :(得分:-2)
在调用createUser()方法之前,您需要检查用户名是否存在。如果不这样做,或者在检查和调用createUser()之间发生了某些事情,则抛出异常。它远没有那么昂贵。
是否有成本?是。这件事重要吗?很可能没有。