PHP code example of klimick / decode

1. Go to this page and download the library: Download klimick/decode library. Choose the download type require.

2. Extract the ZIP file and open the index.php.

3. Add this code to the index.php.
    
        
<?php
require_once('vendor/autoload.php');

/* Start to develop here. Best regards https://php-download.com/ */

    

klimick / decode example snippets




use Klimick\Decode\Decoder as t;

// Describes runtime type for array{name: string, age: int, meta: list<string>}
$libraryDefinition = t\shape(
    id: t\int(),
    name: t\string(),
    meta: t\listOf(t\string()),
);

// Untrusted data
$json = '{
    "id": 42,
    "name": "Decode",
    "meta": [
        "runtime type system",
        "psalm integration",
        "with whsv26/functional"
    ]
}';

// If decode will fail, CastException is thrown.
// $person is array{name: string, age: int, meta: list<string>}
$person = t\tryCast(
    value: $json,
    to: t\fromJson($libraryDefinition),
);

// Either data type from whsv26/functional
// Left side contains decoding errors
// Right side holds decoded valid
// $person is Either<Invalid, Valid<array{name: string, age: int, meta: list<string>}>>
$personEither = t\decode(
    value: $json,
    with: t\fromJson($libraryDefinition),
)

// Option data type from whsv26/functional
// $person is Option<array{name: string, age: int, meta: list<string>}>
$personOption = t\cast(
    value: $json,
    to: t\fromJson($libraryDefinition),
);

$nullOrInt = union(null(), int())

$datetime = datetime(fromFormat: 'Y-m-d H:i:s');

$datetime = datetime(timezone: 'Moscow/Europe');

// int | string
$intOrString = union(int(), string());
// float | null
$floatOrNull = union(float(), null());
// int | float | string | null
$intOrFloatOrStringOrNull = union($intOrString, $floatOrNull);

// array<int, string>
$arr = arrayOf(int(), string());

// non-empty-array<int, string>
$nonEmptyArr = nonEmptyArrayOf(int(), string());

// list<string>
$list = listOf(string());

// non-empty-list<string>
$list = nonEmptyListOf(string());

// array{prop1: int, prop2: string, prop3: bool}
$shape = shape(
    prop1: int(),
    prop2: string(),
    prop3: bool(),
);

// array{prop1?: int, prop2?: string, prop3?: bool}
$shape = partialShape(
    prop1: int(),
    prop2: string(),
    prop3: bool(),
);

// array{prop1: string, prop2: string, prop3?: string, prop4?: string}
$intersection = intersection(
    shape(
        prop1: string(),
        prop2: string(),
    ),
    partialShape(
        prop3: string(),
        prop4: string(),
    ),
);

// array{int, string, bool}
$tuple = tuple(int(), string(), bool());

final class SomeClass
{
    public function __construct(
        public int $prop1,
        public string $prop2,
    ) {}
    
    /**
     * @return DecoderInterface<SomeClass>
     */
    public static function type(): DecoderInterface
    {
        return object(self::class)(
            prop1: int(),
            prop2: string(),
        );
    }
}

final class SomeClass
{
    /**
     * @param list<SomeClass> $recursive
     */
    public function __construct(
        public int $prop1,
        public string $prop2,
        public array $recursive = [],
    ) { }

    /**
     * @return DecoderInterface<SomeClass>
     */
    public static function type(): DecoderInterface
    {
        $self = rec(fn() => self::type());

        return object(self::class)(
            prop1: int(),
            prop2: string(),
            recursive: listOf($self),
        );
    }
}

$shapeFromJson = fromJson(
    shape(
        prop1: string(),
        prop2: string(),
    )
);

$personD = shape(
    name: string(),
    additional: listOf(string())->optional(),
);

// inferred type: array{name: string, additional?: list<string>}
$firstShape = tryCast(['name' => 'foo'], $personD);

// No additional field
// ['name' => 'foo']
print_r($firstShape);

// inferred type: array{name: string, additional?: list<string>}
$secondShape = tryCast(['name' => 'foo', 'additional' => ['bar']], $personD);

// ['name' => 'foo', 'additional' => ['bar']]
print_r($secondShape);

