Menu
Coddy logo textTech

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.14

Union 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 icon

Challenge

Easy

Let'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:
    • Exportable with a method export(): string
    • Loggable with a method log(): string
  • DataProcessor.php — Create a DataProcessor class that showcases both union and intersection types. Include the Interfaces file. Your class should have:
    • A method normalize(int|float|string $value): string that 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): string that 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): string that uses an intersection type to require an object implementing both interfaces. It should return the result of calling log() followed by " -> " followed by the result of export()
  • main.php — Include the DataProcessor file. You'll receive two inputs: a type indicator ("int", "float", or "string") and a value.

    Create a DataProcessor and convert the input value to the appropriate type based on the indicator. Then call normalize() with that value and print the result.

    Next, create an anonymous class that implements both Exportable and Loggable. The export() method should return "Exported data" and the log() method should return "Logged". Pass this object to handleDocument() 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


?>
quiz iconTest yourself

This lesson includes a short quiz. Start the lesson to answer it and track your progress.

All lessons in Object Oriented Programming