Skip to content

void 返回类型

概述

void 是 PHP 中一种特殊的返回类型声明,自 PHP 7.1.0 起可用。它仅用于返回值类型声明,表示函数不会返回有意义的值。使用 void 返回类型的函数仍然可以正常执行代码(如输出内容、修改状态、抛出异常),但不应返回任何值。

核心要点

  • void 只能用于返回类型声明,不能用于参数类型或属性类型。
  • void 函数可以包含 return;(无返回值)或省略 return 语句。
  • void 函数不能返回任何值,包括 null 以外的值。
  • void 不能作为联合类型的一部分(例如 void|int 是非法的)。
  • 自 PHP 8.1.0 起,void 函数通过引用返回已被弃用
  • :::

基础概念

什么是 void

在类型理论中,void 表示"无返回值"。它不是一个真正的"类型",而是一个表明函数不需要返回数据的标记。与之对比:

类型含义示例
void函数不返回任何值function log(string $msg): void
mixed函数可以返回任何值function get(): mixed
null函数返回一个确定的 nullfunction find(): ?string
never函数永远不会正常返回(PHP 8.1+)function abort(): never

void 的设计意图

void 的引入旨在为那些仅执行副作用的函数提供明确的类型声明,使代码意图更加清晰。典型的副作用包括:

  • 输出内容到标准输出
  • 写入数据库或文件
  • 修改全局状态或对象属性
  • 发送 HTTP 请求
  • 记录日志

语法与代码示例

基本用法

php
<?php
declare(strict_types=1);

function logMessage(string $message): void
{
    echo "[" . date('Y-m-d H:i:s') . "] {$message}" . PHP_EOL;
}

function incrementCounter(int &$counter): void
{
    $counter++;
}

$counter = 0;
logMessage("Application started");
incrementCounter($counter);
logMessage("Counter value: {$counter}");

return 语句在 void 函数中的行为

php
<?php
declare(strict_types=1);

function processUser(int $id): void
{
    if ($id <= 0) {
        return; // 合法:无返回值的 return,提前退出函数
    }

    // 执行处理逻辑
    echo "Processing user #{$id}" . PHP_EOL;
}

function saveToFile(string $content, string $path): void
{
    file_put_contents($path, $content);
    // 省略 return 语句也是合法的
}

void 函数的错误用法

php
<?php
declare(strict_types=1);

// 错误:void 函数不能返回值
function badReturn(): void
{
    return 42; // Fatal Error: A void function must not return a value
}

// 错误:void 函数不能返回 null
function badReturnNull(): void
{
    return null; // Fatal Error: A void function must not return a value
}

// 错误:void 不能用于参数类型
function badParameter(void $param): void // Fatal Error
{
}

void 在类方法中的使用

php
<?php
declare(strict_types=1);

class UserRepository
{
    private array $users = [];

    public function add(User $user): void
    {
        $this->users[$user->id] = $user;
    }

    public function remove(int $userId): void
    {
        unset($this->users[$userId]);
    }

    public function clear(): void
    {
        $this->users = [];
    }
}

void 与引用返回(PHP 8.1 弃用)

php
<?php
declare(strict_types=1);

// 自 PHP 8.1.0 起弃用:void 函数通过引用返回
class Config
{
    private string $value = 'default';

    // Deprecated: Returning by reference from a void function is deprecated
    public function &getValue(): void
    {
        return $this->value;
    }
}

弃用警告

自 PHP 8.1.0 起,void 函数通过引用返回会触发 E_DEPRECATED 警告。void 函数不应返回任何引用,因为这与 void(无返回值)的语义矛盾。

详细说明

void 与"空返回"的区别

这是一个容易混淆的概念。以下是三者的对比:

php
<?php
declare(strict_types=1);

// 1. void 返回类型 —— 不返回任何值
function doSomething(): void
{
    echo "done";
    // 没有 return,或者 return;(无返回值)
}

// 2. 没有返回类型声明 —— 可以返回任意值或不返回
function doSomethingElse()
{
    echo "done";
    // 可以返回值,也可以不返回
}

// 3. 返回 ?string —— 明确返回 null 或 string
function findUser(int $id): ?string
{
    // 返回 null 表示"未找到",这是有意义的返回值
    return null;
}

