Baike.dev
All toolsOnline toolsAI codingTrendingOpen sourceNewsSubmit
Log in
< Back to tools
S

schema

> 编程语言
Open source

Validating data structures against a given Schema.

1.0K stars0 likes1 views
WebsiteGitHub

About

Validating data structures against a given Schema.

Nette Schema

Introduction

A practical library for validating and normalizing data structures against a given schema with a smart, easy-to-understand API.

Documentation can be found on the website.

Installation:

bash
composer require nette/schema

It requires PHP version 8.1 and supports PHP up to 8.5.

Support Me

Do you like Nette Schema? Are you looking forward to the new features? Thank you!

Basic Usage

In the variable $schema, we have a validation schema (we'll explain what this means and how to create one in a moment), and in the variable $data, we have the data structure we want to validate and normalize. This could be, for example, data submitted by a user via an API, a configuration file, etc.

The task is handled by the Nette\Schema\Processor class, which processes the input and either returns normalized data or throws a Nette\Schema\ValidationException exception if an error occurs.

php
$processor = new Nette\Schema\Processor;

try {
	$normalized = $processor->process($schema, $data);
} catch (Nette\Schema\ValidationException $e) {
	echo 'Data is invalid: ' . $e->getMessage();
}

The method $e->getMessages() returns an array of all messages as strings, and $e->getMessageObjects() returns all messages as Nette\Schema\Message objects.

Defining the Schema

And now let's create the schema. The class Nette\Schema\Expect is used to define it; we essentially define expectations for what the data should look like. Let's say the input data must be a structure (e.g., an array) containing elements processRefund of type bool and refundAmount of type int.

php
use Nette\Schema\Expect;

$schema = Expect::structure([
	'processRefund' => Expect::bool(),
	'refundAmount' => Expect::int(),
]);

We believe the schema definition looks understandable, even if you're seeing it for the first time.

Let's send the following data for validation:

php
$data = [
	'processRefund' => true,
	'refundAmount' => 17,
];

$normalized = $processor->process($schema, $data); // OK, passes validation

The output, i.e., the value $normalized, is a stdClass object. If we wanted the output to be an array, we would add casting ->castTo('array') to the schema.

All elements of the structure are optional and have a default value of null. Example:

php
$data = [
	'refundAmount' => 17,
];

$normalized = $processor->process($schema, $data); // OK, passes validation
// $normalized = {'processRefund' => null, 'refundAmount' => 17}

The fact that the default value is null does not mean it would accept 'processRefund' => null in the input data. No, the input must be a boolean, i.e. true or false only. We would have to explicitly allow null using Expect::bool()->nullable().

An item can be made mandatory using Expect::bool()->required(). We can change the default value, for example, to false using Expect::bool()->default(false) or shorthand Expect::bool(false).

And what if we wanted to accept 1 and 0 in addition to booleans? Then we list the values that we also want to normalize to boolean:

php
$schema = Expect::structure([
	'processRefund' => Expect::anyOf(true, false, 1, 0)->castTo('bool'),
	'refundAmount' => Expect::int(),
]);

$normalized = $processor->process($schema, $data);
is_bool($normalized->processRefund); // true

Now you know the basics of defining a schema and how the structure items behave. We will now show what other elements you can use when defining a schema.

Data Types: type()

All standard PHP data types can be specified in the schema:

php
Expect::string($default = null)
Expect::int($default = null)
Expect::float($default = null)
Expect::bool($default = null)
Expect::null()
Expect::array($default = [])
Expect::list($default = [])

And also all types supported by the Validators class, for example Expect::type('scalar') or shorthand Expect::scalar(). Also class or interface names, e.g., Expect::type('AddressEntity').

Union syntax can also be used:

php
Expect::type('bool|string|array')

The default value is always null with the exception of array and list, where it is an empty array. (A list is an array indexed by a sequence of numeric keys starting from zero, i.e. a non-associative array).

Array of Values: arrayOf() listOf()

An array represents too general a structure; it's more useful to specify precisely which elements it may contain. For example, an array whose elements can only be strings:

php
$schema = Expect::arrayOf('string');

$processor->process($schema, ['hello', 'world']); // OK
$processor->process($schema, ['a' => 'hello', 'b' => 'world']); // OK
$processor->process($schema, ['key' => 123]); // ERROR: 123 is not a string

The second parameter can specify keys (since version 1.2):

php
$schema = Expect::arrayOf('string', 'int');

$processor->process($schema, ['hello', 'world']); // OK
$processor->process($schema, ['a' => 'hello']); // ERROR: 'a' is not an int

A list is an indexed array:

php
$schema = Expect::listOf('string');

$processor->process($schema, ['a', 'b']); // OK
$processor->process($schema, ['a', 123]); // ERROR: 123 is not a string
$processor->process($schema, ['key' => 'a']); // ERROR: not a list
$processor->process($schema, [1 => 'a', 0 => 'b']); // ERROR: also not a list

With the wrap parameter, a single value is also accepted and wrapped into a one-item list (since version 1.4):

php
$schema = Expect::listOf('string', wrap: true);

$processor->process($schema, 'hello'); // OK, gives ['hello']
$processor->process($schema, ['a', 'b']); // OK

The parameter can also be a schema, so we can write:

php
Expect::arrayOf(Expect::bool())

The default value is an empty array. If you specify a default value and call mergeDefaults(), it will be merged with the passed data.

Enumeration: anyOf()

anyOf() represents a set of values or schemas that a value can take. Here's how to write an array of elements that can be either 'a', true, or null:

php
$schema = Expect::listOf(
	Expect::anyOf('a', true, null),
);

$processor->process($schema, ['a', true, null, 'a']); // OK
$processor->process($schema, ['a', false]); // ERROR: false does not belong there

The elements of the enumeration can also be schemas:

php
$schema = Expect::listOf(
	Expect::anyOf(Expect::string(), true, null),
);

$processor->process($schema, ['foo', true, null, 'bar']); // OK
$processor->process($schema, [123]); // ERROR

The anyOf() method accepts variants as separate parameters, not as an array. To pass it an array of values, use the unpack operator anyOf(...$variants).

Variants are tried in the order they are written and the first matching one wins. The single exception is null: when it belongs to the accepted values, a null input always gives null, even though a structure or an array variant would otherwise read it as an empty value of its own.

The default value is null. Use the firstIsDefault() method to make the first item the default:

php
// default is 'hello'
Expect::anyOf(Expect::string('hello'), true, null)->firstIsDefault();

Enums: enum()

A configuration file can only carry a plain string like 'hearts', but in your code you would much rather work with an enum. That is the gap enum() closes (since version 1.4): give it an enum with a backing value (enum Suit: string) and it accepts either the backing value or the case itself, always handing you back the case:

php
enum Suit: string
{
	case Hearts = 'hearts';
	case Spades = 'spades';
}

$schema = Expect::enum(Suit::class);

$processor->process($schema, 'hearts');     // OK, returns Suit::Hearts
$processor->process($schema, Suit::Spades); // OK, returns Suit::Spades
$processor->process($schema, 'clubs');      // ERROR: expects to be Suit

Enums backed by integers work exactly the same, and so does everything you know from the other elements, such as Expect::enum(Suit::class)->required() or ->default(Suit::Hearts).

You often do not have to reach for enum() explicitly. An enum class name is recognized in a type expression and when generating a schema from a class, so Expect::type(Suit::class) and a public Suit $suit property give you the very same element.

Structures

Structures are objects with defined keys. Each key-value pair is referred to as a "property".

Structures accept arrays and objects and return stdClass objects.

By default, all properties are optional and have a default value of null. You can define mandatory properties using required():

php
$schema = Expect::structure([
	'required' => Expect::string()->required(),
	'optional' => Expect::string(), // default value is null
]);

$processor->process($schema, ['optional' => '']);
// ERROR: option 'required' is missing

$processor->process($schema, ['required' => 'foo']);
// OK, returns {'required' => 'foo', 'optional' => null}

A structure itself is mandatory. Therefore, if it is nested inside another structure and the input does not contain it, it is created anyway - and it reports an error when it contains a required property. Use required(false) to make the entire nested structure optional. If it is missing in the input, null appears in the output, but if it is present, its required properties are enforced:

php
$schema = Expect::structure([
	'db' => Expect::structure([
		'dsn' => Expect::string()->required(),
	])->required(false),
]);

$processor->process($schema, []);
// OK, returns {'db' => null}

$processor->process($schema, ['db' => []]);
// ERROR: 'db › dsn' is missing

If you do not want properties with default values in the output, use skipDefaults():

php
$schema = Expect::structure([
	'required' => Expect::string()->required(),
	'optional' => Expect::string(),
])->skipDefaults();

$processor->process($schema, ['required' => 'foo']);
// OK, returns {'required' => 'foo'}

Although null is the default value for the optional property, it is not allowed in input data (the value must be a string). Properties accepting null are defined using nullable():

php
$schema = Expect::structure([
	'optional' => Expect::string(),
	'nullable' => Expect::string()->nullable(),
]);

$processor->process($schema, ['optional' => null]);
// ERROR: 'optional' expects to be string, null given.

$processor->process($schema, ['nullable' => null]);
// OK, returns {'optional' => null, 'nullable' => null}

The array of all structure properties is returned by the getShape() method.

By default, no additional items can be present in the input data:

php
$schema = Expect::structure([
	'key' => Expect::string(),
]);

$processor->process($schema, ['additional' => 1]);
// ERROR: Unexpected item 'additional'

This can be changed using otherItems(). As a parameter, pass the schema to validate each extra item:

php
$schema = Expect::structure([
	'key' => Expect::string(),
])->otherItems(Expect::int());

$processor->process($schema, ['additional' => 1]); // OK
$processor->process($schema, ['additional' => true]); // ERROR

You can create a new structure by extending another using extend():

php
$dog = Expect::structure([
	'name' => Expect::string(),
	'age' => Expect::int(),
]);

$dogWithBreed = $dog->extend([
	'breed' => Expect::string(),
]);

Array

An array with defined keys (since version 1.3.2). Ev

Issues· 0 open

View all issuesOpen on GitHub

No open issues yet, or sync has not completed.

> Tags

PHPdata-structuresjsonnettenette-framework

No comments yet. Be the first to share.

> Details

PublishedAug 1, 2026
UpdatedSep 17, 2026
Category编程语言
PricingOpen source

> Related tools

T
TypeScript
JavaScript 的超集,为前端与全栈提供静态类型
P
Python
通用编程语言,广泛用于 Web、数据与 AI
G
Go
Google 推出的简洁高效系统语言