Modernizing Your Codebase with PHP 8's Union Types
Jul 27, 2025 am 04:33 AMUpgrade PHP 7.x codebases to PHP 8 by replacing PHPDoc-suggested types like @param string|int with native union types such as string|int for parameters and return types, which improves type safety and clarity; 2. Apply union types to mixed input parameters (e.g., int|string for IDs), nullable or multi-type values (e.g., string|int|null), and functions returning multiple possible types (e.g., User|false); 3. Follow best practices by avoiding the mixed type, ordering union types consistently (e.g., most common first), enabling declare(strict_types=1), removing redundant PHPDoc annotations, and ensuring IDE and tooling compatibility with PHP 8 ; 4. Avoid pitfalls such as using void or mixed in unions, being overly broad with object types, and neglecting to update tooling; 5. Refactor examples like parseValue to use native union types, resulting in cleaner, safer, and self-documenting code that catches errors earlier and enhances developer experience.
Upgrading your PHP codebase to take advantage of PHP 8’s union types isn’t just about using a new syntax — it’s a chance to make your code more expressive, self-documenting, and less error-prone. If you're moving from PHP 7.x to PHP 8 , union types can significantly improve type safety and clarity, especially in real-world applications where variables or parameters often accept more than one type.

Here’s how to effectively modernize your code using union types.
What Are Union Types?
In PHP 8.0, union types allow you to specify that a parameter, return value, or property can be one of several types. Before PHP 8, you either relied on PHPDoc comments or no type hints at all:

// PHP 7 - no native union support /** * @param string|int $id * @return array|bool */ function findUser($id) { ... }
Now, with PHP 8, you can express this directly in the signature:
function findUser(int|string $id): array|bool { // ... }
This is enforced at runtime, so invalid types trigger a TypeError
, and IDEs can provide better autocompletion and analysis.

Where to Apply Union Types in Your Codebase
Look for these common patterns when upgrading:
1. Parameters with Mixed Input Types
Many functions accept IDs that could be integers or strings (e.g., UUIDs vs. auto-incremented DB IDs):
public function loadRecord(int|string $id): ?object { // ... }
This replaces ambiguous mixed
or loose string
casts and makes valid inputs explicit.
2. Nullable Types (Better Than ?Type
)
While ?string
is shorthand for string|null
, union types give you more flexibility:
function setStatus(string|int|null $status): void { ... }
Here, ?string
wouldn’t cover int
, so union types are necessary.
3. Return Types with Multiple Possibilities
Functions that return data or false
on failure (a common PHP pattern) can now be accurately typed:
function findByEmail(string $email): User|false { return $this->users->find($email) ?: false; }
Even better: consider returning ?User
(i.e., User|null
) instead and reserve false
for exceptional cases — but if your codebase uses false
, at least now it's documented.
Best Practices When Modernizing
Avoid overusing
mixed
Even thoughmixed
is allowed, prefer specific unions.int|float|string
may be verbose, but it tells callers exactly what to expect.Order types consistently
There’s no enforced order, but many teams sort by specificity or frequency:public function logError(string|array $message): void
(Put the most common type first.)
Use with
strict_types=1
Enable strict typing to catch type mismatches early:declare(strict_types=1);
Update PHPDoc only when necessary
Native union types make many@param
and@return
annotations redundant. Remove them to avoid duplication and potential mismatches.
Watch Out for Pitfalls
No support for
void
in unions
You can’t dostring|void
—void
means "no return", so it doesn’t make sense in a union.No support for
mixed
in unionsmixed|bool
is invalid becausemixed
already includes all types.Be cautious with
object
While you can useobject|resource
, remember thatobject
is broad. Prefer specific class types when possible.IDE and tooling compatibility
Make sure your IDE, linter (like PHPStan or Psalm), and CI tools support PHP 8 . Older versions may not understand union types.
Example: Before and After
Before (PHP 7):
/** * @param int|string $value * @return array */ function parseValue($value) { if (is_string($value)) { return explode(',', $value); } return [$value]; }
After (PHP 8):
function parseValue(int|string $value): array { return is_string($value) ? explode(',', $value) : [$value]; }
Cleaner, safer, and self-documenting.
Modernizing with union types is one of the most impactful upgrades you can make when adopting PHP 8. It reduces ambiguity, improves tooling support, and catches bugs earlier. Start by identifying functions with PHPDoc-suggested unions, then apply native syntax — and don’t forget to run tests.
Basically, if your function already had @param string|int
in the docblock, it’s a perfect candidate. Just remove the comment and add the real type. That’s modern PHP.
The above is the detailed content of Modernizing Your Codebase with PHP 8's Union Types. For more information, please follow other related articles on the PHP Chinese website!

Hot AI Tools

Undress AI Tool
Undress images for free

Undresser.AI Undress
AI-powered app for creating realistic nude photos

AI Clothes Remover
Online AI tool for removing clothes from photos.

Clothoff.io
AI clothes remover

Video Face Swap
Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Article

Hot Tools

Notepad++7.3.1
Easy-to-use and free code editor

SublimeText3 Chinese version
Chinese version, very easy to use

Zend Studio 13.0.1
Powerful PHP integrated development environment

Dreamweaver CS6
Visual web development tools

SublimeText3 Mac version
God-level code editing software (SublimeText3)

Hot Topics

UpgradePHP7.xcodebasestoPHP8 byreplacingPHPDoc-suggestedtypeslike@paramstring|intwithnativeuniontypessuchasstring|intforparametersandreturntypes,whichimprovestypesafetyandclarity;2.Applyuniontypestomixedinputparameters(e.g.,int|stringforIDs),nullable

PHP supports the coexistence of loose types and strict types, which is the core feature of its evolution from scripting languages to modern programming languages. 1. Loose types are suitable for rapid prototyping, handling dynamic user input, or docking with external APIs, but there are problems such as risk of implicit type conversion, difficulty in debugging and weak tool support. 2. Strict type is enabled by declare(strict_types=1), which can detect errors in advance, improve code readability and IDE support, and is suitable for scenarios with high requirements for core business logic, team collaboration and data integrity. 3. Mixed use should be used in actual development: Strict types are enabled by default, loose types are used only when necessary at the input boundaries, and verification and type conversion are performed as soon as possible. 4. Recommended practices include using PHPSta

Enums introduced in PHP8.1 provides a type-safe constant collection, solving the magic value problem; 1. Use enum to define fixed constants, such as Status::Draft, to ensure that only predefined values are available; 2. Bind enums to strings or integers through BackedEnums, and support conversion from() and tryFrom() between scalars and enums; 3. Enums can define methods and behaviors, such as color() and isEditable(), to enhance business logic encapsulation; 4. Applicable to static scenarios such as state and configuration, not for dynamic data; 5. It can implement the UnitEnum or BackedEnum interface for type constraints, improve code robustness and IDE support, and is

AcallableinPHPisapseudo-typerepresentinganyvaluethatcanbeinvokedusingthe()operator,usedprimarilyforflexiblecodeincallbacksandhigher-orderfunctions;themainformsofcallablesare:1)namedfunctionslike'strlen',2)anonymousfunctions(closures),3)objectmethodsv

