我的大脑开始受伤所以我决定在这里问。
我有一个数据对象Employee。 Getters,setter,formatters等我有一个管理器EmployeeManager,它处理数据库访问和其他事情。现在我在EmployeeManager中有一个大的验证块,但我一直想知道我是否可以将其中一些移动到setter。
例如,我现在有;
public function getSSN($bFormatted = true) {
return ($bFormatted) ? $this->format_ssn($this->SSN) : $this->SSN;
}
public function setSSN($s, $bValidate = false)
{
// If we're validating user entry, save a copy.
// Either way, store a trimmed version.
if ($bValidate): $this->SSNToValidate = $s; endif;
$this->SSN = str_replace('-', '', $s);
}
public function getSSNToValidate() { return $this->SSNToValidate; }
这是做什么的:
*当你设置一个SSN时,如果它是由系统完成的(比如从数据库中),那么它就是setSSN('123456789', false)
,因为SSN存储在数据库中没有破折号。
*当您从用户输入设置SSN时,它只是setSSN('123-45-6789')
,然后不仅修剪破折号,而且还存储要验证的原始版本(因为我想根据格式进行验证)
*当你得到一个SSN时,如果要求格式化(除了你写入数据库之外总是这样),它会根据Employee类中的另一个函数对其进行格式化。
所以我的问题是:我可以在这里将验证添加到setter,而不是依赖于Manager类中的单片验证函数吗?因为我开始不得不处理来自整个应用程序的错误,所以我决定暂时转移到一个中央的错误处理程序静态类,而不是每个管理器都维护自己的错误列表。
因此,我可以轻松地为此添加错误处理:
public function setSSN($s, $bFromUser = false)
{
if ($bFromUser && !$this->validateSSN($s))
{
ErrorHandler::add(array('ssn' => 'Invalid SSN entered'));
}
else
{
$this->SSN = str_replace('-', '', $s);
}
}
所以我想我的问题是:这是否有意义,或者我是通过将管理器中的验证(按需执行或者在写入数据库之前)移动到对象(将在执行时执行)来自我调整)?
这是一般的通用,我只是使用SSN作为一个很好的例子。
答案 0 :(得分:3)
您应该始终在创建对象或在对象中设置值时进行验证。这样,您始终可以保证有一个处于有效状态的对象。如果验证不在对象本身中,则无法保证对象将被验证。
对象外的示例验证:
在这种情况下,有一个错误,我们忘记验证SSN。
class EmployeeManager
{
function saveEmployee($employee)
{
//Oops, we forgot to validate SSN
$db->save($employee); //This is just SQL to persist the employee.
}
}
//Somewhere else in code...
$employee = new Employee();
$employee->setSSN("FredFlintstone"); //No validation is done here.
$employeeManager = new EmployeeManager();
$employeeManager->saveEmployee($employee); //This call will persist FredFlintstone because validation was missed.
对象内部的示例验证:
在这种情况下,employee对象验证其所有输入。这样我们就知道如果我们有员工的实例,那么其中的所有数据都是有效的。
class Employee
{
function setSSN($input)
{
if(strlen($input) != 9)
{
throw new Exception('Invalid SSN.');
}
//Other validations...
$this->ssn = $input;
}
}
//Somewhere else in code...
$employee = new Employee();
$employee->setSSN("FredFlintstone"); //This call will now throw an exception and prevent us from having a bad object.
$employeeManager = new EmployeeManager();
$employeeManager->saveEmployee($employee);
此外,您永远不应该允许创建未完全初始化的对象。如果说员工需要SSN,则不提供空构造函数。您的构造函数应该包含所有必填字段的参数(与我为清晰起见省略它们的示例不同)。
答案 1 :(得分:2)
基于服务的应用程序的一般经验法则是,在持久性之前不久,验证应始终始终发生在服务器端。您可以选择在客户端上执行验证,以获得更好的用户体验。但是,仅在客户端(即在您的setter中)执行验证是不安全的。永远不要依赖客户数据。
在进行基于客户端的验证时,每个类(无论是模型,视图模型,演示者等,取决于您的架构模式)最好自我验证,而不是依赖于某些外部验证器。