0
0
PHPprogramming~15 mins

Union types in PHP - Deep Dive

Choose your learning style9 modes available
Overview - Union types
What is it?
Union types in PHP allow a variable or function parameter to accept more than one type of value. Instead of restricting a value to a single type, union types let you specify multiple possible types separated by a vertical bar (|). This helps make code more flexible while still keeping type safety. For example, a function can accept either an integer or a string as input.
Why it matters
Without union types, developers had to rely on loose typing or manual checks, which could cause bugs or unclear code. Union types solve this by letting the code explicitly say: 'this value can be one of these types.' This improves code clarity, reduces errors, and helps tools catch mistakes early. It makes PHP code safer and easier to understand, especially in larger projects.
Where it fits
Before learning union types, you should understand basic PHP types and type declarations for functions and variables. After mastering union types, you can explore advanced typing features like intersection types, nullable types, and generics in PHP. Union types build on the foundation of PHP's type system and prepare you for writing more robust and flexible code.
Mental Model
Core Idea
Union types let a value be one of several specified types, combining flexibility with type safety.
Think of it like...
Imagine a Swiss Army knife that can be a knife, a screwdriver, or scissors depending on what you need. Union types are like that knife: one tool with multiple possible functions.
┌───────────────┐
│   Variable    │
│  accepts any  │
│  of these:   │
│  int | string │
└──────┬────────┘
       │
       ▼