0.1 0.2!==0.3inPHPduetobinaryfloating-pointprecisionlimitations,sodevelopersmustavoiddirectcomparisonsanduseepsilon-basedchecks,employBCMathorGMPforexactarithmetic,storecurrencyinintegerswhenpossible,formatoutputcarefully,andneverrelyonfloatprecision

PHP uses zval structure to manage variables. The answer is: 1. zval contains values, types and metadata, with a size of 16 bytes; 2. When the type changes, only the union and type information need to be updated; 3. Complex types refer to structures with reference counts through pointers; 4. When assigning values, copy is used to optimize memory; 5. References make variables share the same zval; 6. Recycling references are processed by a special garbage collector. This explains the underlying mechanism of PHP variable behavior.

The life cycle of PHP resources is divided into three stages: 1. Resource creation, obtaining external system handles through functions such as fopen and curl_init; 2. Resource usage, passing resources to related functions for operation, PHP maps to the underlying system structure through resource ID; 3. Resource destruction, manually calling fclose, curl_close and other functions should be given priority to release resources to avoid relying on automatic garbage collection to prevent file descriptors from exhausting. Best practices include: always explicitly close resources, use try... finally ensure cleanup, prioritize objects such as PDO that supports __destruct, avoid global storage resources, and monitor active resources through get_resources()

==performsloosecomparisonwithtypejuggling,===checksbothvalueandtypestrictly;1."php"==0istruebecausenon-numericstringsconvertto0,2.emptystrings,null,false,and0arelooselyequal,3.scientificnotationlike"0e123"=="0e456"cancau
