ZetCode

PHP mixed Type Tutorial

last modified May 18, 2025

In this tutorial, we will explore the mixed type in PHP, a flexible type declaration that allows a variable to hold values of multiple types.

The mixed type, introduced in PHP 8.0, explicitly indicates that a parameter, return value, or property can accept values of any type. This is particularly useful when working with dynamic data structures, such as API responses or user-generated input, where the data type may vary.

Using mixed helps improve code readability and documentation by signaling that a function or variable is designed to handle multiple types. However, developers should use it carefully, as excessive reliance on mixed can lead to unclear type expectations and potential runtime errors.

Basic mixed type usage

The mixed type can be used in parameter types, return types, and property types. It's equivalent to not having a type declaration at all but makes the code more explicit about its dynamic nature. All values are valid for mixed parameters.

basic_mixed.php
<?php

declare(strict_types=1);

function processValue(mixed $input): mixed {
    if (is_int($input)) {
        return $input * 2;
    }
    if (is_string($input)) {
        return strtoupper($input);
    }
    if (is_array($input)) {
        return count($input);
    }
    return $input;
}

echo processValue(10) . "\n";         // 20
echo processValue("hello") . "\n";    // HELLO
echo processValue([1, 2, 3]) . "\n";  // 3
echo processValue(null) . "\n";       // null

class DataProcessor {
    public mixed $data;
    
    public function __construct(mixed $data) {
        $this->data = $data;
    }
    
    public function getProcessedData(): mixed {
        if (is_callable($this->data)) {
            return ($this->data)();
        }
        return $this->data;
    }
}

$processor = new DataProcessor(fn() => "Callback result");
echo $processor->getProcessedData() . "\n"; // Callback result

This example shows mixed used in various contexts. The processValue function accepts and returns any type. The DataProcessor class uses mixed for both a property and method return type. Note that mixed includes all possible types including null, callables, and resources.

λ php basic_mixed.php
20
HELLO
3

Callback result

mixed vs no type declaration

While mixed and no type declaration both accept any value, mixed explicitly documents this intention. Modern PHP code should prefer mixed over omitting type declarations when any type is acceptable.

mixed_vs_no_type.php
<?php

declare(strict_types=1);

// Old style - no type hint (implicit mixed)
function oldStyle($value) {
    return $value;
}

// New style - explicit mixed
function newStyle(mixed $value): mixed {
    return $value;
}

// Union type equivalent (pre-PHP 8.0 alternative)
function unionEquivalent(
    string|int|float|bool|array|object|null $value
) {
    return $value;
}

// Strict comparison of behaviors
function testBehavior($input): void {
    echo "Input: " . gettype($input) . "\n";
    echo "oldStyle: " . gettype(oldStyle($input)) . "\n";
    echo "newStyle: " . gettype(newStyle($input)) . "\n";
    echo "unionEquivalent: " . gettype(unionEquivalent($input)) . "\n\n";
}

testBehavior(42);
testBehavior("text");
testBehavior(null);
testBehavior(new stdClass());

// Parameter type compatibility
class ParentClass {
    public function example($param) {
        // Implicit mixed
    }
}

class ChildClass extends ParentClass {
    public function example(mixed $param) {
        // Explicit mixed - compatible with parent
    }
}

This demonstrates that mixed is functionally equivalent to no type but more explicit. The union type equivalent shows how cumbersome it would be to list all possible types. Mixed is also compatible with untyped parameters in inheritance.

λ php mixed_vs_no_type.php
Input: integer
oldStyle: integer
newStyle: integer
unionEquivalent: integer

Input: string
oldStyle: string
newStyle: string
unionEquivalent: string

Input: NULL
oldStyle: NULL
newStyle: NULL
unionEquivalent: NULL

Input: object
oldStyle: object
newStyle: object
unionEquivalent: object

Type checking with mixed

When working with mixed values, you often need to check the actual type before performing operations. PHP provides several type-checking functions and operators for this purpose.

type_checking.php
<?php

declare(strict_types=1);

