1. Go to this page and download the library: Download wwwision/types 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/ */
wwwision / types example snippets
class Contact {
public function __construct(public string $name, public int $age) {}
}
final class ContactName {
public function __construct(public string $value) {}
}
final class ContactAge {
public function __construct(public int $value) {}
}
#[Description('The full name of a contact, e.g. "John Doe"')]
#[StringBased(minLength: 1, maxLength: 200)]
final class ContactName {
public function __construct(public string $value) {}
}
#[Description('The current age of a contact, e.g. 45')]
#[IntegerBased(minimum: 1, maximum: 130)]
final class ContactAge {
public function __construct(public int $value) {}
}
#[Description('The full name of a contact, e.g. "John Doe"')]
#[StringBased(minLength: 1, maxLength: 200)]
final class ContactName {
private function __construct(public readonly string $value) {}
}
#[Description('The current age of a contact, e.g. 45')]
#[IntegerBased(minimum: 1, maximum: 130)]
final class ContactAge {
private function __construct(public readonly int $value) {}
}
final class Contact {
public function __construct(
public readonly ContactName $name,
public readonly ContactAge $age,
) {}
}
// ...
#[ListBased(itemClassName: Contact::class)]
final class Contacts implements IteratorAggregate {
private function __construct(private readonly array $contacts) {}
public function getIterator() : Traversable {
yield from $this->contacts;
}
}
interface ContactRepository {
public function findByName(ContactName $name): Contacts;
}
final class DatabaseContactRepository implements ContactRepository {
public function __construct(private readonly PDO $pdo) {}
public function findByName(ContactName $name): Contacts
{
$statement = $this->pdo->prepare('SELECT name, age FROM contacts WHERE name = :name');
$statement->execute(['name' => $name->value]);
return instantiate(Contacts::class, $statement->fetchAll(PDO::FETCH_ASSOC));
}
}
#[StringBased]
final class SomeValueObject {
private function __construct(public readonly string $value) {}
}
// ...
final class SomeComposite {
public function __construct(
public readonly SomeValueObject $alreadyValidated,
public readonly bool $neverInvalid,
) {}
}
// this is fine:
instantiate(SomeComposite::class, ['alreadyValidated' => 'some value', 'neverInvalid' => true]);
// and so is this:
new SomeComposite(instantiate(SomeValueObject::class, 'some value'), true);
#[StringBased(format: StringTypeFormat::date, pattern: '^1980')]
final class Date {
private function __construct(public readonly string $value) {}
public function add(\DateInterval $interval): self
{
return instantiate(self::class, \DateTimeImmutable::createFromFormat('Y-m-d', $this->value)->add($interval)->format('Y-m-d'));
}
}
$date = instantiate(Date::class, '1980-12-30');
$date = $date->add(new \DateInterval('P1D'));
// this is fine
assert($date->value === '1980-12-31');
// this is not because of the "pattern"
$date = $date->add(new \DateInterval('P1D'));
// Exception: Failed to cast string of "1981-01-01" to Date: invalid_string (Value does not match regular expression)
#[Description('This is a description for this class')]
final class SomeClass {
public function __construct(
#[Description('This is some overridden description for this parameter')]
public readonly bool $someProperty,
) {}
}
assert(Parser::getSchema(SomeClass::class)->overriddenPropertyDescription('someProperty') === 'This is some overridden description for this parameter');
#[IntegerBased(minimum: 0, maximum: 123)]
final class SomeIntBased {
private function __construct(public readonly int $value) {}
}
instantiate(SomeIntBased::class, '-5');
// Exception: Failed to cast string of "-5" to SomeIntBased: too_small (Number must be greater than or equal to 0)
#[FloatBased(minimum: 12.34, maximum: 30)]
final class SomeFloatBased {
private function __construct(public readonly float $value) {}
}
instantiate(SomeFloatBased::class, 12);
// Exception: Failed to cast integer value of 12 to SomeFloatBased: too_small (Number must be greater than or equal to 12.340)
#[StringBased(minLength: 1, maxLength: 200)]
final class GivenName {
private function __construct(public readonly string $value) {}
}
instantiate(GivenName::class, '');
// Exception: Failed to cast string of "" to GivenName: too_small (String must contain at least 1 character(s))
#[StringBased(format: StringTypeFormat::email, pattern: '@your.org$')]
final class EmployeeEmailAddress {
private function __construct(public readonly string $value) {}
}
instantiate(EmployeeEmailAddress::class, '[email protected]');
// Exception: Failed to cast string of "[email protected]" to EmployeeEmailAddress: invalid_string (Value does not match regular expression)
#[StringBased]
final class Hobby {
private function __construct(public readonly string $value) {}
}
#[ListBased(itemClassName: Hobby::class)]
final class Hobbies implements IteratorAggregate {
private function __construct(private readonly array $hobbies) {}
public function getIterator() : Traversable {
yield from $this->hobbies;
}
}
instantiate(Hobbies::class, ['Soccer', 'Ping Pong', 'Guitar']);
// ...
/**
* @implements IteratorAggregate<Hobby>
*/
#[Description('A list of hobbies')]
#[ListBased(itemClassName: Hobby::class, minCount: 1, maxCount: 3)]
final class HobbiesAdvanced implements IteratorAggregate, Countable, JsonSerializable {
/** @param array<Hobby> $hobbies */
private function __construct(private readonly array $hobbies) {}
public function getIterator() : Traversable {
yield from $this->hobbies;
}
public function count(): int {
return count($this->hobbies);
}
public function jsonSerialize() : array {
return array_values($this->hobbies);
}
}
instantiate(HobbiesAdvanced::class, ['Soccer', 'Ping Pong', 'Guitar', 'Gaming']);
// Exception: Failed to cast value of type array to HobbiesAdvanced: too_big (Array must contain at most 3 element(s))
#[StringBased]
final class GivenName {
private function __construct(public readonly string $value) {}
}
#[StringBased]
final class FamilyName {
private function __construct(public readonly string $value) {}
}
final class FullName {
public function __construct(
public readonly GivenName $givenName,
public readonly FamilyName $familyName,
) {}
}
#[Description('honorific title of a person')]
enum HonorificTitle
{
#[Description('for men, regardless of marital status, who do not have another professional or academic title')]
case MR;
#[Description('for married women who do not have another professional or academic title')]
case MRS;
#[Description('for girls, unmarried women and married women who continue to use their maiden name')]
case MISS;
#[Description('for women, regardless of marital status or when marital status is unknown')]
case MS;
#[Description('for any other title that does not match the above')]
case OTHER;
}
#[Description('A contact in the system')]
final class Contact {
public function __construct(
public readonly HonorificTitle $title,
public readonly FullName $name,
#[Description('Whether the contact is registered or not')]
public bool $isRegistered = false,
) {}
}
// Create a Contact instance from an array
$person = instantiate(Contact::class, ['title' => 'MRS', 'name' => ['givenName' => 'Jane', 'familyName' => 'Doe']]);
assert($person->name->familyName->value === 'Doe');
assert($person->isRegistered === false);
// Retrieve the schema for the Contact class
$schema = Parser::getSchema(Contact::class);
assert($schema->getDescription() === 'A contact in the system');
assert($schema->propertySchemas['isRegistered']->getDescription() === 'Whether the contact is registered or not');
(no test)
#[Generic('TKey', 'TValue')]
final class Collection {
// ...
}
// won't work as of now:
$posts = generic(Collection::class, $dbRows, TKey: Types::int(), TValue: Types::classOf(Post::class));
interface SimpleOrComplexObject {
public function render(): string;
}
#[StringBased]
final class SimpleObject implements SimpleOrComplexObject {
private function __construct(private readonly string $value) {}
public function render(): string {
return $this->value;
}
}
final class ComplexObject implements SimpleOrComplexObject {
private function __construct(private readonly string $prefix, private readonly string $suffix) {}
public function render(): string {
return $this->prefix . $this->suffix;
}
}
$simpleObject = instantiate(SimpleOrComplexObject::class, ['__type' => SimpleObject::class, '__value' => 'Some value']);
assert($simpleObject instanceof SimpleObject);
$complexObject = instantiate(SimpleOrComplexObject::class, ['__type' => ComplexObject::class, 'prefix' => 'Prefix', 'suffix' => 'Suffix']);
assert($complexObject instanceof ComplexObject);
// ...
#[ListBased(itemClassName: SimpleOrComplexObject::class)]
final class SimpleOrComplexObjects implements IteratorAggregate {
public function __construct(private readonly array $objects) {}
public function getIterator() : Traversable{
yield from $this->objects;
}
public function map(Closure $closure): array
{
return array_map($closure, $this->objects);
}
}
$objects = instantiate(SimpleOrComplexObjects::class, [
['__type' => SimpleObject::class, '__value' => 'Simple'],
['__type' => ComplexObject::class, 'prefix' => 'Com', 'suffix' => 'plex'],
]);
assert($objects->map(fn (SimpleOrComplexObject $o) => $o->render()) === ['Simple', 'Complex']);
#[StringBased]
final class GivenName {
private function __construct(public readonly string $value) {}
}
#[StringBased]
final class FamilyName {
private function __construct(public readonly string $value) {}
}
final class ShapeWithUnionType {
private function __construct(
public readonly GivenName|FamilyName $givenOrFamilyName
) {}
}
$instance = instantiate(ShapeWithUnionType::class, ['givenOrFamilyName' => ['__type' => FamilyName::class, '__value' => 'Doe']]);
assert($instance instanceof ShapeWithUnionType);
assert($instance->givenOrFamilyName instanceof FamilyName);
final class ShapeWithSimpleUnionType {
private function __construct(
public readonly string|int $stringOrInteger
) {}
}
$instance = instantiate(ShapeWithSimpleUnionType::class, ['stringOrInteger' => 123]);
assert($instance instanceof ShapeWithSimpleUnionType);
assert(is_int($instance->stringOrInteger));
#[Discriminator(propertyName: 'type', mapping: ['given' => GivenName::class, 'family' => FamilyName::class])]
interface SomeInterface {}
#[StringBased]
final class GivenName implements SomeInterface {
private function __construct(public readonly string $value) {}
}
#[StringBased]
final class FamilyName implements SomeInterface {
private function __construct(public readonly string $value) {}
}
$instance = instantiate(SomeInterface::class, ['type' => 'given', '__value' => 'Jane']);
assert($instance instanceof GivenName);
final class SomeClass {
public function __construct(
#[Discriminator(propertyName: 'type', mapping: ['given' => GivenName::class, 'family' => FamilyName::class])]
public readonly GivenName|FamilyName $givenOrFamilyName,
) {}
}
#[StringBased]
final class GivenName {
private function __construct(public readonly string $value) {}
}
#[StringBased]
final class FamilyName {
private function __construct(public readonly string $value) {}
}
$instance = instantiate(SomeClass::class, ['givenOrFamilyName' => ['type' => 'family', '__value' => 'Doe']]);
assert($instance instanceof SomeClass);
assert($instance->givenOrFamilyName instanceof FamilyName);
#[StringBased]
final class Name {
private function __construct(public readonly string $value) {}
}
$instance = instantiate(Name::class, 'John Doe');
$serialized = json_encode($instance);
assert($serialized === '{"value":"John Doe"}'); // This should preferably just be serialized to the value itself ("John Doe")