1- # PHP Typed Values
1+ ### PHP Typed Values
22
3- PHP library of typed value objects for common PHP data types.
4-
5- Building blocks for a DTO's, ValueObjects, Entities, etc.
3+ Typed value objects for PHP. Build precise, immutable, and validated data for DTOs, Value Objects, and Entities.
64
75[ ![ Latest Version on Packagist] ( https://img.shields.io/packagist/v/georgii-web/php-typed-values.svg?style=flat-square )] ( https://packagist.org/packages/georgii-web/php-typed-values )
86[ ![ Tests] ( https://github.com/georgii-web/php-typed-values/actions/workflows/php.yml/badge.svg )] ( https://github.com/georgii-web/php-typed-values/actions/workflows/php.yml )
97[ ![ Total Downloads] ( https://img.shields.io/packagist/dt/georgii-web/php-typed-values.svg?style=flat-square )] ( https://packagist.org/packages/georgii-web/php-typed-values )
108
11- ## Install
9+ ---
1210
13- Use ` v2.* ` for PHP 8.2 support:
11+ ### Install
1412
15- ```
13+ - PHP 8.2+:
14+
15+ ``` bash
1616composer require georgii-web/php-typed-values:^2.0
1717```
1818
19- Use ` v1.* ` for PHP 7.4 support :
19+ - PHP 7.4:
2020
21- ```
21+ ``` bash
2222composer require georgii-web/php-typed-values:^1.0
2323```
2424
25- ## Usage
25+ ### Why
26+
27+ - Strong typing for scalars with runtime validation
28+ - Immutable and self‑documenting values
29+ - Safer constructors for your DTOs/VOs/Entities
30+ - Great fit for static analysis (Psalm/PHPStan)
31+
32+ ### Quick start
2633
27- #### 1. Use existing typed values with validation built in:
34+ #### Use existing typed values
2835
2936``` php
37+ use TypedValues\Integer\IntegerPositive;
38+
3039$id = IntegerPositive::fromString('123');
3140```
3241
33- instead of spreading this logic across your application like :
42+ Instead of spreading validation across an application:
3443
3544``` php
3645$id = (int) '123';
@@ -39,17 +48,24 @@ if ($id <= 0) {
3948}
4049```
4150
42- #### 2. Create aliases:
51+ #### Create an alias (domain name)
4352
4453``` php
54+ use TypedValues\Integer\IntegerPositive;
55+
4556readonly class Id extends IntegerPositive {}
4657
4758Id::fromInt(123);
4859```
4960
50- #### 3. Create a composite value object:
61+ #### Compose value objects
5162
5263``` php
64+ use TypedValues\Integer\IntegerPositive;
65+ use TypedValues\String\StringNonEmpty;
66+ use TypedValues\Float\FloatPositive;
67+ use TypedValues\Undefined\Alias\Undefined; // represents an intentionally missing value
68+
5369final readonly class Profile
5470{
5571 public function __construct(
@@ -64,65 +80,63 @@ final readonly class Profile
6480 string|float|int|null $height = null,
6581 ): self {
6682 return new self(
67- IntegerPositive::fromInt($id), // Early fail
68- StringNonEmpty::tryFromMixed($firstName), // Late fail
83+ IntegerPositive::fromInt($id), // early fail (must be valid)
84+ StringNonEmpty::tryFromMixed($firstName), // late fail (maybe undefined)
6985 $height !== null
70- ? FloatPositive::fromString((string) $height) // Early fail for not NULL
71- : Undefined::create(), // Late fail for NULL
86+ ? FloatPositive::fromString((string) $height) // early fail if provided
87+ : Undefined::create(), // late fail when accessed
7288 );
7389 }
74-
75- public function getHeight(): FloatPositive|Undefined {
76- return $this->height;
77- }
90+
91+ public function getFirstName(): StringNonEmpty|Undefined { return $this->firstName; }
92+ public function getHeight(): FloatPositive|Undefined { return $this->height; }
7893}
7994```
80- VO strictly typed and must have all valid fields:
8195
82- Use " Early fail" on wrong ` Id `
96+ ##### Early fail (invalid input prevents creation)
8397
8498``` php
85- Profile::fromScalars(id: 0, firstName: 'Alice', height: '172.5'); // Early fail Exception
99+ Profile::fromScalars(id: 0, firstName: 'Alice', height: '172.5'); // throws exception
86100```
87101
88- If VO partly valid but still must be created:
102+ ##### Late fail with ` Undefined ` (object exists, fail on access)
89103
90- Use "Late fail" on a wrong ` firstName `
91104``` php
92- $profile = Profile::fromScalars(id: 101, firstName: '', height: '172.5'); // Profile created
93- $profile = Profile::fromScalars(id: 101, firstName: null, height: '172.5'); // Profile created
94- $profile->getFirstName()->value(); // Late fail, "Undefined" class will throw an exception on trying to get the value
105+ $profile = Profile::fromScalars(id: 101, firstName: '', height: '172.5'); // created
106+ $profile->getFirstName()->value(); // throws an exception on access the Undefined value
95107```
96108
97- Or "Optioanal fail" on a wrong ` height `
109+ ##### Optional fail (only fail if the optional value is provided and invalid)
110+
98111``` php
99- $profile = Profile::fromScalars(id: 101, firstName: 'Alice', height: -1); // Early fail Exception
112+ Profile::fromScalars(id: 101, firstName: 'Alice', height: -1); // invalid provided value -> early fail
100113
101- $profile = Profile::fromScalars(id: 101, firstName: 'Alice', height: null); // Profile created
102- $profile->getHeight()->value(); // Late fail, "Undefined" class will throw an exception on trying to get the value
114+ $profile = Profile::fromScalars(id: 101, firstName: 'Alice', height: null); // value omitted -> created, fails only on access
115+ $profile->getHeight()->value(); // throws an exception on access the Undefined value
103116```
104117
105- ## Key Features
118+ ### Key features
106119
107- - ** Static analysis** – Designed for tools like Psalm and PHPStan with precise type annotations.
108- - ** Strict types** – Uses ` declare(strict_types=1); ` and strict type hints throughout.
109- - ** Validation** – Validates input on construction so objects can’t be created in an invalid state.
110- - ** Immutable** – Value objects are read‑only and never change after creation.
111- - ** No external dependencies ** – Pure PHP implementation without requiring third‑party packages.
112- - ** Extendable ** – Extendable with custom-typed values and composite value objects.
120+ - Static analysis friendly ( Psalm/ PHPStan-ready types)
121+ - Strict types with ` declare(strict_types=1); `
122+ - Validation on construction; no invalid state
123+ - Immutable, readonly objects
124+ - No external runtime dependencies
125+ - Easy to extend with your own types and composites
113126
114- ## Performance disclaimer
127+ ### Performance note
115128
116- - ** Performance** for an array of objects is about ` 3x ` ** slower** than an array of scalars;
117- - ** Memory usage** for an array of objects is about ` 2x ` ** higher** ;
118- - ** Use value objects** for domain modeling, type safety, and validation boundaries;
119- - ** Use raw scalars** for high-performance loops or large-scale data processing;
129+ - Objects vs scalars:
130+ - ~ 3× slower for large arrays of objects
131+ - ~ 2× higher memory usage
132+ - Use value objects for domain boundaries, validation, and clarity
133+ - Use raw scalars in hot loops or large data processing paths
120134
121- ## More information
135+ ### Documentation
122136
123- See [ docs/USAGE .md] ( docs/USAGE.md ) for usage examples.
124- See [ docs/DEVELOP.md ] ( docs/DEVELOP.md ) for development details.
137+ - Development guide: ` docs/DEVELOP .md `
138+ - Usage examples in ` src/Usage `
125139
126- ## License
140+ ### License
127141
128- MIT
142+ MIT
0 commit comments