ZetCode

PHP mixed 类型教程

上次修改时间:2025 年 5 月 18 日

在本教程中,我们将探讨 PHP 中的 mixed 类型,这是一种灵活的类型声明,允许变量保存多种类型的值。

mixed 类型于 PHP 8.0 引入,明确表示参数、返回值或属性可以接受任何类型的值。这在处理动态数据结构(例如 API 响应或用户生成输入,其中数据类型可能有所不同)时特别有用。

使用 mixed 有助于提高代码可读性和文档记录,因为它表明一个函数或变量旨在处理多种类型。但是,开发人员应谨慎使用它,因为过度依赖 mixed 可能会导致类型期望不明确,并可能导致运行时错误。

基本 mixed 类型用法

mixed 类型可用于参数类型、返回类型和属性类型。它等同于根本没有类型声明,但使代码更明确其动态性。所有值对于 mixed 参数都是有效的。

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

此示例显示了在各种上下文中使用 mixed。 processValue 函数接受并返回任何类型。 DataProcessor 类将 mixed 用于属性和方法返回类型。请注意,mixed 包含所有可能的类型,包括 null、可调用对象和资源。

λ php basic_mixed.php
20
HELLO
3

Callback result

mixed 与无类型声明

虽然 mixed 和无类型声明都接受任何值,但 mixed 明确记录了此意图。当可以接受任何类型时,现代 PHP 代码应该优先使用 mixed 而不是省略类型声明。

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
    }
}

这表明 mixed 在功能上等同于无类型,但更明确。联合类型等效项显示了列出所有可能类型将是多么麻烦。 Mixed 也与继承中的未类型化参数兼容。

λ 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

使用 mixed 进行类型检查

处理 mixed 值时,您通常需要在执行操作之前检查实际类型。 PHP 提供了几个用于此目的的类型检查函数和运算符。

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";

这显示了对 mixed 值的全面类型检查。该示例使用 is_* 函数、instanceof 和 match 表达式进行类型处理。在操作之前始终检查类型,以避免 mixed 值的运行时错误。

λ 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

Mixed 类型属性可以保存任何值,但应谨慎使用。 考虑在使用 mixed 属性时,使用 @var 添加文档以指示预期类型。

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";
}

该示例显示了带文档的 mixed 属性。该类在使用属性时执行运行时类型检查。虽然 mixed 提供了灵活性,但在使用之前始终进行验证以保持类型安全。

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

在返回类型中使用 mixed

具有 mixed 返回类型的函数可以返回任何值。在使用 mixed 时,使用 @return 记录预期返回类型,以帮助开发人员了解可能的返回值。

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")
        };
    }
}

这演示了返回 mixed 类型的函数。 parseInput 函数根据输入解析返回各种类型。 ConfigLoader 显示了不同文件格式返回不同结构的真实示例。

λ 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)

使用 mixed 的最佳实践

虽然 mixed 提供了灵活性,但应谨慎使用。 遵循这些最佳实践,以在使用 mixed 类型时保持代码质量。

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
}

这些实践有助于在使用 mixed 时保持代码质量。 重点包括适当的文档记录、验证、尽可能优先使用特定类型,以及创建包装类以获得更好的类型安全。

PHP 中的 mixed 类型在类型系统中起着重要作用。 关于 mixed,需要记住的关键点

虽然 mixed 提供了灵活性,但尽可能优先使用更具体的类型。 使用 mixed 时要谨慎,并在使用 mixed 值时始终在运行时验证类型,以保持代码的可靠性。

在本教程中,我们探讨了 PHP 中的 mixed 类型、其用法和最佳实践。 我们介绍了基本用法、类型检查以及如何在类属性和返回类型中使用 mixed。 我们还讨论了在使用 mixed 时文档记录和验证的重要性。

作者

我叫 Jan Bodnar,是一位充满激情的程序员,拥有丰富的编程经验。 我自 2007 年以来一直在撰写编程文章。 迄今为止,我撰写了 1,400 多篇文章和 8 本电子书。 我拥有超过十年的编程教学经验。

列出 所有 PHP 教程