ArrayReader

use Derafu\Array\ArrayReader;
use Derafu\Value\ValueType;

$reader = ArrayReader::fromArray(['name' => 'Alice', 'enabled' => false]);
$reader->requireString('name'); // 'Alice'
$reader->getBool('enabled', true); // false

Creating a Reader

Factory Input Behavior
fromArray(array $data, ?string $source = null) An array. Creates a reader at the root.
fromValue(mixed $data, ?string $source = null, string $path = '') Untrusted input. Validates that it is an array, without converting it.
new ArrayReader($data, $path = '', $source = null) An array. Creates a reader with an explicit path and source.

toArray() returns the stored array. Changing the original array after creating a reader does not change the reader’s array values.

Optional and Required Values

A missing key or a value of null uses the optional getter’s default. A present value of another type throws. Falsy values such as false, 0, '' and [] are preserved when they match the requested type.

Optional method Required method Value
getString($key, $default = null) requireString($key) String.
getNonEmptyString($key) requireNonEmptyString($key) String containing at least one non-whitespace character; returned without trimming.
getInt($key, $default = null) requireInt($key) Integer.
getFloat($key, $default = null) requireFloat($key) Float; stored integers are rejected.
getNumber($key, $default = null) requireNumber($key) Integer or float.
getBool($key, $default = null) requireBool($key) Boolean.
getDateTime($key) requireDateTime($key) DateTimeInterface; see Value Types.
getObject($key, $class) requireObject($key, $class) Instance of the class or interface; the return type is that class.
getArray($key) requireArray($key) Any array.
getMap($key) requireMap($key) Array with string keys.
getList($key) requireList($key) Zero-based consecutive list.
getStringList($key) requireStringList($key) List of strings.
getIntList($key) requireIntList($key) List of integers.
getScalarList($key) requireScalarList($key) List of booleans, numbers or strings.
getArrayOf($key, $type) requireArrayOf($key, $type) Array whose values match a type; keys are preserved.
getMapOf($key, $type) requireMapOf($key, $type) String-keyed array whose values match a type.
getListOf($key, $type) requireListOf($key, $type) List whose values match a type.

Optional methods return null when there is no value or default. The primitive getters with a non-null default have a non-null return type for PHPStan. Required methods reject missing keys and null, including when the requested ValueType is nullable.

The generic methods accept any composable type:

$reader = ArrayReader::fromArray(['mode' => 'fast']);
$reader->get('mode', ValueType::literal('fast', 'safe'), 'safe');
$reader->require('mode', ValueType::string());
$reader->get('tags', ValueType::listOf(ValueType::string()), []);

Defaults are returned as supplied, not validated or converted by the requested type.

Explicit Conversions

Strict getters validate existing types. The getAsXXX()/requireAsXXX() methods explicitly convert through ValueType and ValueCaster from Derafu Value.

Optional method Required method Converted type
getAsInt($key, $default = null) requireAsInt($key) Integer.
getAsFloat($key, $default = null) requireAsFloat($key) Float.
getAsNumber($key, $default = null) requireAsNumber($key) Integer when possible, otherwise float.
getAsBool($key, $default = null) requireAsBool($key) Boolean.
getAsString($key, $default = null) requireAsString($key) String.
use Derafu\Array\ArrayReader;

$reader = ArrayReader::fromArray(['port' => '5432', 'enabled' => 'off', 'label' => false]);
$reader->requireAsInt('port');       // 5432
$reader->requireAsBool('enabled');   // false
$reader->requireAsString('label');   // '0'
$reader->getAsNumber('missing', 0);  // 0

Missing keys and null retain the reader’s existing default/required rules. Present values that cannot be converted throw; they do not use the default. See ValueCaster’s conversion contracts.

Presence and Allowed Keys

Every read accepts an integer or string key. An existing literal key takes precedence; otherwise, dot notation such as 'connection.port' navigates nested arrays.

Method Meaning
hasKey($key) The key exists, even when its value is null.
hasValue($key) The key exists and its value is not null.
assertOnlyKeys(...$keys) Throws for any key not allowed; returns the same reader. It does not require the allowed keys to exist.
$reader = ArrayReader::fromArray([0 => null, 'enabled' => false]);
$reader->hasKey(0); // true
$reader->hasValue(0); // false
$reader->hasValue('enabled'); // true
$reader->assertOnlyKeys(0, 'enabled');

Integer allowed keys and their equivalent string forms are accepted by assertOnlyKeys(). This method checks actual keys at the current level; allowed names are literal and are not expanded into paths. To check nested keys, obtain a nested reader and call assertOnlyKeys() on it.

Nested Readers and Collections

getReader() and requireReader() read any nested array as another reader: maps, lists and sparse arrays all work. An optional second argument validates the selected array with a ValueType before creating its reader. Omitting it, or passing null, accepts any array as before.

$reader = ArrayReader::fromArray(['authors' => [['Alice', 'alice']]]);
$author = $reader->requireReader('authors')->requireReader(0);
$author->requireString(0); // 'Alice'
$author->getString(1); // 'alice'
Optional Required Outer collection
getReaders($key) requireReaders($key) A list of arrays, returned as a list of readers.
getArrayReaders($key) requireArrayReaders($key) An array of arrays, preserving arbitrary keys.

Each record can itself be any array. The collection methods also accept an optional second ValueType argument: it validates each record without changing the outer collection’s requirements. getReaders() and requireReaders() still require a consecutive list; getArrayReaders() and requireArrayReaders() preserve arbitrary keys.

Optional methods return null for absent or null values without invoking the type. Required methods throw MissingValueException for those values before invoking it. Empty collections return [].

use Derafu\Array\ArrayReader;
use Derafu\Value\ValueType;

$reader = ArrayReader::fromArray([
    'innerJoin' => ['table' => 'stock', 'condition' => 'products.id = stock.product_id'],
    'questions' => [['text' => 'What is PHP?']],
]);

$join = $reader->requireReader('innerJoin', ValueType::map());
$table = $join->requireString('table'); // 'stock'.
$questions = $reader->requireReaders('questions', ValueType::map());
$text = $questions[0]->requireString('text'); // 'What is PHP?'.

The supplied type must produce an array. Examples include ValueType::map(), ValueType::list(), ValueType::arrayOf() and ValueType::mapOf(). Scalar-producing types are not valid arguments. A map requires string keys; a positional list is rejected when a map is requested.

Each selected array is parsed once during reader creation, and the parsed result becomes the child reader’s data. Explicit conversion types can therefore prepare a reader’s values without modifying the parent reader. Both validation errors and subsequent child reads retain the full path and source.

use Derafu\Array\ArrayReader;
use Derafu\Value\ValueType;

$reader = ArrayReader::fromArray([
    'translations' => [
        'es' => ['save' => 'Guardar'],
        'en' => ['save' => 'Save'],
    ],
]);

$languages = $reader->requireArrayReaders(
    'translations',
    ValueType::mapOf(ValueType::string()),
);
$label = $languages['es']->requireString('save'); // 'Guardar'.
$reader = ArrayReader::fromValue(
    ['rows' => [3 => ['name' => 'Alice'], 8 => ['name' => 123]]],
    source: 'account API',
    path: 'response',
);

$rows = $reader->requireArrayReaders('rows');
$rows[3]->requireString('name'); // 'Alice'
$rows[8]->requireString('name');
// Throws: The key "response.rows.8.name" of account API must be of type string, int given.

requireReaders('rows') would reject this outer collection because its keys are not a consecutive list. No reader reindexes an arbitrary collection.

On this page

Last updated on 26/10/2026 by Anonymous