Named Arguments
Pass arguments by name instead of position for clearer code:
<?php
function createUser(
string $name,
string $email,
string $role = 'user',
bool $sendWelcomeEmail = true,
?string $avatar = null
): User {
// Implementation
}
// Old way - hard to read
createUser('John', 'john@example.com', 'admin', true, null);
// With named arguments - crystal clear
createUser(
name: 'John',
email: 'john@example.com',
role: 'admin',
sendWelcomeEmail: true,
);
// Skip optional arguments
createUser(
name: 'Jane',
email: 'jane@example.com',
avatar: 'https://example.com/avatar.jpg',
);
Constructor Property Promotion
Reduce boilerplate in your classes:
<?php
// Before PHP 8
class Point
{
public float $x;
public float $y;
public float $z;
public function __construct(float $x, float $y, float $z)
{
$this->x = $x;
$this->y = $y;
$this->z = $z;
}
}
// PHP 8 - Constructor Property Promotion
class Point
{
public function __construct(
public float $x,
public float $y,
public float $z,
) {}
}
// With readonly (PHP 8.1+)
class User
{
public function __construct(
public readonly int $id,
public readonly string $name,
public string $email,
) {}
}
Match Expression
A more powerful alternative to switch statements:
<?php
// Old switch statement
switch ($status) {
case 'draft':
$label = 'Document is in draft';
break;
case 'published':
$label = 'Document is live';
break;
case 'archived':
$label = 'Document is archived';
break;
default:
$label = 'Unknown status';
}
// PHP 8 match expression
$label = match($status) {
'draft' => 'Document is in draft',
'published' => 'Document is live',
'archived' => 'Document is archived',
default => 'Unknown status',
};
// Match with multiple conditions
$emoji = match($status) {
'draft', 'pending' => '📝',
'published', 'active' => '✅',
'archived', 'deleted' => '📦',
default => '❓',
};
Nullsafe Operator
Safely access nested nullable properties:
<?php
// Before PHP 8 - verbose null checks
$country = null;
if ($user !== null) {
$address = $user->getAddress();
if ($address !== null) {
$country = $address->country;
}
}
// PHP 8 - Nullsafe operator
$country = $user?->getAddress()?->country;
// Combining with null coalescing
$countryName = $user?->address?->country?->name ?? 'Unknown';
Attributes
Native metadata annotations in PHP:
<?php
use Attribute;
#[Attribute(Attribute::TARGET_METHOD)]
class Route
{
public function __construct(
public string $path,
public string $method = 'GET',
) {}
}
class UserController
{
#[Route('/users', method: 'GET')]
public function index(): array
{
return User::all()->toArray();
}
#[Route('/users/{id}', method: 'GET')]
public function show(int $id): array
{
return User::findOrFail($id)->toArray();
}
#[Route('/users', method: 'POST')]
public function store(): array
{
// Create user
}
}
Conclusion
PHP 8 brings significant improvements to the language. Start using these features today to write cleaner, more maintainable code.