Practical PHP 8 New Features - From Scratch
PHP 8, released on November 26, 2020, introduced a range of exciting features that enhance the language's performance, flexibility, and developer experience. This blog post will guide you through the most significant PHP 8 features, complete with practical examples, best practices, and actionable insights to help you leverage these features effectively.
Table of Contents
- Union Types
- Intersection Types
- Null Safe Operator
- Attributes (Annotations)
- Match Expression
- Typed Properties
- New String Functions
- Best Practices and Recommendations
- Conclusion
1. Union Types
Union types allow you to specify that a variable, parameter, or return type can be one of several types. This enhances type safety by providing more flexibility than traditional scalar type hinting.
Example:
<?php
function processInput(mixed $value): void {
if (is_string($value)) {
echo "Input is a string: $value\n";
} elseif (is_int($value)) {
echo "Input is an integer: $value\n";
} else {
echo "Unsupported type\n";
}
}
// Using Union Types
function processInputWithUnionTypes(mixed $value): void {
if ($value instanceof String || $value instanceof Int) {
echo "Input is valid: $value\n";
} else {
echo "Unsupported type\n";
}
}
Best Practice:
Use union types when a function can accept multiple types but still maintain type safety.
2. Intersection Types
Intersection types, introduced in PHP 8.1, allow you to specify that a variable must be compatible with multiple types simultaneously. This is particularly useful when working with interfaces and classes.
Example:
<?php
interface Logger {
public function log(string $message): void;
}
interface Cache {
public function set(string $key, mixed $value): void;
}
// A class that implements both Logger and Cache
class LoggerCache implements Logger, Cache {
public function log(string $message): void {
echo "Logging: $message\n";
}
public function set(string $key, mixed $value): void {
echo "Caching key: $key, value: $value\n";
}
}
function processLoggerCache(Logger&Cache $obj): void {
$obj->log("This is a log message");
$obj->set("key", "value");
}
$loggerCache = new LoggerCache();
processLoggerCache($loggerCache);
Best Practice:
Use intersection types when you want to enforce that a variable must implement multiple interfaces or extend multiple classes.
3. Null Safe Operator
The null safe operator (?->
) simplifies the handling of null values and reduces the need for verbose null checks. It allows you to safely access properties or call methods on an object that may be null.
Example:
<?php
class User {
public function __construct(public ?Address $address) {}
}
class Address {
public function __construct(public string $city) {}
}
$user = new User(null);
$city = $user?->address?->city;
// Before PHP 8:
$city = isset($user->address) ? $user->address->city : null;
Best Practice:
Use the null safe operator to simplify null checks and make your code more readable.
4. Attributes (Annotations)
Attributes, also known as annotations, allow you to attach metadata to classes, methods, and properties. This is particularly useful for frameworks and libraries that need to process additional information about code elements.
Example:
<?php
#[Attribute(Attribute::TARGET_CLASS)]
class Entity {
public string $table;
public function __construct(string $table) {
$this->table = $table;
}
}
#[Entity("users")]
class User {
public function __construct(public string $name) {}
}
// Accessing attributes at runtime
$reflection = new ReflectionClass(User::class);
$attributes = $reflection->getAttributes(Entity::class);
foreach ($attributes as $attribute) {
$entity = $attribute->newInstance();
echo "Entity table: " . $entity->table . "\n";
}
Best Practice:
Use attributes to add metadata to your code, making it easier for frameworks to process and understand your classes, methods, or properties.
5. Match Expression
The match
expression is a more concise and readable way to write switch statements. It evaluates an expression against a set of patterns and returns a value.
Example:
<?php
function getGreeting(string $time): string {
return match ($time) {
'morning' => 'Good morning!',
'afternoon' => 'Good afternoon!',
'evening' => 'Good evening!',
default => 'Hello!',
};
}
echo getGreeting('morning'); // Output: Good morning!
Best Practice:
Use the match
expression for simple conditional logic where you need to evaluate an expression against multiple patterns and return values.
6. Typed Properties
Typed properties allow you to specify the type of a property directly in the class definition. This enhances type safety and makes the code more self-documenting.
Example:
<?php
class User {
public string $name;
public int $age;
public function __construct(string $name, int $age) {
$this->name = $name;
$this->age = $age;
}
}
$user = new User("John", 30);
Best Practice:
Always use typed properties to enhance type safety and make your code more maintainable.
7. New String Functions
PHP 8 introduced several new string functions that make string manipulation more powerful and efficient.
Example:
<?php
// str_contains() - Checks if a string contains a substring
echo str_contains("Hello World", "World") ? "Found\n" : "Not found\n";
// str_starts_with() - Checks if a string starts with a substring
echo str_starts_with("Hello World", "Hello") ? "Starts with Hello\n" : "Does not start with Hello\n";
// str_ends_with() - Checks if a string ends with a substring
echo str_ends_with("Hello World", "World") ? "Ends with World\n" : "Does not end with World\n";
Best Practice:
Use these new string functions for more concise and readable string checks.
8. Best Practices and Recommendations
-
Leverage Type Safety: Use union types, intersection types, and typed properties to enhance type safety and improve code maintainability.
-
Simplify Null Checks: The null safe operator (
?->
) simplifies null checks and makes your code more readable. Use it whenever possible. -
Embrace Modern Syntax: Utilize new features like the
match
expression and string functions to write cleaner and more efficient code. -
Use Attributes Wisely: Attributes are powerful but should be used judiciously. Avoid overusing them to prevent unnecessary complexity.
-
Profile and Test: As you adopt PHP 8 features, ensure you profile your application to identify performance improvements or potential bottlenecks.
9. Conclusion
PHP 8 introduces a range of features that significantly enhance the language's capabilities and developer experience. By leveraging union types, intersection types, the null safe operator, attributes, the match
expression, and new string functions, you can write more robust, maintainable, and efficient code.
Remember to follow best practices and test your code thoroughly as you migrate to PHP 8. These new features not only improve the language but also set the stage for future innovations in PHP development.
Happy coding! 🚀
References: