Skip to content

Performance Tips

LiteDto is designed for maximum performance, but there are still ways to optimize your usage.

Here are the actual benchmark results from our comprehensive tests:

ImplementationFrom ArrayTo ArrayComplex Data
LiteDto3.247μs6.447μs3.226μs
LiteDto #[UltraFast]2.642μs4.728μs2.598μs
SimpleDto #[UltraFast]5.708μs37.787μs5.742μs
SimpleDto Normal6.299μs38.534μs6.321μs

Average: LiteDto is 3.3x faster than SimpleDto Normal.

ConverterMode adds ~0.5μs overhead due to format detection and parsing.

// ❌ Slower: ConverterMode when only using arrays
#[ConverterMode]
class UserDto extends LiteDto
{
public function __construct(
public readonly string $name,
public readonly int $age,
) {}
}
$user = UserDto::from(['name' => 'John', 'age' => 30]); // ~2.8μs
// ✅ Faster: No ConverterMode for array-only usage
class UserDto extends LiteDto
{
public function __construct(
public readonly string $name,
public readonly int $age,
) {}
}
$user = UserDto::from(['name' => 'John', 'age' => 30]); // ~2.3μs

Rule: Only use #[ConverterMode] when you need to accept JSON, XML or other formats.

Each nested DTO adds overhead for reflection and instantiation.

// ❌ Slower: Deep nesting
class CountryDto extends LiteDto { /* ... */ }
class CityDto extends LiteDto {
public function __construct(
public readonly string $name,
public readonly CountryDto $country,
) {}
}
class AddressDto extends LiteDto {
public function __construct(
public readonly string $street,
public readonly CityDto $city,
) {}
}
class UserDto extends LiteDto {
public function __construct(
public readonly string $name,
public readonly AddressDto $address,
) {}
}
// ✅ Faster: Flatten when possible
class UserDto extends LiteDto {
public function __construct(
public readonly string $name,
public readonly string $street,
public readonly string $city,
public readonly string $country,
) {}
}

Rule: Only use nested DTOs when the structure truly benefits from it.

LiteDto requires readonly properties for immutability and performance.

// ✅ Correct: Readonly properties
class UserDto extends LiteDto
{
public function __construct(
public readonly string $name,
public readonly int $age,
) {}
}
// ❌ Wrong: Non-readonly properties (won't work)
class UserDto extends LiteDto
{
public function __construct(
public string $name, // Missing readonly
public int $age,
) {}
}

Each attribute adds a small overhead for reflection and processing.

// ❌ Slower: Many attributes
class UserDto extends LiteDto
{
public function __construct(
#[From('user_name'), To('full_name'), ConvertEmptyToNull]
public readonly ?string $name,
#[From('user_age'), To('age_years')]
public readonly int $age,
) {}
}
// ✅ Faster: Only necessary attributes
class UserDto extends LiteDto
{
public function __construct(
public readonly string $name,
public readonly int $age,
) {}
}

Rule: Only use attributes when you need the functionality.

When creating many DTOs, consider batching:

// ❌ Slower: Creating DTOs one by one in a loop
$users = [];
foreach ($apiData as $userData) {
$users[] = UserDto::from($userData);
}
// ✅ Faster: Use array_map for better performance
$users = array_map(
fn($userData) => UserDto::from($userData),
$apiData
);

If you’re using the same DTO multiple times, cache it:

// ❌ Slower: Creating same DTO multiple times
for ($i = 0; $i < 1000; $i++) {
$config = ConfigDto::from($configData);
// Use $config
}
// ✅ Faster: Create once, reuse
$config = ConfigDto::from($configData);
for ($i = 0; $i < 1000; $i++) {
// Use $config
}
FeatureLiteDtoLiteDto #[UltraFast]SimpleDto NormalSimpleDto #[UltraFast]
Performance~4.3μs~3.3μs~17.1μs~16.4μs
Validation
Type Casting
Property Mapping
Nested DTOs
Collections
Hidden Properties
Converter Support✅ (optional)✅ (optional)

When to use LiteDto:

  • You need maximum performance (~5x faster than SimpleDto)
  • You want validation and type casting with minimal overhead
  • You want simple, clean code

When to use SimpleDto:

  • You need advanced validation rules (RequiredIf, RequiredWith, etc.)
  • You need computed properties or lazy loading
  • You need framework-specific features (Laravel, Symfony)
MetricLiteDtoLiteDto #[UltraFast]Other Dtos
Performance~4.3μs~3.3μsN/A
Property Mapping
Hidden Properties
Nested DTOs
Collections
Converter Support✅ (optional)✅ (optional)
ConvertEmptyToNull

Why choose LiteDto?

  • No build step required
  • More features (Converter, ConvertEmptyToNull)
  • Better developer experience
  • Competitive performance with other Dto libraries
// 1000 requests/second
// LiteDto: ~2.3ms total overhead
// SimpleDto: ~18.5ms total overhead
// Savings: ~16.2ms per 1000 requests
Route::post('/users', function (Request $request) {
$user = UserDto::from($request->all()); // ~2.3μs
// Save to database
User::create($user->toArray());
return response()->json($user);
});
// Processing 10,000 records
// LiteDto: ~23ms total
// SimpleDto: ~185ms total
// Savings: ~162ms per 10,000 records
$users = array_map(
fn($data) => UserDto::from($data),
$csvData // 10,000 rows
);

Use PHPBench to profile your DTOs:

use PhpBench\Attributes\Revs;
use PhpBench\Attributes\Iterations;
class MyDtoBench
{
#[Revs(1000)]
#[Iterations(5)]
public function benchMyDto(): void
{
MyDto::from([
'name' => 'John',
'age' => 30,
]);
}
}

Run benchmarks:

Terminal window
vendor/bin/phpbench run benchmarks/MyDtoBench.php --report=default