Menu
Coddy logo textTech

Type Hinting & Union Types

Part of the Object Oriented Programming section of Coddy's PHP journey — lesson 35 of 91.

So far, you've used single types in your type hints - one class, one interface, or one primitive type. But what if a function should accept multiple different types? PHP 8.0 introduced union types, which let you specify that a parameter or return value can be one of several types.

Union types use the pipe character | to separate allowed types:

<?php
function formatValue(int|float|string $value): string {
    return "Value: " . $value;
}

echo formatValue(42) . "\n";
echo formatValue(3.14) . "\n";
echo formatValue("hello");

Output:

Value: 42
Value: 3.14
Value: hello

This becomes especially powerful when combined with polymorphism. You can accept multiple unrelated classes or interfaces in a single parameter:

<?php
interface Printable {
    public function print(): string;
}

class Document implements Printable {
    public function print(): string {
        return "Printing document";
    }
}

class Image {
    public function render(): string {
        return "Rendering image";
    }
}

function process(Printable|Image $item): string {
    if ($item instanceof Printable) {
        return $item->print();
    }
    return $item->render();
}

echo process(new Document()) . "\n";
echo process(new Image());

The instanceof operator helps you determine which type you're working with inside the function. This pattern lets you write flexible functions that handle multiple types while still maintaining type safety.

Key Point: Union types expand polymorphism beyond inheritance hierarchies, allowing functions to accept completely different types while keeping your code type-safe.

challenge icon

Challenge

Easy

Let's build a content renderer system that demonstrates the power of union types. You'll create a function that can handle multiple unrelated types — some implementing an interface, others being standalone classes — and process each one appropriately using instanceof checks.

You'll organize your code across four files:

  • Renderable.php — Define a Renderable interface with a single method signature: render(). Classes implementing this interface promise they can render themselves to a string.
  • TextBlock.php — Create a TextBlock class that implements Renderable. Include the interface file. The class should have a private $content property set through the constructor. Implement render() to return "Text: [content]".
  • RawHtml.php — Create a RawHtml class that does NOT implement Renderable. This is a standalone class with a private $html property set through the constructor. Add a getHtml() method that returns "HTML: [html]".
  • main.php — Include both the TextBlock and RawHtml files. Create a function called renderContent that uses a union type to accept either a Renderable or a RawHtml object. Inside the function, use instanceof to check the type: if it's Renderable, call and return render(); otherwise, call and return getHtml().

You'll receive two inputs: text content for the TextBlock and HTML content for the RawHtml. Create both objects with their respective content. Pass each one to your renderContent() function and print the results — the TextBlock first, then the RawHtml, each on its own line.

This challenge shows how union types let you write a single function that handles completely different types. The TextBlock follows the Renderable contract, while RawHtml is an entirely separate class — yet your function works seamlessly with both thanks to the union type Renderable|RawHtml.

Try it yourself

<?php
require_once 'TextBlock.php';
require_once 'RawHtml.php';

// Read input
$textContent = trim(fgets(STDIN));
$htmlContent = trim(fgets(STDIN));

// TODO: Create a function called renderContent that:
// - Uses a union type to accept either Renderable or RawHtml
// - Uses instanceof to check the type
// - If Renderable, call and return render()
// - Otherwise, call and return getHtml()

function renderContent(/* TODO: Add union type parameter */) {
    // TODO: Use instanceof to check type and return appropriate result
}

// TODO: Create TextBlock object with $textContent
// TODO: Create RawHtml object with $htmlContent

// TODO: Pass each object to renderContent() and print the results
// Print TextBlock result first, then RawHtml result (each on its own line)
?>
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