PHP 7.4 Features: Typed Properties, Arrow Functions, and More

12 min read 2,317 words
PHP 7.4 Features Worth Knowing: Typed featured image

Understanding PHP 7.4: A Practical Overview

PHP 7.4 was released in November 2019 as the last minor release in the PHP 7.x series before PHP 8.0 introduced major changes to the language. This version brought several features that developers still use daily, including typed properties, arrow functions, and OPcache preloading. Understanding what PHP 7.4 introduced helps you write better code, whether you are maintaining older applications or comparing PHP versions to decide which to use for a new project.

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. Adding type safety to properties required getter and setter methods that performed validation. PHP 7.4 removed that requirement by letting you declare types directly on properties.

class User {
    public int $id;
    public string $name;
    public ?string $email = null;
    protected array $roles = [];
    private bool $active = true;
}

The supported types include int, float, string, bool, array, object, iterable, and any class name or interface. Nullable types use the ? prefix before the type name, as shown with ?string in the example above.

When you assign an incorrect type to a typed property, PHP throws a TypeError immediately at the assignment line. This behaviour catches bugs early, closer to their source, rather than allowing invalid data to propagate through your application until something else fails.

$user = new User();
$user->id = 42;              // Works correctly
$user->name = "Alice";       // Works correctly
$user->id = 'not_an_integer'; // TypeError: must be int, string given

Properties can have default values, but those defaults must match the declared type. Using default values makes your classes self-documenting and provides clear expectations for how the class should be initialised.

For existing codebases, you can add typed properties incrementally. Start with new classes, then add types to existing properties when you modify them. This approach lets you improve type safety over time without large refactoring efforts that risk introducing bugs.

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. The fn keyword declares an arrow function, and the expression to the right of => is returned automatically.

$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 the use clause that traditional closures require when accessing outer variables.

$multiplier = 3;
$result = array_map(fn($n) => $n * $multiplier, $numbers);
// Result: [3, 6, 9, 12, 15]

The limitation of arrow functions is their single-expression design. If you need multiple statements, complex logic, or multiple return points, use a traditional closure. Arrow functions cannot have a body block enclosed in braces. This constraint is by design—it keeps them short and readable for the cases where they are appropriate.

For simple data transformations in array operations, arrow functions reduce boilerplate significantly. The concise syntax makes the intent clear without the visual noise of a full closure declaration.

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. Previous PHP versions required exact type matches between parent and child method signatures.

class Animal {
    public function getSound(): Animal {
        return $this;
    }
}

class Dog extends Animal {
    public function getSound(): Dog {
        return $this;
    }
}

For most application code, this change matters when designing class hierarchies with inheritance. Covariance lets you use more specific return types in child classes, which improves type safety for code that calls those methods. Contravariance lets you accept broader parameter types, which provides more flexibility when overriding methods.

This feature gives you more freedom when designing inheritance structures without forcing exact type matches that may be unnecessarily restrictive for your use case.

Null Coalescing Assignment Operator

The null coalescing assignment operator ??= assigns a value to a variable only if the variable is currently null or does not exist. 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 and you want to preserve them rather than overwrite them with defaults.

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 where you know the contents at write time rather than generating them dynamically.

// 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

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 with a path to a preload script.

opcache.preload=/var/www/html/preload.php

The preload script compiles and caches the files you specify when the server starts.

// 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, which can translate to faster response times for end users.

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 such as those running in server environments.

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 indicate what needs fixing.

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 an earlier PHP version to PHP 7.4 is straightforward for most applications. On Ubuntu, you can add the Ondřej Surý PPA which provides current PHP packages for multiple versions.

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.

Preparing for PHP 8.0 and Beyond

PHP 7.4 receives security updates until late 2022, making it a stable choice for maintaining legacy 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.

Later PHP versions continued adding features that build on PHP 7.4 foundations. PHP 8.1 added readonly properties and enums, PHP 8.2 introduced readonly classes and constants in traits, and PHP 8.3 brought typed class constants and performance improvements. Each version builds on the type safety and syntax improvements that PHP 7.4 introduced.

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.

Related practical reading

These related guides can help you connect this topic with the wider website, server, security, and support decisions around it.

Putting PHP 7.4 Features to Work

PHP 7.4 introduced practical improvements that PHP developers still use daily. 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 provide immediate benefits while preparing your codebase for PHP 8.0.

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.

Frequently Asked Questions

What is the difference between typed properties and type hints on function parameters?
Type hints on function parameters check types when a function is called. Typed properties check types when a value is assigned to the property. Typed properties catch errors earlier, at the point of assignment, which makes debugging easier because the error location is closer to the actual problem source.
Should I use arrow functions or traditional closures?
Use arrow functions for simple single-expression callbacks, especially when working with array functions like array_map and array_filter. Use traditional closures when you need multiple statements, complex logic, or multiple return points. Arrow functions are more concise for simple cases; closures are more flexible for complex cases.
Does OPcache preloading work in development environments?
Preloading is most useful in production where files do not change between server restarts. In development, you restart the server frequently as you edit code, which negates the benefit. For local development, the performance improvement does not outweigh the inconvenience of restarting after every change.
How do I prepare for PHP 8.0 when using PHP 7.4?
Address every deprecation warning that appears when running your code under PHP 7.4. Pay particular attention to removed functions, changed default behaviours, and any code that relies on deprecated features. Running your test suite under both PHP 7.4 and PHP 8.0 helps identify issues before a full production migration.
Is PHP 7.4 still supported?
PHP 7.4 reached end of security support in November 2022. For new projects, use PHP 8.0 or later. For existing applications on PHP 7.4, plan an upgrade to a supported version. Running unsupported PHP versions poses security risks, as vulnerabilities are no longer patched.
Can I mix typed and untyped properties in the same class?
Yes, you can mix typed and untyped properties in the same class. Untyped properties behave as they did before PHP 7.4, accepting any value. When adding typed properties to existing code, you do not need to add types to every property at once.
When would I use WeakReference in a real application?
Weak references are useful when building caches that should not prevent objects from being garbage collected. For example, if you cache the results of expensive computations keyed to objects, a weak reference lets the cache entry disappear when the original object is no longer referenced elsewhere. This prevents memory leaks in long-running processes.