v4.0.0
The first stable release of v4 — a complete architectural overhaul from attribute-based annotations to inheritance-based object definitions.
Highlights:
extends DataTransferObject / ValueObject / SingleValueObjectreplaces#[DataTransferObject]/#[ValueObject]- New
SingleValueObjecttype with TypeScript-like type narrowing - Automatic validation chain across inheritance hierarchy
with()deep path mutation with 44–68% performance improvement- CLI tools:
ib-cacher(metadata cache) +ib-writer(doc generation) - Zero dependencies. Requires PHP 8.4+.
📦 composer require reallifekip/immutable-base
Breaking Changes
- Architecture: Attribute annotation replaced by class inheritance. Objects are now defined by extending
DataTransferObject,ValueObject, orSingleValueObjectinstead of annotating with#[DataTransferObject],#[ValueObject], or#[Entity]. - Entity removed. The
Entityobject type has been removed entirely. - All properties must be
public. In v3,ValueObjectandEntityproperties wereprivatewith getter methods. All properties now requirepublicvisibility, enforced at scan time. Classes should be declared asreadonly class, which handles immutability at the PHP level. - Exception system rebuilt. All v3 exceptions have been removed and replaced with a structured hierarchy under
ImmutableBaseException, categorized intoLogicException>DefinitionException(design errors) andRuntimeException>InitializationException(input type violations) /ValidationException(domain constraint violations). See README for details. object,iterable, and non-IB/non-Enum class types forbidden. Properties typed asobject,iterable, or unsupported classes (e.g.DateTime,Closure) now throwInvalidPropertyTypeExceptionat scan time.
Added
SingleValueObject(SVO). New object type for semantically meaningful single values. Providesfrom(),__toString(),__invoke(), andjsonSerialize(). Child classes can freely define the type of$valuevia interface + hooked property design.equals(). Deep structural equality comparison for all ImmutableBase subclasses, with recursive comparison of nested objects and arrays.#[Strict]/#[Lax]. Control whether undeclared input keys are rejected or accepted.#[SkipOnNull]/#[KeepOnNull]. Control whether null-valued properties appear intoArray()/toJson()output.#[Spec]. Attach a domain-specific validation message to VO/SVO, retrievable viaValidationChainException::getSpec().#[ValidateFromSelf]. Reverse the validation chain direction to bottom-up (default is top-down).- Automatic validation chain. VO and SVO automatically traverse the entire inheritance hierarchy during construction. Each class in the chain is invoked if it defines
validate(): bool, but defining it is optional -- classes without it are simply skipped without breaking the chain. - Hierarchical error path tracing. Nested construction errors include the full property path in the exception message (e.g.
OrderDTO > $customer > $email > {error message}). ImmutableBase::strict(). Global strict mode.ImmutableBase::debug(). Debug logging for redundant input keys.ImmutableBase::loadCache(). Load pre-generated metadata cache to bypass runtime reflection.- CLI:
ib-cacher. Metadata cache generator. Supports--scan-dirfor targeted scanning and--clearfor cache removal. - CLI:
ib-writer. Documentation generator producing Mermaid class diagrams and Markdown property tables. - Benchmark suite. Dedicated benchmarks for
with()and hydration covering flat scalar updates, dot-notation deep paths, bracket notation, chained calls, and batch operations.
Changed
with()selective resolution. Only changed properties are resolved; unchanged properties are carried over by reference, yielding a 44–68% performance improvement depending on nesting depth.with()deep path syntax now supports bracket notation (items[0].sku) and custom separators, in addition to existing dot notation.
Deprecated
#[DataTransferObject]attribute — useextends DataTransferObject.#[ValueObject]attribute — useextends ValueObject.#[Entity]attribute — removed entirely.