function handleMixed(mixed $value): string {
    // Type checking functions
    if (is_int($value)) {
        return "Integer: " . ($value * 2);
    }
    if (is_string($value)) {
        return "String length: " . strlen($value);
    }
    if (is_array($value)) {
        return "Array count: " . count($value);
    }
    if (is_object($value)) {
        return "Object class: " . get_class($value);
    }
    if (is_callable($value)) {
        return "Callable result: " . $value();
    }
    if (is_null($value)) {
        return "Null value";
    }
    return "Unknown type: " . gettype($value);
}

// Test cases
echo handleMixed(42) . "\n";
echo handleMixed("PHP") . "\n";
echo handleMixed([1, 2, 3]) . "\n";
echo handleMixed(new DateTime()) . "\n";
echo handleMixed(fn() => "Called") . "\n";
echo handleMixed(null) . "\n";
echo handleMixed(tmpfile()) . "\n";

// Using match expression (PHP 8.0+)
function handleMixedWithMatch(mixed $value): string {
    return match(true) {
        is_numeric($value) => "Number: $value",
        is_iterable($value) => "Iterable with " . count([...$value]) . " items",
        $value instanceof DateTimeInterface => "Date: " . $value->format('Y-m-d'),
        default => gettype($value)
    };
}

echo "\nWith match:\n";
echo handleMixedWithMatch(3.14) . "\n";
echo handleMixedWithMatch(new ArrayIterator([1, 2])) . "\n";
echo handleMixedWithMatch(new DateTime()) . "\n";

This shows comprehensive type checking for mixed values. The example uses is_* functions, instanceof, and match expression for type handling. Always check types before operations to avoid runtime errors with mixed values.

λ php type_checking.php
Integer: 84
String length: 3
Array count: 3
Object class: DateTime
Callable result: Called
Null value
Unknown type: resource

With match:
Number: 3.14
Iterable with 2 items
Date: 2025-05-18

mixed in class properties

Mixed type properties can hold any value but should be used judiciously. Consider adding documentation with @var to indicate expected types when using mixed properties.

mixed_properties.php
<?php

declare(strict_types=1);

class Configuration {
    /** @var mixed Can be string, array, or bool */
    public mixed $logging;
    
    /** @var mixed Callable or null */
    private mixed $formatter;
    
    public function __construct(mixed $logging, mixed $formatter = null) {
        $this->logging = $logging;
        $this->formatter = $formatter;
    }
    
    public function formatMessage(string $message): string {
        if ($this->formatter === null) {
            return $message;
        }
        if (!is_callable($this->formatter)) {
            throw new RuntimeException("Formatter must be callable");
        }
        return ($this->formatter)($message);
    }
    
    public function shouldLog(): bool {
        if (is_bool($this->logging)) {
            return $this->logging;
        }
        return $this->logging !== null;
    }
}

// Usage examples
$config1 = new Configuration(true);
echo $config1->shouldLog() ? "Logging enabled\n" : "Logging disabled\n";

$config2 = new Configuration(
    ['level' => 'debug'],
    fn($msg) => "[DEBUG] $msg"
);
echo $config2->formatMessage("Test message") . "\n";

// Type safety checks
try {
    $badConfig = new Configuration(null, "not callable");
    echo $badConfig->formatMessage("Will fail");
} catch (RuntimeException $e) {
    echo "Error: " . $e->getMessage() . "\n";
}

The example shows mixed properties with documentation. The class performs runtime type checking when using the properties. While mixed provides flexibility, always validate before use to maintain type safety.

λ php mixed_properties.php
Logging enabled
[DEBUG] Test message
Error: Formatter must be callable

mixed in return types

Functions with mixed return types can return any value. Document expected return types with @return when using mixed to help developers understand the possible return values.

mixed_returns.php
<?php

declare(strict_types=1);

/** 
 * @return mixed Returns parsed value or false on failure 
 */
