Performance Attributes
Performance attributes allow you to skip unnecessary operations for maximum DTO instantiation speed.
Quick Comparison
Section titled “Quick Comparison”| Attribute | Nested DTOs | Native Type Casts | Explicit #[Cast] | Validation | Other Attributes | Performance Gain |
|---|---|---|---|---|---|---|
| None | ✅ Auto | ❌ TypeError | ✅ Applied | ✅ Active | ✅ Active | Baseline (12.7μs) |
#[AutoCast] | ✅ Auto | ✅ Auto | ✅ Applied | ✅ Active | ✅ Active | -50% slower |
#[NoCasts] | ❌ TypeError | ❌ TypeError | ❌ Disabled | ✅ Active | ✅ Active | +37% faster |
#[NoValidation] | ✅ Auto | ❌ TypeError | ✅ Applied | ❌ Disabled | ✅ Active | +5% faster |
#[NoAttributes] | ✅ Auto | ❌ TypeError | ❌ Disabled | ❌ Disabled | ❌ Disabled | +5% faster |
#[NoAttributes, NoCasts] | ❌ TypeError | ❌ TypeError | ❌ Disabled | ❌ Disabled | ❌ Disabled | +34% faster |
#[UltraFast] | ✅ Auto | ❌ TypeError | ❌ Disabled | ❌ Disabled | ❌ Disabled | +639% faster (1.7μs) 🚀 |
Available Attributes
Section titled “Available Attributes”#[UltraFast] ⚡
Section titled “#[UltraFast] ⚡”NEW! Bypass ALL SimpleDto overhead for maximum performance.
Use when:
- You need maximum speed (7.4x faster than normal SimpleDto)
- You only need basic mapping (#[MapFrom], #[MapTo])
- Input data is already validated and correctly typed
- You’re processing large datasets
Performance Impact:
- 639% faster than normal SimpleDto! 🚀
- 1.723μs vs 12.740μs (normal mode)
- Only 5.5x slower than other minimalist Dto libraries
- 2.4x less memory (2.7mb vs 6.7mb)
What gets disabled:
- ❌ All validation
- ❌ All type casting
- ❌ All lazy loading
- ❌ All optional properties
- ❌ All computed properties
- ❌ All pipeline steps
- ❌ Cache overhead
What stays active:
- ✅
#[MapFrom]attribute (configurable) - ✅
#[MapTo]attribute (configurable) - ✅ Nested DTO auto-casting
- ✅ Basic fromArray/toArray functionality
Example:
use event4u\DataHelpers\SimpleDto;use event4u\DataHelpers\SimpleDto\Attributes\UltraFast;use event4u\DataHelpers\SimpleDto\Attributes\MapFrom;
#[UltraFast]class FastUserDto extends SimpleDto{ public function __construct( #[MapFrom('user_name')] public readonly string $name, public readonly string $email, public readonly int $age, ) {}}
// Create from array (1.7μs)$user = FastUserDto::fromArray([ 'user_name' => 'John Doe', 'email' => 'john@example.com', 'age' => 30,]);Automatic Attribute Detection:
#[UltraFast] automatically detects and processes #[MapFrom], #[MapTo], #[CastWith] and #[Hidden] attributes if they are present on properties. No configuration needed!
use event4u\DataHelpers\SimpleDto\Attributes\Hidden;
#[UltraFast]class AutoDetectDto extends SimpleDto{ public function __construct( #[MapFrom('old_name')] public readonly string $name, // Automatically detected!
public readonly string $email,
#[Hidden] public readonly string $password, // Automatically hidden! ) {}}
$dto = AutoDetectDto::fromArray([ 'old_name' => 'John', 'email' => 'john@example.com', 'password' => 'secret123',]);
$array = $dto->toArray();// ['name' => 'John', 'email' => 'john@example.com']// password is hidden!#[NoCasts]
Section titled “#[NoCasts]”Skip ALL type casting operations for maximum performance.
Use when:
- Your data is already in the correct types
- You control the data source (e.g., from database)
- You need maximum performance
- You want strict type checking
Performance Impact:
- 34-63% faster DTO instantiation! 🚀
- No type coercion overhead
- Strict type checking only
What gets disabled:
- ❌ Nested DTO auto-casting (arrays won’t be converted to DTOs)
- ❌ Native type casts (even with
#[AutoCast]) - ❌ Explicit
#[Cast]attributes - ❌ All casting operations
What stays active:
- ✅ Validation attributes
- ✅ Visibility attributes
- ✅ Mapping attributes
- ✅ All other attributes
Example with Native Types:
use event4u\DataHelpers\SimpleDto;use event4u\DataHelpers\SimpleDto\Attributes\NoCasts;
#[NoCasts]class StrictDto extends SimpleDto{ public function __construct( public readonly string $name, public readonly int $age, public readonly float $salary, ) {}}
// ✅ Works - correct types$dto = StrictDto::fromArray([ 'name' => 'John Doe', 'age' => 30, 'salary' => 50000.00,]);
// ❌ TypeError - wrong types, no casting at all$dto = StrictDto::fromArray([ 'name' => 'John Doe', 'age' => '30', // ← TypeError: string instead of int 'salary' => 50000.00,]);Example with Nested DTOs:
use event4u\DataHelpers\SimpleDto;use event4u\DataHelpers\SimpleDto\Attributes\NoCasts;
class AddressDto extends SimpleDto{ public function __construct( public readonly string $street, public readonly string $city, ) {}}
#[NoCasts]class UserDto extends SimpleDto{ public function __construct( public readonly string $name, public readonly AddressDto $address, ) {}}
// ❌ TypeError - array is not auto-casted with #[NoCasts]$user = UserDto::fromArray([ 'name' => 'John', 'address' => ['street' => 'Main St', 'city' => 'NYC'], // ← TypeError!]);
// ✅ Works - pass AddressDto object$user = UserDto::fromArray([ 'name' => 'John', 'address' => AddressDto::fromArray(['street' => 'Main St', 'city' => 'NYC']),]);#[NoAttributes]
Section titled “#[NoAttributes]”Skip all attribute reflection and processing.
Use when:
- You don’t need any attributes on your DTO
- You want to reduce memory usage
- You have a simple DTO with just properties
Performance Impact:
- Skips reflection of all property attributes
- Reduces memory usage
- ~0-5% faster (only noticeable with many attributes)
What gets disabled:
- ❌ Validation attributes (
#[Required],#[Email], etc.) - ❌ Visibility attributes (
#[Visible],#[Hidden], etc.) - ❌ Cast attributes (
#[Cast],#[AutoCast], etc.) - ❌ Conditional attributes (
#[WhenValue],#[WhenContext], etc.) - ❌ Mapping attributes (
#[MapFrom],#[MapTo]) - ❌ All other property attributes
What stays active:
- ✅ Nested DTO auto-casting (always active unless
#[NoCasts]is used)
Example:
use event4u\DataHelpers\SimpleDto;use event4u\DataHelpers\SimpleDto\Attributes\NoAttributes;
#[NoAttributes]class FastDto extends SimpleDto{ public function __construct( public readonly string $name, public readonly int $age, public readonly AddressDto $address, ) {}}
// ✅ Nested DTOs still work!$dto = FastDto::fromArray([ 'name' => 'John', 'age' => 30, 'address' => ['street' => 'Main St', 'city' => 'NYC'], // ← Auto-casted to AddressDto]);
// ❌ TypeError - native types need correct types (no AutoCast)$dto = FastDto::fromArray([ 'name' => 'John', 'age' => '30', // ← TypeError: string instead of int]);#[NoValidation]
Section titled “#[NoValidation]”Skip all validation operations.
Use when:
- You trust your data source
- Data is already validated elsewhere
- You need maximum performance
- You’re in a high-throughput scenario
Performance Impact:
- Skips all validation logic
- No validation rule extraction
- Faster DTO instantiation
Example:
use event4u\DataHelpers\SimpleDto;use event4u\DataHelpers\SimpleDto\Attributes\NoValidation;use event4u\DataHelpers\SimpleDto\Attributes\Required;use event4u\DataHelpers\SimpleDto\Attributes\Email;
#[NoValidation]class TrustedDto extends SimpleDto{ public function __construct( #[Required, Email] // These are ignored! public readonly string $email, public readonly int $age, ) {}}
// ✅ Works - no validation performed$dto = TrustedDto::fromArray([ 'email' => 'invalid-email', // No validation! 'age' => 25,]);What gets disabled:
- ❌ Validation attributes (
#[Required],#[Email], etc.) - ❌ Auto-inferred validation rules
- ❌ Custom validation rules
What still works:
- ✅ Type casts (unless
#[NoCasts]is also used) - ✅ Visibility attributes
- ✅ Conditional attributes
- ✅ Mapping attributes
- ✅ All other non-validation attributes
How Attributes Interact
Section titled “How Attributes Interact”Understanding how performance attributes interact is crucial for choosing the right optimization:
Casting Behavior Matrix
Section titled “Casting Behavior Matrix”| Scenario | Nested DTOs | Native Types | Explicit #[Cast] |
|---|---|---|---|
| No attributes | ✅ Auto-casted | ❌ TypeError | ✅ Applied |
#[AutoCast] | ✅ Auto-casted | ✅ Auto-casted | ✅ Applied |
#[NoCasts] | ❌ TypeError | ❌ TypeError | ❌ Disabled |
#[NoAttributes] | ✅ Auto-casted | ❌ TypeError | ❌ Disabled |
#[NoAttributes, NoCasts] | ❌ TypeError | ❌ TypeError | ❌ Disabled |
Key Insights
Section titled “Key Insights”- Nested DTOs are special: They’re auto-casted by default (unlike native types)
#[NoCasts]is the only way to disable nested DTO auto-casting#[NoAttributes]disables#[Cast]attributes but NOT nested DTO auto-casting#[AutoCast]is opt-in for native types only- Combining both gives maximum performance but requires exact types
Decision Tree
Section titled “Decision Tree”Do you have nested DTOs?├─ YES → Use #[NoCasts] only if you can pass DTO objects│ Otherwise, don't use #[NoCasts]└─ NO → Use #[NoCasts] for maximum performance
Do you need validation?├─ YES → Don't use #[NoValidation] or #[NoAttributes]└─ NO → Use #[NoValidation] for +5% performance
Do you use any attributes (#[Cast], #[MapFrom], etc.)?├─ YES → Don't use #[NoAttributes]└─ NO → Use #[NoAttributes] for cleaner codeCombining Attributes
Section titled “Combining Attributes”You can combine multiple performance attributes for maximum optimization:
Common Combinations
Section titled “Common Combinations”| Combination | Use Case | Performance Gain |
|---|---|---|
#[NoCasts] | Trusted data with correct types | +37% faster |
#[NoValidation] | Pre-validated data | +5% faster |
#[NoCasts, NoValidation] | Trusted, pre-validated data | +34% faster |
#[NoAttributes] | Simple DTOs without attributes | +5% faster |
#[NoAttributes, NoCasts] | Maximum performance | +34% faster |
Option 1: Skip Casts and Validation (Recommended)
Section titled “Option 1: Skip Casts and Validation (Recommended)”Best for trusted data sources (e.g., internal APIs, database queries):
use event4u\DataHelpers\SimpleDto;use event4u\DataHelpers\SimpleDto\Attributes\NoCasts;use event4u\DataHelpers\SimpleDto\Attributes\NoValidation;
#[NoCasts, NoValidation]class FastDto extends SimpleDto{ public function __construct( public readonly string $name, public readonly int $age, ) {}}Best for: Trusted data sources where you control the types and validation is done elsewhere.
Option 2: Skip All Attributes (Keep Nested DTO Casts)
Section titled “Option 2: Skip All Attributes (Keep Nested DTO Casts)”use event4u\DataHelpers\SimpleDto;use event4u\DataHelpers\SimpleDto\Attributes\NoAttributes;
class AddressDto extends SimpleDto{ public function __construct( public readonly string $street, public readonly string $city, ) {}}
#[NoAttributes]class UserDto extends SimpleDto{ public function __construct( public readonly string $name, public readonly int $age, public readonly AddressDto $address, ) {}}
// ✅ Nested DTOs still work!$dto = UserDto::fromArray([ 'name' => 'John', 'age' => 30, 'address' => ['street' => 'Main St', 'city' => 'NYC'], // ← Auto-casted!]);
// ❌ TypeError - native types need correct types (no AutoCast)$dto = UserDto::fromArray([ 'name' => 'John', 'age' => '30', // ← TypeError: string instead of int]);Best for: Simple DTOs with nested DTOs where you don’t need validation or other attributes.
Option 3: Maximum Performance (No Casts, No Attributes)
Section titled “Option 3: Maximum Performance (No Casts, No Attributes)”use event4u\DataHelpers\SimpleDto;use event4u\DataHelpers\SimpleDto\Attributes\NoAttributes;use event4u\DataHelpers\SimpleDto\Attributes\NoCasts;
#[NoAttributes, NoCasts]class UltraFastDto extends SimpleDto{ public function __construct( public readonly string $name, public readonly int $age, ) {}}
// ✅ Works - correct types$dto = UltraFastDto::fromArray([ 'name' => 'John', 'age' => 30,]);
// ❌ TypeError - no casting at all$dto = UltraFastDto::fromArray([ 'name' => 'John', 'age' => '30', // ← TypeError]);Performance Impact:
- ~32-35% faster than normal DTOs
- Minimal overhead
- Perfect for high-performance APIs
Best for: Absolute maximum performance when data is already in correct types.
Selective Optimization
Section titled “Selective Optimization”Use only what you need:
// Only skip casts, keep validation#[NoCasts]class ValidatedDto extends SimpleDto{ public function __construct( #[Required, Email] // Validation still works! public readonly string $email, public readonly int $age, ) {}}
// Only skip validation, keep casts#[NoValidation]class CastedDto extends SimpleDto{ public function __construct( public readonly string $email, public readonly int $age, ) {}
protected function casts(): array { return ['age' => 'integer']; // Casts still work! }}Performance Benchmarks
Section titled “Performance Benchmarks”Basic DTO (10,000 iterations)
Section titled “Basic DTO (10,000 iterations)”Normal DTO: 1.6 μs (baseline)#[NoCasts]: 1.05 μs (34% faster)#[NoAttributes]: 1.61 μs (no difference without attributes)Both: 1.08 μs (32% faster)With AutoCast (10,000 iterations)
Section titled “With AutoCast (10,000 iterations)”AutoCast DTO: 3.09 μs (with type casting)#[NoCasts]: 1.13 μs (63% faster!)Real-World API (1,000 DTOs)
Section titled “Real-World API (1,000 DTOs)”Normal DTO: 1.6ms#[NoCasts]: 1.05ms (34% faster)Both: 1.08ms (32% faster)
Savings per 1M requests: ~550msUse Cases
Section titled “Use Cases”High-Performance API
Section titled “High-Performance API”#[NoCasts]class ApiResponseDto extends SimpleDto{ public function __construct( public readonly int $id, public readonly string $name, public readonly float $price, ) {}}
// Data from database is already typed correctly$dto = ApiResponseDto::fromArray($dbRow);Internal Data Transfer
Section titled “Internal Data Transfer”#[NoAttributes, NoCasts]class InternalDto extends SimpleDto{ public function __construct( public readonly string $key, public readonly mixed $value, ) {}}
// Fast internal data transfer between services$dto = InternalDto::fromArray(['key' => 'cache_key', 'value' => $data]);Batch Processing
Section titled “Batch Processing”#[NoCasts]class BatchItemDto extends SimpleDto{ public function __construct( public readonly int $id, public readonly string $status, ) {}}
// Process 10,000 items 34% faster$dtos = array_map( fn($item) => BatchItemDto::fromArray($item), $items);When NOT to Use
Section titled “When NOT to Use”Don’t use #[NoCasts] when:
Section titled “Don’t use #[NoCasts] when:”❌ Data from external APIs - Types may vary
// Bad - API might return strings#[NoCasts]class ApiDto extends SimpleDto { ... }❌ User input - Always needs validation and casting
// Bad - user input needs casting#[NoCasts]class FormDto extends SimpleDto { ... }❌ Mixed data sources - Types not guaranteed
// Bad - data from multiple sources#[NoCasts]class MixedDto extends SimpleDto { ... }Don’t use #[NoAttributes] when:
Section titled “Don’t use #[NoAttributes] when:”❌ Need validation - Validation attributes won’t work
// Bad - validation won't work#[NoAttributes]class UserDto extends SimpleDto { public function __construct( #[Required, Email] // Won't work! public readonly string $email, ) {}}❌ Need visibility control - Conditional attributes won’t work
// Bad - visibility control won't work#[NoAttributes]class SecureDto extends SimpleDto { public function __construct( #[WhenAuth] // Won't work! public readonly string $secret, ) {}}Best Practices
Section titled “Best Practices”- Use
#[NoCasts]for database DTOs - Data is already typed - Use both for internal DTOs - Maximum performance
- Don’t use for user input - Always validate and cast
- Benchmark your use case - Measure the impact
- Document the decision - Explain why you’re using them
See Also
Section titled “See Also”- Performance Optimization - Complete optimization guide
- Attributes Overview - All available attributes
- Performance Benchmarks - Detailed benchmarks