Введение
Вам понадобится как минимум PHP 5.4+, чтобы этот ответ работал (как минимум, из-за синтаксиса массива).
Если цель состоит в том, чтобы сделать что-то вроде этого:
$filteredArray = filter_var_array($arrayToFilter, $filterInstuctionsArray);
... и использовать возвращаемые результаты базовых функций PHP (вместе с логикой принятия решений) для проверки длины (mb_strlen()
, strlen()
) строки, ключ в том, чтобы иметь отличные инструкции фильтра Array`. Чтобы передать аргументы вашей функции обратного вызова (для повторного использования, инкапсуляции, обобщения и т. д.), я считаю, что есть как минимум два сценария.
Сценарии
A) Формы класса/объекта.
'options' => [$this, 'callbackMethod']
'options' => [$this->object, 'callbackMethod']
'options' => [$object, 'callbackMethod']
B) процедурная форма.
'options' => 'callbackFunction'
Решения
1) Замените $this
или $object
в сценарии A на new
экземпляр объекта прямо здесь и сейчас, передав в любых аргументах его конструктор. Это кажется маловероятным, так как попахивает тесно связанным кодом.
В качестве альтернативы можно внедрить предварительно заполненный объект в какой-нибудь Validator
класс и запустить filter_input_array()
из этого Validator
класса. Таким образом, передача аргументов в callbackMethod
не требуется.
Or
2) Замените 'callbackFunction'
в сценарии B на анонимная функция PHP и реализовать синтаксис use
для передачи ей аргументов/ограничений из класса Validator
.
function ($value) use ($min, $max) {
$length = mb_strlen($value, 'UTF-8');
return ($length >= $min) && ($length <= $max);
}
Попытка №1: фильтрация массива инструкций с помощью анонимных функций
Вот последовательный пример работы со скалярными значениями.
$filterInstructionsArray[
'fName' = ['filter' => FILTER_CALLBACK,
'flags' => FILTER_REQUIRE_SCALAR,
'options' => function ($value) use ($min, $max) {
$length = mb_strlen($value, 'UTF-8');
return ($length >= $min) && ($length <= $max);}],
'lName' = ['filter' => FILTER_CALLBACK,
'flags' => FILTER_REQUIRE_SCALAR,
'options' => function ($value) use ($min, $max) {
$length = mb_strlen($value, 'UTF-8');
return ($length >= $min) && ($length <= $max);}]
];
Конечно, это нарушает принципы DRY. Таким образом, вы можете определить анонимную функцию как свойство класса Validator
(или просто присвоить ее переменной), что сделает ее именованным экземпляром объекта Closure
.
private $checkNameLength = function ($value) use ($this->nameMin, $this->nameMax) {
$length = mb_strlen($value, 'UTF-8');
return ($length >= $this->nameMin) && ($length <= $this->nameMax);
};
Or
$checkNameLength = function ($value) use ($min, $max) {
$length = mb_strlen($value, 'UTF-8');
return ($length >= $min) && ($length <= $max);
};
Итак, я надеюсь, что одно из двух сработает.
Попытка № 2: фильтрация массива инструкций с именованными анонимными функциями
$filterInstructionsArray[
'fName' = ['filter' => FILTER_CALLBACK,
'flags' => FILTER_REQUIRE_SCALAR,
'options' => [$this, 'checkNameLength']]
];
Or
$filterInstructionsArray[
'fName' = ['filter' => FILTER_CALLBACK,
'flags' => FILTER_REQUIRE_SCALAR,
'options' => 'checkNameLength']
];
Возможные осложнения
Экземпляры Closure
$this->checkNameLength
и $checkNameLength
являются объектами, а не обычными "методами/функциями". Но, если PHP не жалуется, я не буду мудрить. Я полагаю, можно попробовать определить функцию внутри анонимной функции.
$checkName = function ($value) use ($min, $max) {
function lengthTest($string, $min, $max){
$length = mb_strlen($string, 'UTF-8');
return ($length >= $min) && ($length <= $max);
}
};
Тогда ваш массив инструкций фильтра будет выглядеть так.
$filterInstructionsArray[
'fName' = ['filter' => FILTER_CALLBACK,
'flags' => FILTER_REQUIRE_SCALAR,
'options' => [$checkName, 'lengthTest']]
];
Или, наверное, это...
$filterInstructionsArray[
'fName' = ['filter' => FILTER_CALLBACK,
'flags' => FILTER_REQUIRE_SCALAR,
'options' => 'lengthTest']
];
Вывод
Существует лучший способ создать универсальную проверку длины строки, чем использование filter_var_array()
и анонимных функций PHP. Использование 'filter' => FILTER_VALIDATE_REGEXP
может упростить проверку длины отдельной строки, но не заменяет соблюдение принципов DRY. В конечном итоге у вас будет много инструкций в массиве инструкций фильтра, таких как this, просто для обработки длин строк в массиве ввода.
//If you just want to test only the lengths first, this is
//very inefficient. Assume each $regex is only checking string length.
$filterLengthInstructions = [
'fName' => ['filter' => FILTER_VALIDATE_REGEXP,
'flags' => FILTER_REQUIRE_SCALAR,
'options' => ['regexp' => $fNameRegex]],
'lName' => ['filter' => FILTER_VALIDATE_REGEXP,
'flags' => FILTER_REQUIRE_SCALAR,
'options' => ['regexp' => $lNameRegex]],
'company' => ['filter' => FILTER_VALIDATE_REGEXP,
'flags' => FILTER_REQUIRE_SCALAR,
'options' => ['regexp' => $comanyRegex]],
'address1' => ['filter' => FILTER_VALIDATE_REGEXP,
'flags' => FILTER_REQUIRE_SCALAR,
'options' => ['regexp' => $address1Regex]],
'address2' => ['filter' => FILTER_VALIDATE_REGEXP,
'flags' => FILTER_REQUIRE_SCALAR,
'options' => ['regexp' => $address2Regex]],
'zip' => ['filter' => FILTER_VALIDATE_REGEXP,
'flags' => FILTER_REQUIRE_SCALAR,
'options' => ['regexp' => $zipRegex]],
'website' => ['filter' => FILTER_VALIDATE_REGEXP,
'flags' => FILTER_REQUIRE_SCALAR,
'options' => ['regexp' => $urlRegex]],
'email' => ['filter' => FILTER_VALIDATE_REGEXP,
'flags' => FILTER_REQUIRE_SCALAR,
'options' => ['regexp' => $emailRegex]]
];
Это можно сделать, если вы пытаетесь создать чистый filter_input_array()
Validator
класс или подпрограмму. Но вам придется сделать несколько проходов filter_var_array()
с несколькими массивами инструкций фильтра (поскольку длина строки — не единственное, что что делает его действительным или недействительным).
Для website
и email
вы захотите воспользоваться преимуществами 'filter' => FILTER_VALIDATE_URL
и 'filter' => FILTER_VALIDATE_EMAIL.
В другое время вы захотите воспользоваться преимуществом 'filter' => FILTER_VALIDATE_IP
. Кроме того, особенно в случае email
, вы можете захотеть ограничить действительные адреса электронной почты подмножеством официального RFC с регулярным выражением. Чтобы сохранить чистоту, вы не стали бы помещать это регулярное выражение в файл $filterLengthInstructions
.
Фундаментальные причины желания изменить min_length
и max_length
— возможность один раз написать бизнес-логику и использовать ее везде.
Как минимум, я советую создать абстрактный суперкласс Validator
и определить один (1) метод, который проверяет длину строк.
Теперь вы можете разделить этот метод или делегировать эту задачу внедренному методу объекта StringTester
.
Как бы то ни было, но, определив конкретные дочерние классы Validator
, все, что вам нужно сделать, это определить параметры теста в массиве, создать цикл и вызвать:
$this->testString($string, $min, $max, $pattern, $errorMessage);
or
$this->stringTester->testString($string, $min, $max, $pattern, $errorMessage);
... внутри цикла. Обязательно учитывайте ошибку $errorMessage.
abstract Class Tester
{
}
class StringTester extends Tester
{
private function testString($string, $min, $max, $pattern, &$errorMessage)
{
$length = mb_strlen($string, 'UTF-8');
if($length < $min) //Test string against minimum length.
{
$errorMessage = 'Too small! ('.$min.' min, ' .$length. ' given.)';
}
elseif($length > $max) //Test string against maximum length.
{
$errorMessage = 'Too large! ('.$max.' max, ' .$length. ' given.)';
}
elseif(preg_match($pattern, $string) === 0) //Test string's pattern.
{
$errorMessage = 'Invalid string format!';
}
else
{
$errorMessage = ''; //The error message is the empty string.
}
return;
}
}
abstract Class Validator
{
//Arrays
protected $inputArray;
protected $errorMessagesArray = [];
protected $stringTestRulesArray; //I know. I know. :-)
//Objects
protected $stringTester;
//Abstract functions
abstract public function validate();
public function __construct(Tester $stringTester, array $inputArray, array $stringTestRutlesArray)
{
$this->stringTester = $stringTester;
$this->inputArray = $inputArray;
$this->stringTestRulesArray = $stringTestRulesArray
}
public function getInput()
{
return $this->inputArray;
}
public function getErrorMessages()
{
return $this->errorMessagesArray();
}
protected function validateStrings()
{
//Notice how input values correspond to error message elements via $key.
foreach($this->stringTestRulesArray as $key = $valuesArr)
{
$this->stringTester->testString($this->inputArray[$key], $valuesArr['min'], $valuesArr['max'], $valuesArr['pattern'], $this->errorMessagesArray[$key]);
}
return;
}
}
class ContactValidator extends Validator
{
public function __construct(Tester $stringTester, Sanitizer $sanitizer)
{
$stringTestRulesArray = [
'fName' => ['min' => 1, 'max' => 25, 'pattern' => '/[A-Za-z\' -]/'],
'lName' => ['min' => 1, 'max' => 40, 'pattern' => '/[A-Za-z\' -]/']
];
parent::__construct($stringTester, $sanitizer->getInput(), $stringTestRulesArray);
}
public function validate()
{
$this->validateStrings();
//Other, contact form specific validation stuff.
}
}
class RegisterValidator extends Validator
{
public function __construct(Tester $stringTester, Sanitizer $sanitizer)
{
$stringTestRulesArray = [
'fName' => ['min' => 1, 'max' => 30, 'pattern' => '/[A-Za-z\' -]/'],
'lName' => ['min' => 1, 'max' => 45, 'pattern' => '/[A-Za-z\' -]/']
];
parent::__construct($stringTester, $sanitizer->getInput(), $stringTestRulesArray);
}
public function validate()
{
$this->validateStrings();
//Other, register form specific validation stuff.
}
}
person
Anthony Rutledge
schedule
23.02.2017