┌───────────────┐
│  int value    │
│  or string    │
│  value       │
└───────────────┘
Build-Up - 7 Steps
1
FoundationBasic type declarations in PHP
🤔
Concept: Learn how PHP enforces types on function parameters and return values.
In PHP, you can declare the type of a function parameter or return value to ensure it matches. For example: function add(int $a, int $b): int { return $a + $b; } This function only accepts integers and returns an integer.
Result
If you call add(2, 3), it returns 5. If you call add('2', 3), PHP tries to convert '2' to int automatically.
Understanding basic type declarations is essential because union types extend this idea by allowing multiple types instead of just one.
2
FoundationWhat are union types in PHP?
🤔
Concept: Union types allow specifying multiple types for a parameter or return value using the | symbol.
Starting with PHP 8.0, you can write: function example(int|string $value): int|string { if (is_int($value)) { return $value * 2; } return strtoupper($value); } This means $value can be an int or a string, and the function returns the same.
Result
Calling example(5) returns 10; example('hi') returns 'HI'.
Union types let you write clearer, safer code that handles multiple types explicitly without losing type checking.
3
IntermediateNullable types vs union types
🤔Before reading on: Do you think nullable types are a special case of union types or something different? Commit to your answer.
Concept: Nullable types are a shorthand for a union type with null included.
In PHP, ?int means int|null. For example: function test(?int $value) { // $value can be int or null } This is equivalent to: function test(int|null $value) { // same meaning } Nullable types are just a simpler way to write a union with null.
Result
You can pass an integer or null to test().
Knowing nullable types are a subset of union types helps you understand PHP's type system consistency and syntax shortcuts.
4
IntermediateUsing union types with class and scalar types
🤔Before reading on: Can union types mix classes and scalar types like int or string? Commit to your answer.
Concept: Union types can combine scalar types and class/interface types in one declaration.
Example: class User {} function process(User|string $input) { if ($input instanceof User) { // handle User object } else { // handle string } } This function accepts either a User object or a string.
Result
You can call process(new User()) or process('guest').
Union types increase flexibility by allowing different kinds of values, including objects and simple types, in one place.
5
IntermediateType checking and union types at runtime
🤔Before reading on: Does PHP automatically convert types inside union types or throw errors? Commit to your answer.
Concept: PHP enforces union types strictly and does not convert types automatically inside unions.
If a function expects int|string, passing a float will cause a TypeError. For example: function test(int|string $value) {} test(3.14); // TypeError You must pass exactly one of the allowed types.
Result
Passing wrong types causes errors, helping catch bugs early.
Understanding strict enforcement prevents confusion and runtime bugs when using union types.
6
AdvancedUnion types with mixed and never types
🤔Before reading on: Can union types include 'mixed' or 'never' types? Commit to your answer.
Concept: The 'mixed' type means any type, so combining it with union types is redundant; 'never' means no value and cannot be combined in unions.
In PHP: - 'mixed' means any type, so writing int|mixed is just mixed. - 'never' means a function never returns; it can't be part of a union. Therefore, union types should avoid mixing these special types to keep meaning clear.
Result
Using mixed or never in unions is either redundant or invalid.
Knowing these special types' roles helps avoid confusing or meaningless union type declarations.
7
ExpertUnion types and backward compatibility challenges
🤔Before reading on: Do you think adding union types can break older PHP code silently or always causes errors? Commit to your answer.
Concept: Introducing union types can cause compatibility issues with older code expecting looser typing or different behaviors.
PHP 8.0 added union types, but older code might rely on implicit type juggling. For example, a function previously accepting any type now restricts inputs, causing TypeErrors. Also, reflection and type hints behave differently, requiring careful migration. Developers must test and update codebases to handle strict union types safely.
Result
Union types improve safety but require careful adoption to avoid breaking existing code.
Understanding backward compatibility challenges helps plan safe upgrades and avoid subtle bugs in large projects.
Under the Hood
At runtime, PHP checks the actual type of a value against the declared union types using internal type checking logic. When a function is called, PHP verifies if the argument matches any of the allowed types in the union. If not, it throws a TypeError. This check happens before the function body executes, ensuring type safety. The union type information is stored in the function's metadata and used by the engine during calls and reflection.
Why designed this way?
Union types were introduced to balance PHP's dynamic nature with modern type safety needs. Before union types, PHP was either loosely typed or forced to use workarounds like doc comments or manual checks. The design uses a simple syntax (|) to keep declarations readable and leverages existing type checking mechanisms. Alternatives like complex type systems or generics were avoided initially to keep PHP accessible and backward compatible.
┌───────────────┐
│ Function call │
└──────┬────────┘
       │
       ▼
┌─────────────────────────┐
│ Check argument type      │
│ against union types      │
│ (e.g., int|string)       │
└──────┬────────┬──────────┘
       │        │
   Matches?    No
       │        │
       ▼        ▼
┌───────────┐  ┌─────────────┐
│ Execute   │  │ Throw       │
│ function  │  │ TypeError   │
└───────────┘  └─────────────┘
Myth Busters - 4 Common Misconceptions
Quick: Does union type int|string accept float values? Commit to yes or no.
Common Belief:Union types accept any value that can be converted to one of the types, like float to int.
Tap to reveal reality
Reality:Union types require the value to be exactly one of the declared types; implicit conversions do not happen.
Why it matters:Assuming implicit conversion leads to unexpected TypeErrors and bugs when passing floats where int|string is expected.
Quick: Can you use union types with void return type? Commit to yes or no.
Common Belief:You can combine void with other return types in a union.
Tap to reveal reality
Reality:Void means no return value and cannot be combined in union types; it's exclusive.
Why it matters:Misusing void in unions causes syntax errors and confusion about function behavior.
Quick: Do union types allow mixing nullable and non-nullable types without explicit null? Commit to yes or no.
Common Belief:If you write int|string, null is allowed automatically.
Tap to reveal reality
Reality:Null is not included unless explicitly stated, e.g., int|string|null or ?int.
Why it matters:Assuming null is allowed causes unexpected null-related bugs and runtime errors.
Quick: Can union types be used in property declarations in PHP 8.0? Commit to yes or no.
Common Belief:Union types can be used anywhere types are declared, including properties.
Tap to reveal reality
Reality:PHP 8.0 supports union types for parameters and returns but not for typed properties until PHP 8.1.
Why it matters:Trying to use union types in properties in PHP 8.0 causes syntax errors and confusion.
Expert Zone
1
Union types do not support recursive or nested unions; each union is flat and explicit.
2
When multiple union types are combined in inheritance, PHP requires compatible declarations, which can be tricky to manage.
3
Reflection API treats union types as a collection of single types, requiring careful handling when inspecting code dynamically.
When NOT to use
Avoid union types when you need more complex type relationships like intersections or generics, which PHP does not support natively. Also, if your codebase targets PHP versions before 8.0, union types are not available. In those cases, use doc comments or manual type checks instead.
Production Patterns
In real-world PHP applications, union types are used to handle flexible input data, such as accepting IDs as int|string or processing different object types in one function. They improve API clarity and reduce boilerplate type checks. Frameworks and libraries adopt union types to enforce contracts while supporting multiple data formats.
Connections
TypeScript union types
Same pattern in a different language
Understanding PHP union types helps grasp TypeScript's similar feature, showing how multiple languages solve flexible typing with unions.
Set theory in mathematics
Union types correspond to the union of sets of possible values
Seeing union types as set unions clarifies why a value must belong to any one of the specified types, linking programming to fundamental math concepts.
Natural language ambiguity
Union types reflect how words can have multiple meanings depending on context
Recognizing that union types model multiple possible meanings helps understand ambiguity management in language and programming.
Common Pitfalls
#1Passing a float to a union type expecting int|string
Wrong approach:function test(int|string $value) {} test(3.14);
Correct approach:function test(int|string $value) {} test(3); // or test('3.14');
Root cause:Misunderstanding that union types do not allow implicit type conversions.
#2Assuming null is allowed without explicit declaration
Wrong approach:function example(int|string $value) {} example(null);
Correct approach:function example(int|string|null $value) {} example(null);
Root cause:Confusing nullable types with union types that exclude null by default.
#3Using union types in property declarations in PHP 8.0
Wrong approach:class A { public int|string $prop; }
Correct approach:class A { public int|string $prop; // valid only in PHP 8.1+ }
Root cause:Not knowing union types for properties were introduced after PHP 8.0.
Key Takeaways
Union types let you specify multiple allowed types for variables, parameters, and return values, increasing flexibility while keeping type safety.
They use the vertical bar (|) to separate types and require exact matches without implicit conversions.
Nullable types are a special case of union types that include null explicitly.
Union types improve code clarity and error detection but require careful use to avoid compatibility and runtime issues.
Understanding union types connects programming with broader concepts like set theory and language ambiguity, enriching your mental model.