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
LiteDto2.779μs4.791μs2.940μs
LiteDto #[UltraFast]0.659μs0.825μs0.641μs
SimpleDto #[UltraFast]2.402μs4.737μs2.351μs
SimpleDto Normal16.359μs22.669μs16.192μs

Average: LiteDto is 5.4x 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~3.5μs~0.7μs~18.4μs~3.2μs
Validation
Type Casting
Property Mapping
Nested DTOs
Collections
Hidden Properties
Converter Support✅ (optional)✅ (optional)

When to use LiteDto:

  • You need maximum performance
  • You don’t need validation or type casting
  • You want simple, clean code

When to use SimpleDto:

  • You need validation (Required, Email, Min, Max, etc.)
  • You need type casting (DateTime, Enum, etc.)
  • You need computed properties or lazy loading
MetricLiteDtoLiteDto #[UltraFast]Other Dtos
Performance~3.5μs~0.7μ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