You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: CHANGELOG.md
+19Lines changed: 19 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1,5 +1,24 @@
1
1
# CHANGELOG
2
2
3
+
## [v4.1.0] - 2026-03-07
4
+
5
+
### Added
6
+
7
+
-**`defaultValues()` — Static default value declaration.** Override `defaultValues(): array` to declare fallback values for properties absent from input data. Keys must match declared property names; unmatched keys are silently ignored. Supports any type valid for the target property, including subclasses of ImmutableBase and Enum.
8
+
-**`#[Defaults(value)]` — Attribute-based default value.** Apply `#[Defaults(value)]` to individual properties for constant-expression defaults. Constrained by PHP attribute syntax to scalar values, arrays, and class constants.
9
+
-**Default value resolution priority.** During construction (`fromArray` / `fromJson`), property values are resolved in the following order:
10
+
1. Explicit input value (including explicit `null`)
11
+
2.`defaultValues()[$propertyName]`
12
+
3.`#[Defaults(value)]` attribute value
13
+
4.`null` (if nullable) or `RequiredValueException`
14
+
-**Explicit `null` is respected.** When a key is present in the input with a `null` value, it is treated as an intentional assignment — default values are not applied.
15
+
-**Cache-aware default values.**`ib-cacher` serializes cacheable default values (scalars, arrays) into the cache file. Non-serializable defaults (objects, Closures) are excluded from the cache with a `[Notice]` warning and resolved at runtime via `defaultValues()` on every construction.
16
+
-**SVO `defaultValues()` sealed.**`SingleValueObject::defaultValues()` is declared `final` and returns an empty array. SVOs require explicit values via `from()` by design.
17
+
18
+
### Changed
19
+
20
+
-**`__construct()` uses `array_key_exists()` for default resolution.** Replaces `isset()` to correctly distinguish between "key absent" (apply default) and "key present with `null`" (respect explicit null).
Copy file name to clipboardExpand all lines: README.md
+124Lines changed: 124 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -51,6 +51,31 @@ class Order extends DataTransferObject
51
51
new Order('2026-01-01', '00:00:00', ...); // Cannot directly accept external array or JSON data, and risks argument misordering if parameter names are not explicitly specified
52
52
```
53
53
54
+
### 🛡️ Declarative Default Values
55
+
```php
56
+
// 🥳 ImmutableBase fills missing properties from defaultValues() or #[Defaults], with clear priority and null-awareness.
57
+
readonly class CreateUserDTO extends DataTransferObject
58
+
{
59
+
public string $name;
60
+
#[Defaults('member')]
61
+
public string $role;
62
+
63
+
public static function defaultValues(): array
64
+
{
65
+
return ['role' => 'admin']; // Takes precedence over #[Defaults]
66
+
}
67
+
}
68
+
CreateUserDTO::fromArray(['name' => 'Kip']); // role = 'admin'
69
+
70
+
// 🫤 The conventional approach requires manual null-coalescing or constructor defaults, with no centralized declaration.
71
+
class CreateUserDTO {
72
+
public function __construct(
73
+
public readonly string $name,
74
+
public readonly string $role = 'member', // Cannot be overridden per-class without rewriting constructors
75
+
){}
76
+
}
77
+
```
78
+
54
79
### 🔧 Flexible Deep Path Updates
55
80
Update deeply nested properties by path - no Russian nesting dolls.
Properties absent from input data can be populated with fallback values via two complementary mechanisms.
386
+
387
+
### `defaultValues()` — Dynamic Defaults
388
+
389
+
Override the static method to declare default values as an associative array keyed by property name. Supports any type valid for the target property, including subclasses of ImmutableBase and Enum.
390
+
391
+
```php
392
+
readonly class CreateUserDTO extends DataTransferObject
393
+
{
394
+
public string $name;
395
+
public string $role;
396
+
public string $locale;
397
+
398
+
public static function defaultValues(): array
399
+
{
400
+
return [
401
+
'role' => 'member',
402
+
'locale' => 'en',
403
+
];
404
+
}
405
+
}
406
+
CreateUserDTO::fromArray(['name' => 'Kip']); // role = 'member', locale = 'en'
407
+
```
408
+
409
+
### `#[Defaults]` — Attribute Defaults
410
+
411
+
Apply `#[Defaults(value)]` to individual properties for inline constant-expression defaults. Constrained by PHP attribute syntax to scalars, arrays, and class constants.
412
+
413
+
```php
414
+
use ReallifeKip\ImmutableBase\Attributes\Defaults;
415
+
416
+
readonly class CreateUserDTO extends DataTransferObject
417
+
{
418
+
public string $name;
419
+
#[Defaults('member')]
420
+
public string $role;
421
+
#[Defaults('en')]
422
+
public string $locale;
423
+
}
424
+
```
425
+
426
+
### Resolution Priority
427
+
428
+
When a property key is absent from the input data, defaults are resolved in this order:
429
+
430
+
1.`defaultValues()[$propertyName]`
431
+
2.`#[Defaults(value)]` attribute value
432
+
3.`null` (if nullable) or `RequiredValueException`
433
+
434
+
When both mechanisms define a value for the same property, `defaultValues()` takes precedence.
435
+
436
+
### Explicit `null` Is Not Absent
437
+
438
+
When a key is present in the input with a `null` value, it is treated as an intentional assignment — default values are **not** applied.
`ib-cacher` serializes cacheable default values (scalars, arrays) into the cache file. Non-serializable values (objects, Closures, resources) are excluded with a `[Notice]` warning and resolved at runtime via `defaultValues()` instead.
459
+
460
+
### SVO Restriction
461
+
462
+
`SingleValueObject` does not support default values. SVOs require an explicit value via `from()` by design. The `defaultValues()` method is sealed (`final`) on `SingleValueObject` and always returns an empty array.
463
+
464
+
---
465
+
358
466
## Attributes
359
467
468
+
### `#[Defaults]` - Property Default Value
469
+
470
+
Declares a fallback value for a single property when the key is absent from input data. Constrained by PHP attribute syntax to scalar values, arrays, and class constants. For dynamic or object defaults, use `defaultValues()` instead.
471
+
472
+
```php
473
+
use ReallifeKip\ImmutableBase\Attributes\Defaults;
474
+
475
+
readonly class CreateUserDTO extends DataTransferObject
476
+
{
477
+
public string $name;
478
+
#[Defaults('member')]
479
+
public string $role;
480
+
}
481
+
CreateUserDTO::fromArray(['name' => 'Kip']); // role = 'member'
482
+
```
483
+
360
484
### `#[ArrayOf]` - Typed Array
361
485
362
486
Marks an array property as a typed collection of ImmutableBase instances. Each element is automatically instantiated from arrays, JSON strings, or pre-built objects. The target class must be a subclass of DTO, VO, or SVO.
0 commit comments