function parseInput(string $input): mixed {
    if ($input === '') return null;
    if ($input === 'true') return true;
    if ($input === 'false') return false;
    if (is_numeric($input)) return $input + 0; // int or float
    if (str_starts_with($input, '[')) {
        return json_decode($input, true) ?? $input;
    }
    return $input;
}

// Test cases
$tests = ['42', '3.14', 'true', 'false', '[1,2,3]', 'invalid', ''];
foreach ($tests as $test) {
    $result = parseInput($test);
    echo "$test => " . gettype($result) . " (" . var_export($result, true) . ")\n";
}

// Real-world example: configuration loader
class ConfigLoader {
    /** 
     * @return mixed Returns parsed config array or throws exception
     */
    public function loadConfig(string $path): mixed {
        if (!file_exists($path)) {
            throw new RuntimeException("Config file not found");
        }
        
        $content = file_get_contents($path);
        $ext = pathinfo($path, PATHINFO_EXTENSION);
        
        return match($ext) {
            'json' => json_decode($content, true),
            'yml', 'yaml' => yaml_parse($content),
            'php' => include $path,
            default => throw new RuntimeException("Unsupported config format")
        };
    }
}

This demonstrates functions returning mixed types. The parseInput function returns various types based on input parsing. The ConfigLoader shows a real-world example where different file formats return different structures.

λ php mixed_returns.php
42 => integer (42)
3.14 => double (3.14)
true => boolean (true)
false => boolean (false)
[1,2,3] => array (
  0 => 1,
  1 => 2,
  2 => 3,
)
invalid => string ('invalid')
 => NULL (NULL)

Best practices with mixed

While mixed provides flexibility, it should be used thoughtfully. Follow these best practices to maintain code quality when working with mixed types.

best_practices.php
<?php

declare(strict_types=1);

// 1. Always document expected types with @var or @return
/** @var mixed $id */
$id = $_GET['id'] ?? null;

// 2. Validate mixed values before use
function processUserId(mixed $id): int {
    if (!is_numeric($id)) {
        throw new InvalidArgumentException("ID must be numeric");
    }
    return (int)$id;
}

// 3. Prefer more specific types when possible
// Bad: function store(mixed $data) { ... }
// Good: function store(array|object $data) { ... }

// 4. Use helper functions for type checking
function isCountable(mixed $value): bool {
    return is_array($value) || $value instanceof Countable;
}

// 5. Consider creating wrapper classes instead of using mixed
final class DynamicValue {
    public function __construct(private mixed $value) {}
    
    public function asInt(): int {
        if (!is_numeric($this->value)) {
            throw new RuntimeException("Not a number");
        }
        return (int)$this->value;
    }
    
    public function asString(): string {
        return (string)$this->value;
    }
    
    public function getRawValue(): mixed {
        return $this->value;
    }
}

// 6. Use mixed sparingly in public APIs
interface Logger {
    // Better than mixed: public function log(string|array $message);
    public function log(mixed $message): void;
}

// 7. Always handle null explicitly with mixed
function handleNullable(mixed $input): void {
    if ($input === null) {
        echo "Got null\n";
        return;
    }
    // Process non-null value
}

// 8. Consider using union types instead of mixed when possible
// (PHP 8.0+)
function betterThanMixed(string|int|float|bool|null $value) {
    // More type safety than mixed
}

These practices help maintain code quality when using mixed. Key points include proper documentation, validation, preferring specific types when possible, and creating wrapper classes for better type safety.

The mixed type in PHP serves an important role in the type system. Key points to remember about mixed:

While mixed provides flexibility, prefer more specific types whenever possible. Use mixed judiciously and always validate types at runtime when working with mixed values to maintain code reliability.

In this tutorial, we explored the mixed type in PHP, its usage, and best practices. We covered basic usage, type checking, and how to work with mixed in class properties and return types. We also discussed the importance of documentation and validation when using mixed.

Author

My name is Jan Bodnar, and I am a passionate programmer with extensive programming experience. I have been writing programming articles since 2007. To date, I have authored over 1,400 articles and 8 e-books. I possess more than ten years of experience in teaching programming.

List all PHP tutorials.