关键区别在于:void 函数不允许返回任何值(包括 null),而 ?string 函数明确地返回 null 作为一种有效结果

void 的继承与协变

在面向对象编程中,子类方法可以使用 void 替换父类方法的返回类型(协变):

php
<?php
declare(strict_types=1);

interface CacheInterface
{
    public function set(string $key, mixed $value): mixed;
}

class SimpleCache implements CacheInterface
{
    private array $store = [];

    public function set(string $key, mixed $value): void
    {
        $this->store[$key] = $value;
        // void 是 mixed 的子类型,因此这是合法的协变
    }
}

void 不能出现在联合类型中

由于 void 不是一个"真正的类型"(它不描述任何值),因此它不能与其他类型组合使用:

php
<?php
declare(strict_types=1);

// 以下写法全部非法
function bad1(): void|int {}     // Fatal Error
function bad2(): void|null {}    // Fatal Error
function bad3(): void|never {}   // Fatal Error

实战示例

日志系统

php
<?php
declare(strict_types=1);

interface LoggerInterface
{
    public function emergency(string $message, array $context = []): void;
    public function error(string $message, array $context = []): void;
    public function warning(string $message, array $context = []): void;
    public function info(string $message, array $context = []): void;
}

class FileLogger implements LoggerInterface
{
    private string $logPath;

    public function __construct(string $logPath)
    {
        $this->logPath = $logPath;
    }

    public function emergency(string $message, array $context = []): void
    {
        $this->writeLog('EMERGENCY', $message, $context);
    }

    public function error(string $message, array $context = []): void
    {
        $this->writeLog('ERROR', $message, $context);
    }

    public function warning(string $message, array $context = []): void
    {
        $this->writeLog('WARNING', $message, $context);
    }

    public function info(string $message, array $context = []): void
    {
        $this->writeLog('INFO', $message, $context);
    }

    private function writeLog(string $level, string $message, array $context): void
    {
        $entry = date('c') . " [{$level}] {$message}";

        if (!empty($context)) {
            $entry .= ' ' . json_encode($context, JSON_UNESCAPED_UNICODE);
        }

        file_put_contents($this->logPath, $entry . PHP_EOL, FILE_APPEND);
    }
}

事件分发器

php
<?php
declare(strict_types=1);

class EventDispatcher
{
    /** @var array<string, callable[]> */
    private array $listeners = [];

    public function on(string $event, callable $callback): void
    {
        $this->listeners[$event][] = $callback;
    }

    public function off(string $event, callable $callback): void
    {
        if (!isset($this->listeners[$event])) {
            return;
        }

        $this->listeners[$event] = array_filter(
            $this->listeners[$event],
            fn($cb) => $cb !== $callback
        );
    }

    public function dispatch(string $event, mixed $payload = null): void
    {
        if (!isset($this->listeners[$event])) {
            return;
        }

        foreach ($this->listeners[$event] as $callback) {
            $callback($payload);
        }
    }
}

注意事项

常见错误

错误写法正确写法说明
function f(): void { return 0; }function f(): void { return; }不能返回值
function f(): void { return null; }function f(): ?int { return null; }void 不等于 null
function f(void $x): voidfunction f(): voidvoid 不能用于参数
function f(): void|intfunction f(): int|nullvoid 不能在联合类型中
public function &f(): voidpublic function f(): void引用返回已弃用(PHP 8.1+)

void 与 null 的语义差异

php
<?php
declare(strict_types=1);

// void:函数不返回任何值 —— 关注点是"做什么"
function sendEmail(string $to, string $subject): void
{
    mail($to, $subject, 'Body');
}

// ?string:函数返回 null 或字符串 —— 关注点是"返回什么"
function findEmail(int $userId): ?string
{
    // null 表示"该用户没有邮箱"
    return $email ?? null;
}

