Union & Intersection Types
Part of the Object Oriented Programming section of Coddy's PHP journey — lesson 65 of 91.
While nullable types let you accept a type or null, union types (PHP 8.0+) allow a parameter or return value to accept multiple different types. Use the pipe | to separate the allowed types:
<?php
class Formatter {
public function format(int|float $number): string {
return number_format($number, 2);
}
}
$formatter = new Formatter();
echo $formatter->format(42) . "\n";
echo $formatter->format(3.14159);
Output:
42.00
3.14Union types are particularly useful when a method can work with different but related types. You can combine as many types as needed, including class names and interfaces:
<?php
class Logger {
public function log(string|array|Stringable $message): void {
if (is_array($message)) {
$message = implode(", ", $message);
}
echo "Log: $message";
}
}
Intersection types (PHP 8.1+) are the opposite - they require a value to implement all specified types simultaneously. Use the ampersand & to combine them:
<?php
interface Printable {
public function print(): string;
}
interface Saveable {
public function save(): void;
}
class DocumentHandler {
public function process(Printable&Saveable $doc): void {
echo $doc->print();
$doc->save();
}
}
Here, process() only accepts objects that implement both Printable and Saveable. This ensures the object has all required capabilities before the method runs, making your code safer and more expressive.
Challenge
EasyLet's build a data processor that demonstrates both union types and intersection types. You'll create a system that can handle multiple input formats and requires objects to implement multiple interfaces for certain operations.
You'll organize your code across three files:
Interfaces.php— Define two interfaces that represent different capabilities:Exportablewith a methodexport(): stringLoggablewith a methodlog(): string
DataProcessor.php— Create aDataProcessorclass that showcases both union and intersection types. Include the Interfaces file. Your class should have:- A method
normalize(int|float|string $value): stringthat converts any of these types to a string. For numbers, format them with 2 decimal places. For strings, return them as-is. - A method
processMultiple(array $values): stringthat accepts an array of mixed values (integers, floats, or strings), normalizes each one using the method above, and returns them joined with" | " - A method
handleDocument(Exportable&Loggable $doc): stringthat uses an intersection type to require an object implementing both interfaces. It should return the result of callinglog()followed by" -> "followed by the result ofexport()
- A method
main.php— Include the DataProcessor file. You'll receive two inputs: a type indicator ("int","float", or"string") and a value.Create a
DataProcessorand convert the input value to the appropriate type based on the indicator. Then callnormalize()with that value and print the result.Next, create an anonymous class that implements both
ExportableandLoggable. Theexport()method should return"Exported data"and thelog()method should return"Logged". Pass this object tohandleDocument()and print the result on a new line.
This challenge combines union types for flexible input handling with intersection types for ensuring objects have multiple required capabilities — both powerful features for building robust, type-safe PHP applications.
Try it yourself
<?php
require_once 'DataProcessor.php';
// Read input
$type = trim(fgets(STDIN));
$value = trim(fgets(STDIN));
// TODO: Create a DataProcessor instance
// TODO: Convert $value to the appropriate type based on $type indicator
// ("int", "float", or "string")
// TODO: Call normalize() with the converted value and print the result
// TODO: Create an anonymous class that implements both Exportable and Loggable
// - export() should return "Exported data"
// - log() should return "Logged"
// TODO: Pass the anonymous class instance to handleDocument() and print the result
?>This lesson includes a short quiz. Start the lesson to answer it and track your progress.
All lessons in Object Oriented Programming
1Fundamentals of OOP
External FilesIntroduction to OOPClasses vs ObjectsThe $this KeywordMethodsPropertiesConstructor (__construct)Destructor (__destruct)Recap - Simple Calculator4Inheritance
Basic InheritanceThe parent:: KeywordMethod OverridingThe final KeywordAbstract ClassesRecap - Employee Hierarchy7Encapsulation
Public, Protected, PrivateAccess Modifiers in DepthGetters and SettersInformation HidingConstructor Promotion (8.0)Recap - Student Records System2Namespaces & Autoloading
Introduction to NamespacesThe use KeywordPSR-4 Autoloading StandardComposer AutoloaderRecap - Organized Project5Interfaces & Contracts
Introduction to InterfacesImplementing InterfacesMultiple Interface ImplementInterface vs Abstract ClassType Hinting with InterfacesRecap - Shape Calculator8Magic Methods
Magic Methods Introduction__toString & __debugInfo__get, __set, __isset, __unset__call & __callStatic__clone & Object Cloning__serialize & __unserializeRecap - Custom Collection11Type System & Error Handling
Type DeclarationsNullable TypesUnion & Intersection TypesException ClassesCustom Exception HierarchyTry, Catch, FinallyRecap - Form Validator14Project: Library Management
Project OverviewBook and User Classes3Class Properties
Instance vs Static PropertiesConstants in ClassesStatic Methods & PropertiesPrivate & Protected PropertiesReadonly Properties (PHP 8.1)Recap - Bank Account Manager6Polymorphism
Method Overriding RevisitedPolymorphism via InterfacesType Hinting & Union TypesLate Static BindingRecap - Payment Processor9Traits
Introduction to TraitsUsing Multiple TraitsTrait Conflict ResolutionAbstract Methods in TraitsTraits vs Inheritance12Design Patterns Part 1
Intro to Design PatternsSingleton PatternFactory PatternObserver PatternStrategy Pattern