$personD = shape(
    name: string(),
    isEmployed: bool()->default(false),
);

// inferred type: array{name: string, isEmployed: bool}
$firstShape = tryCast(['name' => 'foo'], $personD);

// With default ['isEmployed' => false]
// ['name' => 'foo', 'isEmployed' => false]
print_r($firstShape);

// inferred type: array{name: string, isEmployed: bool}
$secondShape = tryCast(['name' => 'foo', 'isEmployed' => true], $personD);

// ['name' => 'foo', 'isEmployed' => true]
print_r($secondShape);

$personD = shape(
    name: string()->constrained(
        minSize(is: 1),
        maxSize(is: 255),
    ),
    street: string()->constrained(
        minSize(is: 1),
        maxSize(is: 255),
    ),
);

$personD = shape(
    name: string()->from('$.person'),
    street: string()->from('$.address.street'),
);

$untrustedData = [
    'person' => 'foo',
    'address' => [
        'street' => 'bar',
    ],
];

// Inferred type: array{name: string, street: string}
$personShape = tryCast($untrustedData, $personD);

/* Decoded data looks different rather than source: [
    'name' => 'foo',
    'street' => 'bar',
] */
print_r($personShape);

$messengerD = shape(
    kind: string()->from('$.messenger_type'),
    contact: string()->from('$.messenger_contact'),
);

$personD = shape(
    name: string()->from('$.person'),
    street: string()->from('$.address.street'),
    messenger: $messengerD->from('$'), // means "use the same data for this decoder"
);

$untrustedData = [
    'person' => 'foo',
    'address' => [
        'street' => 'bar',
    ],
    'messenger_type' => 'telegram',
    'messenger_contact' => '@Klimick',
];

// inferred type: array{name: string, street: string, messenger: array{kind: string, messenger: string}}
$personShape = tryCast($untrustedData, $personD);

/* Decoded data looks different rather than source: [
    'name' => 'foo',
    'street' => 'bar',
    'messenger' => [
        'kind' => 'telegram',
        'contact' => '@Klimick',
    ]
] */
print_r($personShape);

$fooString = string()
    ->constrained(equal('foo'));

$greaterThan10 = int()
    ->constrained(greater(10));

$greaterOrEqualTo10 = int()
    ->constrained(greaterOrEqual(10));

$lessThan10 = int()
    ->constrained(less(10));

$lessOrEqualTo10 = int()
    ->constrained(lessOrEqual(10));

$from10to20 = int()
    ->constrained(inRange(10, 20));

$min10char = string()
    ->constrained(minLength(10));

$max10char = string()
    ->constrained(maxLength(10));

$startsWithFoo = string()
    ->constrained(startsWith('foo'));

$endsWithFoo = string()
    ->constrained(endsWith('foo'));

$uuidString = string()
    ->constrained(uuid());

$noLeadingOrTrailingSpaces = string()
    ->constrained(trimmed());

$stringWithNumbers = string()
    ->constrained(matchesRegex('/^[0-9]{1,3}$/'));

$allNumbersGreaterThan10 = forall(greater(than: 10));

$numbersGreaterThan10 = listOf(int())
    ->constrained($allNumbersGreaterThan10);

$hasNumbersGreaterThan10 = exists(greater(than: 10));

$withNumberGreaterThan10 = listOf(int())
    ->constrained($hasNumbersGreaterThan10);

$listWith10 = listOf(int())
    ->constrained(inCollection(10));

$max10numbers = listOf(int())
    ->constrained(maxSize(is: 10));

$atLeast10numbers = listOf(int())
    ->constrained(minSize(is: 10));

$from100to200 = allOf(
    greaterOrEqual(to: 100),
    lessOrEqual(to: 200),
);

$numbersFrom100to200 = listOf(int())
    ->constrained($from100to200);

$from100to200 = allOf(
    greaterOrEqual(to: 100),
    lessOrEqual(to: 200),
);

$from300to400 = allOf(
    greaterOrEqual(to: 300),
    lessOrEqual(to: 400),
);

$numbersFrom100to200orFrom300to400 = listOf(int())
    ->constrained(anyOf($from100to200, $from300to400));