改进PHP循环验证
我有一个执行验证的php脚本,我有一个代码块,它设置了4个需要相同验证的字段。我想实现的是,在这个代码块中,我可以设置键名、显示名和字段类型以及下面的设置代码,然后根据为每个字段类型设置的规则自动验证字段 下面是有问题的代码块:改进PHP循环验证,php,Php,我有一个执行验证的php脚本,我有一个代码块,它设置了4个需要相同验证的字段。我想实现的是,在这个代码块中,我可以设置键名、显示名和字段类型以及下面的设置代码,然后根据为每个字段类型设置的规则自动验证字段 下面是有问题的代码块: // key name => display name $fields = [ 'firstName' => 'First Name', 'lastName' => 'Last Name', 'compa
// key name => display name
$fields = [
'firstName' => 'First Name',
'lastName' => 'Last Name',
'companyName' => 'Company Name',
'companyAddress' => 'Company Address',
];
所以在这个模块中,我想设置键名、显示名和字段类型。目前我只得到了这四个字段。有没有办法实现我的愿望
这是我的全部代码:
function validate($formData)
{
// Initiate Array
$validationMSG = array(); // array to hold validation errors
// what to validate (basics, i.e. required fields)
// key name => display name
$fields = [
'firstName' => 'First Name',
'lastName' => 'Last Name',
'companyName' => 'Company Name',
'companyAddress' => 'Company Address',
];
//simple loop
foreach($fields as $name => $display){
if(empty($formData[$name])){
$validationMSG[$name] = "${display} is required.";
}
}
//and NOW wee can perform some specific tests:
$pname_exp = '/^[a-zA-Z0-9\_]{2,20}/';
if(isset($formData['firstName']) && !preg_match($pname_exp, $formData['firstName'])){
$validationMSG['firstName'] = 'First Name is not valid.';
}
if(isset($formData['lastName']) && !preg_match($pname_exp, $formData['lastName'])){
$validationMSG['lastName'] = 'Last Name is required.';
}
//removed company name and company address checks, because we are done with them in the loop.
// Validate state
if (!isset($formData['state'])) {
$validationMSG['state'] = 'State is required.';
}
// Validate city
if (!isset($formData['city'])) {
$validationMSG['city'] = 'City is required.';
}
// Validate Zipcode - If Field is Empty
if (!isset($formData['zipcode'])) {
$validationMSG['zipcode'] = 'Zipcode is required.';
}
// Validate emailAddress
if (!isset($formData['emailAddress'])) {
$validationMSG['emailAddress'] = 'Email Address is required.';
}
// Check if emailAddress is a valid email address
elseif (!filter_var($formData['emailAddress'], FILTER_VALIDATE_EMAIL)) {
$validationMSG['emailAddress'] = 'Email address is not valid.';
}
//Validate phoneNumber
if (!isset($formData['phoneNumber'])) {
$validationMSG['phoneNumber'] = 'Phone Number is required.';
}
//Validate phoneNumber
elseif (preg_match('/^[0-9-\s]+$/D', $formData['phoneNumber'])) {
$validationMSG['phoneNumber'] = 'Must be a valid phone number.';
}
// Validate message
if (!isset($formData['message'])) {
$validationMSG['message'] = 'Message is required.';
}
if (!empty($validationMSG)) {
return $validationMSG;
}
else {
$captcha = checkCaptcha($formData['g-recaptcha-response']);
if(!$captcha['isSuccess']){
$validationMSG['captcha'] = 'ReCaptcha is required.';
return $validationMSG;
}
//End of Validation Function
}
}
//testing
$input = ['firstName' => 'John'];
$errors = validate($input);
var_dump($errors);
你应该使用这样的方法。这是在循环中编写更好的验证检查的起点:
这里是一种进行验证的方法,同时仍然可以在重构时将格式提升为类型化类(例如,使用名称空间和依赖项注入等)。我将向您展示的是一种获取对象的方法,您可以基于公共命名构造验证消息负载
首先,创建一个名为userActions()
的常规php函数。这将用于(全局或在需要时作为include)调用和获取这些对象。这将返回一个结束
function userActions(): \Closure { ... }
接下来,您需要封装您的过程。我建议这样做:
$startUserRecord = static function(
string $firstName,
string $lastName,
string $companyName,
string $companyAddress
) {
return new class(...func_get_args()) {
private $payload = [];
private $firstName;
private $lastName;
private $companyName;
private $companyAddress;
public function __construct(
string $firstName,
string $lastName,
string $companyName,
string $companyAddress
) {
$this->payload = func_get_args();
$this->firstName = $firstName;
$this->lastName = $lastName;
$this->companyName = $companyName;
$this->companyAddress = $companyAddress;
}
public function validate(): array {
// Here is where you would actually validate this one message.
// Empty array means no validation messages (errors).
return [];
}
public function payload(): array {
return $this->payload;
}
};
};
// Other ones go here, too.
$saveUserProfile = static function() { ... };
$resetUserLogin = static function() { ... };
将它们关联到一起,这样我们就可以在我们的userActivities()
闭包中使用它们了:
$activities= [
'startUserRecord' => $startUserRecord,
'saveUserProfile ' => $saveUserProfile,
'resetUserLogin ' => $resetUserLogin,
];
现在,我将其命名为startUserRecord
,因为我需要创建一个命令名;给它取一个你想要的名字,但是我推荐动词+主语+上下文结构
静态检查适用于“string,integer”和其他低级类型检查,或者您现有的基于类的构造(例如,Email
value对象)。如您所见,值的验证发生在validate()
方法中
接下来,创建将返回的闭包,该闭包实际上允许您搜索并仅获取所需的命令对象:
return static function(/* autoset as $get */) use($activities) {
$get = func_get_args();
$find = static function($name) use(&$get) {
return in_array($name, $get);
};
$filtered = array_filter($activities, $find, ARRAY_FILTER_USE_KEY);
$found = [];
// Keep in the same order.
foreach($get as $name) {
$found[] = $filtered[$name];
}
return $found;
};
注意闭包上的use()
语句
这被放在userActivities()
函数声明中。现在,您可以调用并设置它,并通常使用您拥有的:
$fields = [
'firstName' => 'First Name',
'lastName' => 'Last Name',
'companyName' => 'Company Name',
'companyAddress' => 'Company Address',
];
$userActivities = userActions();
[$startUserRecord] = $userActivities('startUserRecord');
$activity = $startUserRecord(...array_values($fields));
if ($errors = $activity->validate()) {
throw new InvalidCommand($errors);
}
// Do something with $activity->payload().
注:
- 我没有修改有效载荷。您可以添加一个作用于有效负载的调节器/消毒剂方法,或者以某种形式返回对象的属性
- 我们正在使用
[$startUserRecord]
行进行解构。这允许您返回多个条目并将它们加载到它们自己的变量名中。例如:
[$saveUserProfile,$resetUserLogin] = $userActivites('saveUserProfile','resetUserLogin');
$startUserRecord(…数组_值($fields))
这称为扩展或splat操作(调用中的splat操作符:…
),并使每个数组项按顺序成为自己的独立参数。我在这里通过array\u values()
实现了这一点,但是最好是传入一个实际的数组,而不使用键,以便在所有情况下都保持顺序
以下是它们的组合:
这只是一个起点。改变它,做你需要做的,这会让你知道你能完成什么
例如,您可以将初始值设定项移动到with()
方法,并“自动加载”在userActivities()
函数中共享的小型基于闭包的验证器,例如声明的$validateEmail()
或$validatePhone()
闭包,然后使用($validateEmail,…)
并在该闭包中新建类($validateEmail,…)
在活动的上下文中共享这些内容。您所说的字段类型是什么意思?您能提供一个示例吗?我建议根据活动将数组转换为值对象,并实现一个公共接口(StartUserRecord implements Transport
),并在验证类型的属性上使用注释(@Assert\NotBlank
或@Assert\NotNull
,或自定义类型)。然后,您的validate(Transport$message)
函数运行验证并返回消息。请参阅Symfony Validator以获取示例:@weegee例如,firstName和lastName需要相同类型的验证,但phoneNumber需要不同类型的验证,与emailAddress相同,emailAddress甚至需要其他类型的验证。我想在代码块中指定那些“类型”。比如字符串、int和电子邮件?您可以使用类型声明:公共函数setName(string$name)
,或者在7.4属性类型中:公共字符串$name代码>这是使用类的好处。电子邮件和电话号码是约束而不是类型,因此您可能需要像Email
这样的自定义类,或者使用通用或自定义电子邮件约束(请参阅我提供的Symfony链接)。您实际上必须验证验证,这意味着所有构造都是完整的。这是源代码验证的一个起点,随着时间的推移,它可能会变得笨拙,尽管正如您所建议的,这是一个不错的起点。“不过,我会很快从它那里重构出来。”贾雷德法里什同意了!但是这种方法比@jucyva目前所做的要好得多。@JaredFarrish你能给我一个你的方法/建议的样本吗?@Rehmat你为什么要离开源代码验证点?我没有使用像laravel或symfony这样的框架。@jucyva你能再解释一下源代码验证吗?我没有建议你使用任何框架。这是纯粹的PHP。在今天之前,我已经考虑了一段时间了,所以这里有另一个重构,它有更多的健全性检查和一些很好的特性:基本思想是使用间接和匿名类(包括invocable闭包)进行原型化,这迫使您进行设置,而不仅仅是解决方案驱动的(而不是问题驱动的),通常是程序性的,结果。分离出一个抽象类,因此更容易理解:感谢providin