选择原则:

  • 如果函数的目的是执行操作,使用 void
  • 如果函数的目的是查找并返回数据,使用具体类型(可能含 ?

最佳实践

  1. 对仅执行副作用的函数使用 void:如日志记录、事件发送、数据持久化等场景,明确表明该函数不返回值。

  2. 不要用 void 代替 ?Type:当函数需要返回 null 来表示"未找到"或"无结果"时,应使用可空类型(如 ?string)而非 void

  3. 避免在 void 函数中返回引用:自 PHP 8.1 起已弃用,应在升级前重构代码。

  4. void 方法适合 Builder 模式:在链式调用中,void 方法通过修改自身状态实现链式操作。

  5. 配合 declare(strict_types=1) 使用:虽然 void 类型不涉及类型转换,但严格模式是整体代码质量的保障。

  6. 在接口中善用 void:接口方法声明为 void 可以约束所有实现类都不返回值,提高代码一致性。

进阶用法

调试与测试技巧

php
<?php
declare(strict_types=1);

// 单元测试辅助函数
function createTestResource(): mixed
{
    return match (true) {
        default => new stdClass(),
    };
}

// 调试输出函数
function debugOutput(mixed , string  = ''): void
{
     =  ? ": " : '';
     .= print_r(, true);
    fwrite(STDERR,  . "\n");
}

// 性能基准测试
function benchmark(callable , int  = 1000): float
{
     = hrtime(true);
    for ($i = 0; $i < $iterations; $i++) {
        $fn();
    }
    return (hrtime(true) - $start) / 1e9;
}

日志记录实践

php
<?php
declare(strict_types=1);

/**
 * 简易日志记录器
 */
class SimpleLogger
{
    private string $logFile;
    private string $level = 'INFO';

    public function __construct(string $logFile)
    {
        $this->logFile = $logFile;
    }

    public function info(string $message, array $context = []): void
    {
        $this->log('INFO', $message, $context);
    }

    public function warning(string $message, array $context = []): void
    {
        $this->log('WARNING', $message, $context);
    }

    public function error(string $message, array $context = []): void
    {
        $this->log('ERROR', $message, $context);
    }

    private function log(string $level, string $message, array $context): void
    {
        $timestamp = date('Y-m-d H:i:s');
        $contextStr = $context ? ' ' . json_encode($context, JSON_UNESCAPED_UNICODE) : '';
        $line = "[{$timestamp}] [{$level}] {$message}{$contextStr}\n";
        file_put_contents($this->logFile, $line, FILE_APPEND | LOCK_EX);
    }
}

配置与环境检测

php
<?php
declare(strict_types=1);

// 环境检测工具
class EnvironmentChecker
{
    public static function checkRequirements(array $requirements): array
    {
        $results = [];
        foreach ($requirements as $name => $check) {
            $results[$name] = is_callable($check) ? $check() : false;
        }
        return $results;
    }

    public static function getSystemInfo(): array
    {
        return [
            'php_version' => PHP_VERSION,
            'os' => PHP_OS,
            'sapi' => PHP_SAPI,
            'memory_limit' => ini_get('memory_limit'),
            'max_execution_time' => ini_get('max_execution_time'),
            'loaded_extensions' => get_loaded_extensions(),
        ];
    }
}

常见问题排查

问题可能原因解决方案
连接超时网络问题/配置错误检查配置,增加超时时间
权限不足文件/目录权限使用 chmod/chown 修正
性能下降索引缺失/数据量大添加索引,优化查询
数据不一致并发冲突/事务残留使用锁机制和事务
内存溢出大数据集/未释放资源增大内存限制,分批处理

故障排除步骤

  1. 检查错误日志和异常信息
  2. 确认配置和环境是否正确
  3. 使用调试工具逐步排查
  4. 参考官方文档查找已知问题

版本兼容性说明

功能最低版本说明
基础功能PHP 8.1本文档基准版本
只读属性PHP 8.1public readonly 修饰符
枚举类型PHP 8.1enum 类型和 match 表达式
FiberPHP 8.1协程/轻量级并发
命名参数PHP 8.0foo(arg_name: value)
联合类型PHP 8.0`int
Null 安全运算符PHP 8.0$obj?->method()
析构器 promotionPHP 8.0__construct(public $x)
php
<?php
declare(strict_types=1);

// 版本兼容性检测
function ensureVersion(string $minVersion): void
{
    if (version_compare(PHP_VERSION, $minVersion, '<')) {
        throw new RuntimeException(
            sprintf('需要 PHP %s+, 当前版本: %s', $minVersion, PHP_VERSION)
        );
    }
}

ensureVersion('8.1.0');

参考链接