Pasvl
Array Validator (regular expressions for arrays, sort of)
Install / Use
/learn @lezhnev74/PasvlREADME
PASVL - PHP Array Structure Validation Library
Think of a regular expression [ab]+ which matches a string abab. Now imaging the same for arrays.
The purpose of this library is to validate an existing (nested) array against a template and report a mismatch. It has the object-oriented extendable architecture to write and add custom validators.
Note to current users: this version is not backwards compatible with the previous 0.5.6.
Installation
composer require lezhnev74/pasvl
Example
Refer to files in Example folder.
Usage
Array Validation
// Define the pattern of the data, define keys and values separately
$pattern = [
'*' => [
'type' => 'book',
'title' => ':string :contains("book")',
'chapters' => [
':string :len(2) {1,3}' => [
'title' => ':string',
':exact("interesting") ?' => ':bool',
],
],
],
];
// Provide the data to match against the above pattern.
$data = [
[
'type' => 'book',
'title' => 'Geography book',
'chapters' => [
'eu' => ['title' => 'Europe', 'interesting' => true],
'as' => ['title' => 'America', 'interesting' => false],
],
],
[
'type' => 'book',
'title' => 'Foreign languages book',
'chapters' => [
'de' => ['title' => 'Deutsch'],
],
],
];
$builder = \PASVL\Validation\ValidatorBuilder::forArray($pattern);
$validator = $builder->build();
try {
$validator->validate($data);
} catch (ArrayFailedValidation $e) {
// If data cannot be matched against the pattern, then exception is thrown.
// It is not always easy to detect why the data failed matching, the exception MAY sometimes give you extra hints.
echo "failed: " . $e->getMessage() . "\n";
}
Optional String Validation
$pattern = ":string :regexp('#^[ab]+$#')";
$builder = \PASVL\Validation\ValidatorBuilder::forString($pattern);
$validator = $builder->build();
$validator->validate("abab"); // the string is valid
$validator->validate("abc"); // throws RuleFailed exception with the message: "string does not match regular expression ^[ab]+$"
Validation Language
This package supports a special dialect for validation specification. It looks like this:

Short language reference:
-
Rule Name Specify zero or one Rule Name to apply to the data. Optinal postfix
?allows data to benull. Refer to the set of built-in rules insrc/Validation/Rules/Library. For custom rules read below underCustom Rules. For example,:string?describes strings andnull. -
Sub-Rule Name Specify zero or more Sub-Rule Names to apply to the data AFTER the Rule is applied. Sub Rules are extra methods of the main Rule. For example,
:number :floatdescribes floats. -
Quantifier Specify quantity expectations for data keys. If none is set then default is assumed -
!. Available quantifiers:!- one key required (default)?- optional key*- any count of keys{2}- strict keys count{2,4}- range of keys count
For example:
$pattern = [":string *" => ":number"]; // the above pattern matches data: $data = ["june"=>10, "aug" => "11"];
Pattern Definitions
- as exact value
$pattern = ["name" => ":any"]; // here the key is the exact value $pattern = ["name?" => ":any"]; // here the key is the exact value, can be absent as well $pattern = [":exact('name')" => ":any"]; // this is the same - as nullable rule
$pattern = ["name" => ":string?"]; // the value must be a string or null - as rule with subrules
$pattern = ["name" => ":string :regexp('#\d*#')"]; // the value must be a string which contains only digits - as rule with quantifiers
$pattern = [":string {2}" => ":any"]; // data must have exactly two string keys
Compound Definitions
This package supports combinations of rules, expressed in a natural language. Examples:
:string or :number:string and :number(:string and :number) or :array
There are two combination operators: and, or.
and operator has precedence.
Both are left-associative.
Custom Rules
By default, the system uses only the built-in rules. However you can extend them with your own implementations. To add new custom rules, follow these steps:
- implement your new rule as a class and extend it from
\PASVL\Validation\Rules\Rule - implement a new rule locator by extending a class
\PASVL\Validation\Rules\RuleLocator - configure your validator like this:
$builder = ValidatorBuilder::forArray($pattern)->withLocator(new MyLocator()); // set your new locator $validator = $builder->build();
Built-in Rules
This package comes with a few built-in rules and their corresponding sub-rules (see in folder src/Validation/Rules/Library):
:string- the value must be string:regexp(<string>)- provide a regular expression(the same as forpreg_match()):url:email:uuid:contains(<string>):starts(<string>):ends(<string>):in(<string>,<string>,...):len(<int>):max(<int>):min(<int>):between(<int>,<int>)
:number:max(<int>):min(<int>):between(<int>, <int>):int- the number must be an integer:float- the number must be a float:positive:negative:in(<a>,<b>,<c>)- the number must be within values (type coercion possible):inStrict(<a>,<b>,<c>)- the number must be within values (type coercion disabled)
:exact(<value>):bool(<?value>)- the value must be boolean, if optional argument is given the value must be exactly it:object:instance(<fqcn>):propertyExists(<string>):methodExists(<string>)
:array:count(<int>):keys(<string>,<string>,...):min(<int>)- min count:max(<int>)- max count:between(<int>, <int>)- count must be within
:any- a placeholder, any value will match
Hints
- PHP casts "1" to 1 for array keys:
$data = ["12" => ""]; $pattern_invalid = [":string" => ""]; $pattern_valid = [":number :int" => ""]; - Technically speaking PASVL is a non-deterministic backtracking parser, and thus it can't always show you what exact key did not match the pattern. That is because, say, a key can match different patterns and there is no way of knowing which one was meant to be correct. In such cases it returns a message like "no matches found at X level".
🏆 Contributors
- Greg Corrigan. Greg spotted a problem with nullable values reported as invalid.
- Henry Combrinck. Henry tested the library extensively on real data and found tricky bugs and edge cases. Awesome contribution to make the package valuable to the community.
- @Averor. Found a bug in parentheses parsing.
- Julien Gidel. Improved
regexpsub-rule.
License
This project is licensed under the terms of the MIT license.
Related Skills
node-connect
346.4kDiagnose OpenClaw node connection and pairing failures for Android, iOS, and macOS companion apps
frontend-design
107.2kCreate distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.
openai-whisper-api
346.4kTranscribe audio via OpenAI Audio Transcriptions API (Whisper).
qqbot-media
346.4kQQBot 富媒体收发能力。使用 <qqmedia> 标签,系统根据文件扩展名自动识别类型(图片/语音/视频/文件)。
