What PHP 7.4 Brought to PHP Development
PHP 7.4 was released in November 2019 as the final release in the PHP 7.x series before the significant changes introduced in PHP 8.0. This version brought practical improvements that made PHP code cleaner, more type-safe, and faster. For developers working with PHP applications, understanding these features helps you write better code today and prepares you for PHP 8.0, which removed several features that PHP 7.4 first deprecated.
This guide covers the most useful PHP 7.4 features with practical examples showing how to apply them in real projects.
Typed Properties in PHP 7.4
Typed properties allow you to declare type hints directly on class properties. Before PHP 7.4, type hints could only be used on function parameters and return types. Now you can enforce types on properties, catching bugs at the point of assignment rather than when the property is read later.
class User {
public int $id;
public string $name;
public ?string $email = null;
protected array $roles = [];
private bool $active = true;
}
The types you can use include int, float, string, bool, array, object, iterable, and class names or interfaces. Nullable types use the ? prefix before the type name.
Typed properties catch type errors early. When you assign an incorrect type, PHP throws a TypeError immediately at the assignment line.
$user = new User();
$user->id = 42; // Works fine
$user->name = "Alice"; // Works fine
$user->id = 'not_an_integer'; // TypeError: must be int, string given
Properties can have default values, but those defaults must match the declared type. This makes classes self-documenting and prevents a category of bugs that are difficult to trace when type mismatches occur somewhere downstream from the actual assignment.
For existing codebases, adding typed properties is straightforward. Start with new classes and gradually add types to existing properties when you modify them. This approach lets you improve type safety incrementally without large refactoring efforts.
Arrow Functions for Cleaner Callbacks
Arrow functions provide a concise syntax for single-expression functions. They are particularly useful when passing callbacks to array functions like array_map, array_filter, and array_reduce.
$numbers = [1, 2, 3, 4, 5];
// Traditional closure
$double = array_map(function ($n) {
return $n * 2;
}, $numbers);
// Arrow function
$double = array_map(fn($n) => $n * 2, $numbers);
Arrow functions automatically capture variables from the parent scope by value. This removes the need for a use clause that traditional closures require.
$multiplier = 3;
$result = array_map(fn($n) => $n * $multiplier, $numbers);
// Result: [3, 6, 9, 12, 15]
The limitation of arrow functions is that they support only a single expression. If you need multiple statements, multiple return points, or complex logic, use a traditional closure. Arrow functions cannot have a body block enclosed in braces, only a single expression whose value is returned automatically.
For simple data transformations in array operations, arrow functions reduce boilerplate significantly. The fn keyword signals intent clearly while keeping the code readable.
Argument and Return Type Widening
PHP 7.4 introduced proper covariance and contravariance for method overrides. In practical terms, a child class method can now return a more specific type than its parent, and can accept a more general type than its parent.
class Animal {
public function getSound(): Animal {
return $this;
}
}
class Dog extends Animal {
public function getSound(): Dog { // Valid: more specific return type
return $this;
}
}
class Cat extends Animal {
public function speak(Animal $animal): Animal {
return $animal;
}
}
For most application code, this change matters primarily when designing class hierarchies with inheritance. It gives you more flexibility when overriding methods in child classes without forcing exact type matches that may be unnecessarily restrictive.
Null Coalescing Assignment Operator
The null coalescing assignment operator ??= assigns a value to a variable only if the variable is currently null. This operator provides shorthand for a common pattern that appears frequently in configuration handling and default value assignment.
// Before PHP 7.4
if (!isset($config)) {
$config = 'localhost';
}
// With ??= in PHP 7.4
$config ??= 'localhost';
This operator is particularly useful when initialising configuration arrays or object properties with default values. It keeps code concise while remaining clear about intent.
$options['timeout'] ??= 30;
$user->displayName ??= 'Guest';
$settings['debug'] ??= false;
The ??= operator checks if the variable exists and is not null. It does not assign if the variable exists with an empty string, zero, or false. This distinction matters when those values are meaningful in your application.
Spread Operator in Array Expressions
PHP 7.4 allows the spread operator inside array expressions, not just in function arguments. This enables more readable array construction when combining static and dynamic data.
$base = ['a', 'b', 'c'];
$extended = [...$base, 'd', 'e', 'f'];
// Result: ['a', 'b', 'c', 'd', 'e', 'f']
Spread arrays are processed at compile time, which makes them faster than array_merge() for static arrays. When you know the contents at write time rather than generating them dynamically, spread syntax is the more efficient choice.
// Faster than array_merge for static arrays
$combined = [...$first, ...$second, ...$third];
The spread operator also works inside function calls with the same effect as in previous PHP versions.
function add($a, $b, $c) {
return $a + $b + $c;
}
echo add(...[1, 2, 3]); // 6
Note that spread syntax in array expressions requires string or integer keys. Using arrays with duplicate string keys results in the later value overwriting earlier ones, following the same behaviour as array_merge().
OPcache Preloading for Better Performance
OPcache preloading loads specified PHP files into shared memory at server startup, before any application code runs. All functions and classes in those files become available for every request without the overhead of loading and parsing the files each time.
This feature is configured in php.ini and points to a preload script that runs once when the server starts.
opcache.preload=/var/www/html/preload.php
The preload script compiles and caches the files you specify.
// preload.php
opcache_compile_file('/var/www/html/vendor/autoload.php');
opcache_compile_file('/var/www/html/src/MyClass.php');
opcache_compile_file('/var/www/html/src/AnotherClass.php');
Preloading provides measurable performance improvements for applications that load many files on every request, such as Symfony or Laravel applications. Startup time improvements of 10-20% are common in framework applications.
The trade-off is that changing any preloaded file requires a server restart. This makes preloading most suitable for production deployments where restarting the server is part of your deployment process. For development environments where files change frequently, preloading adds friction without benefit.
If you are running a PHP application on a dedicated server and want to improve response times, preloading is worth testing. Measure your application performance before and after to confirm the benefit for your specific setup.
Weak References for Memory-Efficient Caching
Weak references allow you to hold a reference to an object without preventing that object from being garbage collected. This is useful for caches and memoisation where you want to reference objects but allow them to be freed when memory pressure requires it.
$obj = new stdClass();
$ref = WeakReference::create($obj);
echo $ref->get() !== null ? 'Object exists' : 'Object collected';
// Output: Object exists
unset($obj);
echo $ref->get() !== null ? 'Object exists' : 'Object collected';
// Output: Object collected
For most application code, you will not use WeakReference directly. It is primarily relevant when building caching systems, ORM implementations, or other infrastructure that needs to track objects without preventing garbage collection.
If you are building a cache that stores computed results, weak references let you hold those results while allowing PHP to free memory when needed. This prevents caches from causing memory exhaustion in long-running processes.
Deprecated Features to Address Before PHP 8.0
PHP 7.4 deprecated several features that were removed in PHP 8.0. If you are upgrading from an earlier version or planning your migration to PHP 8.0, these deprecations tell you what to fix.
Real Type and Functions
The real type cast and functions using it are deprecated. Use float instead. Functions like realpath() remain available, but the real type itself is removed.
Parent Keyword Without Parent Class
Using parent in a class with no parent emits a deprecation warning. Ensure your class hierarchy is correct or remove the reference.
Magic Quotes Functions
get_magic_quotes_gpc() and get_magic_quotes_runtime() are deprecated. These were removed in PHP 5.4 and the functions have had no effect since then. Remove any calls to these functions from your codebase.
mbstring Function Aliases
Some mbstring function aliases are deprecated in favour of their full names. Check the PHP documentation for the recommended function names and update your code accordingly.
Installing PHP 7.4 on Ubuntu
The upgrade from PHP 7.3 to 7.4 is straightforward for most applications. On Ubuntu, you can add the Ondřej Surý PPA which provides current PHP packages.
sudo add-apt-repository ppa:ondrej/php
sudo apt update
sudo apt install php7.4 php7.4-fpm php7.4-mysql php7.4-cli php7.4-xml php7.4-mbstring
Set the default PHP CLI version if you have multiple versions installed.
sudo update-alternatives --set php /usr/bin/php7.4
Before deploying to production, run your test suite with PHP 7.4 and enable full error reporting.
error_reporting(E_ALL);
Any deprecation warnings in your code should be addressed, as they will become errors in PHP 8.0. Working through deprecations in PHP 7.4 makes your eventual upgrade to PHP 8.0 significantly smoother.
Moving Forward: PHP 8.0 Compatibility
PHP 7.4 receives security updates until late 2022, making it a stable choice for many applications. However, PHP 8.0 brought substantial changes including attributes, enums, named arguments, and readonly properties. If you are starting a new project, PHP 8.0 or later is worth considering for access to these modern features.
For existing applications running on earlier PHP versions, PHP 7.4 represents a safe intermediate step. It offers performance improvements and new syntax features without the breaking changes that PHP 8.0 introduced. Upgrading through PHP 7.4 first lets you address deprecations gradually before facing the larger changes in PHP 8.0.
A thorough approach to upgrading involves testing your application comprehensively under the new PHP version, fixing any deprecation warnings, and verifying that all functionality works correctly. For applications with custom code or older dependencies, this testing phase may take time but helps avoid issues in production.
Applying PHP 7.4 Features in Your Projects
PHP 7.4 introduced practical improvements that make PHP code more readable and performant. Typed properties catch type errors earlier, arrow functions reduce callback boilerplate, and OPcache preloading speeds up application startup for framework-based projects.
For most applications, adopting PHP 7.4 is straightforward. Test your code with the new version, address deprecation warnings, and deploy. The features in this version prepare your codebase for PHP 8.0 while still offering immediate benefits.
If you are working through a PHP version upgrade or need help optimising your application's PHP configuration, you can get in touch with details of your current setup and what you want to improve.