Search by

diego-ninja / granite

diego.ninja

A lightweight zero-dependency PHP library for building immutable, serializable objects with validation capabilities.

Package info

github.com/diego-ninja/granite

pkg:composer/diego-ninja/granite

Statistics

Installs: 977

Dependents: 1

Suggesters: 0

Stars: 58

Open Issues: 1


README

Latest Version on Packagist Total Downloads PHP Version License: MIT GitHub last commit wakatime

Tests Static Analysis Code Style Coveralls

A powerful, zero-dependency PHP library for building immutable, serializable objects with validation and mapping capabilities. Perfect for DTOs, Value Objects, API responses, and domain modeling.

๐Ÿชถ Pebble - Lightweight Immutable Snapshots

Pebble is a lightweight alternative to Granite for defensive, immutable snapshots without validation overhead โ€” ideal for caching, Eloquent snapshots, and fast comparisons. Nested arrays, userland objects, and dates are copied so later source mutations cannot change the snapshot.

$snapshot = Pebble::from($eloquentModel);

$snapshot->name;           // Magic __get
$snapshot['email'];        // ArrayAccess
$snapshot->equals($other); // O(1) fingerprint comparison

๐Ÿ“– Read Pebble Documentation

โœจ Features

  • Immutable Objects โ€” Read-only DTOs and Value Objects, thread-safe by design
  • Flexible from() Method โ€” Create from arrays, JSON, named parameters, other Granite objects, or mix them
  • Comprehensive Validation โ€” 30+ built-in rules including Carbon date validation (Age, Future, Past, BusinessDay...)
  • ObjectMapper โ€” Convention-based property mapping between objects with custom transformations
  • Smart Serialization โ€” Custom property names, naming conventions, hidden fields, Carbon date formats
  • Object Comparison โ€” Deep equality with equals(), detailed diffs with differs()
  • Performance Optimized โ€” Conservative fast path for simple DTOs, deep immutable WeakMap caching, direct property access

๐Ÿš€ Quick Start

Installation

composer require diego-ninja/granite

Basic Usage

use Ninja\Granite\Granite;
use Ninja\Granite\Validation\Attributes\Required;
use Ninja\Granite\Validation\Attributes\Email;
use Ninja\Granite\Validation\Attributes\Min;
use Ninja\Granite\Serialization\Attributes\Hidden;

final readonly class User extends Granite
{
    public function __construct(
        #[Required]
        #[Min(2)]
        public string $name,

        #[Required]
        #[Email]
        public string $email,

        #[Hidden]
        public ?string $password = null,
    ) {}
}

// Create from array
$user = User::from(['name' => 'John Doe', 'email' => 'john@example.com', 'password' => 'secret']);

// Create from named parameters
$user = User::from(name: 'John Doe', email: 'john@example.com');

// Immutable updates
$updated = $user->with(['name' => 'Jane Doe']);

// Serialization (password hidden automatically)
$json = $user->json();   // {"name":"John Doe","email":"john@example.com"}
$array = $user->array();

๐Ÿ“– Documentation

Core Concepts

  • Enhanced from() Method โ€” Multiple invocation patterns for flexible object creation
  • Validation โ€” Comprehensive validation system with 30+ built-in rules including Carbon
  • Serialization โ€” Control how objects are converted to/from arrays and JSON with Carbon support
  • Object Comparison โ€” Deep equality checks and difference detection
  • ObjectMapper โ€” Powerful object-to-object mapping with conventions
  • Pebble โ€” Lightweight immutable snapshots with fingerprinting
  • Advanced Usage โ€” Patterns for complex applications
  • API Reference โ€” Complete API documentation

Guides

๐Ÿ“ˆ Performance & Benchmarks

Granite uses a multi-layer fast path system that detects simple DTOs at class-load time and bypasses the full hydration pipeline (reflection, metadata, type conversion) entirely. For objects that qualify, the overhead vs plain PHP constructors is minimal.

Benchmark Results

Measured on PHP 8.5.10 with OPcache CLI enabled, using the median of 7 repetitions with 100,000 operations each:

Scenario ยตs/op Improvement
Plain PHP constructor 0.147 control
Granite::from(array) 0.284 โ€”
Granite::from(JSON) 1.019 6.11x faster
Granite::from(object) 1.000 5.59x faster
Granite::from(Granite) 0.898 7.50x faster
Array-property DTO hydration 0.201 11.69x faster
Validated DTO hydration 4.691 1.96x faster
Cached array() 0.040 22.58x faster
Cached nested array() 0.040 31.56x faster
General array serialization 1.175 1.39x faster
ObjectMapper to plain object 1.869 1.11x faster
ObjectMapper to Granite 1.550 1.14x faster

Improvements compare the same benchmark against the pre-optimization baseline. Full samples and methodology are recorded in the performance optimization plan.

How it works

Granite's performance comes from three layers of optimization:

  1. Capability-specific fast paths (ClassProfile) โ€” Hydration, serialization, and comparison are evaluated independently. Exact array properties can use constructor hydration while still using recursive general serialization.

  2. WeakMap caching โ€” array() and json() results are read before repeating graph analysis and are cached only for deeply immutable graphs. Runtime serialization configuration invalidates cached values.

  3. Compiled metadata โ€” Reflection objects, validation attributes, validators, class date providers, and property transformers are reused across operations.

Classes that need conversion or custom naming use the general pipeline, with cached metadata and early exits for scalar values.

Running the Benchmarks

php benchmarks/GraniteBench.php
composer bench:objects
composer bench:objects -- --json --iterations=100000 --repetitions=7

โš ๏ธ Deprecation Notice

GraniteDTO was already deprecated before v2.0.0, and GraniteVO is deprecated as of v2.0.0, in favor of the unified Granite base class. Both still extend Granite for backward compatibility but will be removed in v3.0.0.

// โŒ Deprecated โ€” use Granite instead
final readonly class User extends GraniteVO { }
// โœ…
final readonly class User extends Granite { }

๐Ÿ”ง Requirements

  • PHP 8.3+ โ€” Takes advantage of modern PHP features
  • No dependencies โ€” Zero external dependencies for maximum compatibility

๐Ÿ“ฆ Installation

composer require diego-ninja/granite

๐Ÿค Contributing

Contributions are welcome! Please see CONTRIBUTING.md for details.

๐Ÿ“„ License

This package is open-sourced software licensed under the MIT license.

๐Ÿ™ Credits

This project is developed and maintained by ๐Ÿฅท Diego Rin in his free time.

If you find this project useful, please consider:

  • โญ Starring the repository
  • ๐Ÿ› Reporting bugs and issues
  • ๐Ÿ’ก Suggesting new features
  • ๐Ÿ”ง Contributing code improvements

Made with โค๏ธ for the PHP community