PHP 8.1 核心特性

简介:

自 PHP 8.0 发布以来,该语言经历了一系列重要的功能迭代与性能改进。对于开发者而言,系统理解这些新特性不仅是技术更新的需要,更是优化代码设计、降低维护成本的有效途径。本分类将按版本梳理 PHP 8.x 的新特性。

8.1官方手册参考指南(含其他特性):官方链接

一、枚举

PHP8.1 正式引入枚举(Enumeration,简称 Enum)特性,解决了传统开发中用「类常量」「数组」管理固定值集合时的类型不安全「取值范围无法约束」「语义不清晰」等问题。

核心概念:枚举是一种特殊的自定义数据类型,用于定义一组命名且不可变的常量集合,强制变量只能取集合内的某个值。PHP 枚举分为两种核心类型(纯枚举、带值枚举),且所有枚举本质上是「final 类」,无法继承、无法实例化(单例设计)。

纯枚举示例:

php 复制代码
<?php
declare(strict_types=1);

/**
 * 纯枚举类 
 * 无关联值,仅表示「命名常量」
 * 标识状态(如开关)
 */
enum EnumExample{
    case Active; // 激活
    case Inactive; // 未激活
    case Banned; // 封禁
}
$status = EnumExample::Active;
var_dump($status->name); // string(6) "Active"

带值枚举示例:

php 复制代码
<?php
declare(strict_types=1);

/**
 * 带值枚举 
 * 关联标量值(仅 int/string),且值类型统一
 * 需要状态 + 对应值(如编码)
 */
enum HttpEnumExample : int {
    // 通常用于 GET 和 POST请求成功, 服务器已成功处理同时响应体中包含所请求的数据
    case OK = 200;
    // 临时重定向​​, 常用于临时活动页或登录后跳转
    case FOUND = 302;
    // 请求参数错误
    case BAD_REQUEST = 400;
    // ​​未认证​​。请求要求用户的身份验证
    case UNAUTHORIZED = 401;
    // 服务器内部错误
    case INTERNAL_SERVER_ERROR = 500;
}

$http = HttpEnumExample::OK;
var_dump($http->name); // string(2) "OK"
var_dump($http->value); // int(200) 注:纯枚举无此属性

枚举的核心特性:

  1. 内置默认方法

    方法 适用类型 作用
    cases(): array 所有枚举 返回枚举所有案例的数组(按定义顺序)
    from(mixed $value) 带值枚举 根据值查找枚举案例,值不存在则抛出 ValueError 异常
    tryFrom(mixed $value) 带值枚举 根据值查找枚举案例,值不存在则返回 null(推荐替代 from

    示例:

    php 复制代码
    echo '<pre>';
    $httpArray = HttpEnumExample::cases();
    foreach($httpArray as $http){
        var_dump($http->name.'->'.$http->value); // string(7) "OK->200" ...
    }
    
    // from():值存在返回案例,不存在抛异常
    $isOk = HttpEnumExample::from(200);
    
    // $isFound = TestHttpEnum::from(303); //抛出异常
    var_dump($isOk); // 枚举案例 enum(HttpEnumExample::OK)
    
    // tryFrom():值不存在返回null(更安全) 
    $isOk = HttpEnumExample::tryFrom(200);
    $isFound = HttpEnumExample::tryFrom(303); 
    var_dump($isOk); // 枚举案例 enum(HttpEnumExample::OK)
    var_dump($isFound); // NULL
  2. 自定义方法与构造函数,枚举支持定义普通方法「静态方法」。甚至私有构造函数(禁止外部实例化),但构造函数必须是 private(枚举默认单例)注:PHP8.4版本已经禁用

    示例:

    php 复制代码
    <?php
    declare(strict_types=1);
    
    enum HttpEnumExample : int {
        case OK = 200;
        case FOUND = 302;
        case BAD_REQUEST = 400;
        case UNAUTHORIZED = 401;
        case INTERNAL_SERVER_ERROR = 500;
    
        /**
         * 自定义方法:获取状态的中文描述
         * @return string
         */
        public function getLabel() : string{
            return match($this){
                self::OK => "请求成功",
                self::FOUND => "临时重定向​",
                self::BAD_REQUEST => "请求参数错误",
                self::UNAUTHORIZED => "​未认证",
                self::INTERNAL_SERVER_ERROR => "服务器内部错误"
            };
    
        }
    
        /**
         * 静态方法:批量获取「值-标签」映射
         * @return array
         */
        public static function getLabelMap(): array{
            $map = [];
            foreach(self::cases() as $case){
                    $map[$case->value] = $case->getLabel();
            }
            return $map;
        }
    }
    
    $status = HttpEnumExample::OK;
    echo '<pre>';
    var_dump($status->getLabel()); // 请求成功
    var_dump($status::getLabelMap()); // 数组 [200 => "请求成功",...]
  3. 类型提示与类型安全。枚举可作为参数「返回值」「属性」的类型提示,强制传入 / 返回的值必须是枚举案例,杜绝非法值。

  4. 枚举的比较,枚举案例是单例对象,推荐使用「严格比较(===)」,松散比较(==)也可但不推荐

  5. 反射(ReflectionEnum),PHP 提供 ReflectionEnum 类(继承自 ReflectionClass),用于动态获取枚举信息

  6. 序列化与反序列化,枚举支持 serialize()/unserialize(),且反序列化后仍指向原单例对象,保证一致性

补充:注意事项与最佳实践

核心限制:

枚举是 final 类,无法继承;

枚举不能实例化(new OrderStatus() 抛 Error);

带值枚举的值必须唯一(重复值抛 Fatal Error);

枚举不能定义属性(仅能通过 name/value 访问固定值)

最佳实践:

优先使用 tryFrom() 而非 from():避免未捕获的 ValueError,提升代码健壮性;

枚举方法保持单一职责:仅处理与枚举本身相关的逻辑(如标签转换),不写复杂业务逻辑;

结合接口统一契约:多个枚举需实现相同逻辑时,通过接口约束;

用 match 替代 switch:穷尽检查确保覆盖所有案例,避免遗漏;

带值枚举优先用 int 类型:便于扩展(如后续加状态时,int 比 string 更灵活)

二、只读属性

PHP8.1 引入的只读属性是对对象属性不可变性的语法级 增强。只读属性是通过 readonly 关键字修饰的实例属性,仅能在对象初始化阶段(构造函数内)赋值一次,赋值后任何修改操作都会触发 Error 异常,从语法层面强制保障属性的不可变性。

语法规则:

1. readonly 关键字必须位于访问修饰符(public/protected/private)之后、类型声明之前;

2. PHP8.1 中,只读属性必须显式声明类型(不能省略类型,也不能用 mixed,PHP8.2 开始支持 mixed);

3. 只读属性仅支持实例属性,不能修饰静态属性(static);

4. 支持所有合法的类型声明(标量、对象、联合类型、Nullable 类型等)

注意规避「浅只读」坑点。若属性类型为「标量(int/string/bool/float)」:完全不可修改;若属性类型为「数组 / 对象」:属性本身的引用不可改,但数组元素 / 对象属性可自由修改。

示例:

php 复制代码
<?php

declare(strict_types=1);

class Example
{
    public readonly ?string $msg;

    public function __construct(
        ?string $msg = '信息',
        public readonly string $otherMsg = '另一个信息'
    ) {
        $this->msg = $msg === '信息' ? '第一次改变信息' : $msg;
        // 使用属性构造器提升,其属性赋值在进入构造函数函数体之前就已经赋值完成了。
        // $this->otherMsg = '第一次改变另一个信息'; // 这行代码会抛出错误,因为 otherMsg 已经被赋值了,并且是只读的。

    }

    public function getChangeMsg(): string
    {
        $this->msg = '尝试第二次改变信息';
        return $this->msg;
    }
}

$exampleClass = new Example();
echo '<pre>';
try {
    var_dump($exampleClass->msg); // 输出: string(9) "信息"
    var_dump($exampleClass->otherMsg); // 输出: string(12) "另一个信息"
    var_dump($exampleClass->getChangeMsg()); // 抛出异常
} catch (Error $e) {
    echo  $e->getMessage(); // Cannot modify readonly property Example::$msg
}

最佳实践:

按需使用:仅对「赋值后无需修改」的属性使用 readonly,避免滥用(如业务属性需要动态修改的,不要用);

结合构造函数参数提升:简化代码,提升可读性(推荐写法);

初始化校验:在构造函数内对只读属性做合法性校验(如金额非负、邮箱格式正确);

三、一阶可调用语法(First-class)

一阶可调用语法是 PHP 8.1 推出的语法糖级核心特性,官方定义:Callable 表达式语法,用于极简、安全、优雅地创建可调用对象(Callable),彻底解决了传统 PHP 中回调写法丑陋、无类型检查、IDE 不识别、易写错的痛点。

语法:用 函数/方法名(...) 的语法,直接将任意可调用元素转换为标准闭包(Closure),... 是固定语法标记(非可变参数、非参数展开)

示例:

php 复制代码
<?php

declare(strict_types=1);

class Example
{
    public function getMsg(string $msg = '')
    {
        return $msg ? $msg : '执行了';
    }

    public static function getStaticMsg(string $msg = '')
    {
        return $msg ? $msg : '执行了';
    }
}

/** 传统写法 */
echo '<pre>';
// 字符串函数名
$func = 'strlen';
var_dump($func('把"strlen"这个函数当做一个变量来传递,$func("hello") 相当于调用 strlen("hello")')); // 99
// 数组静态方法 
$staticMethod = [Example::class, 'getStaticMsg'];
var_dump($staticMethod()); // 执行了
// 数组对象方法
$test = new Example();
$objectMethod = [$test, 'getMsg'];
var_dump($objectMethod()); // 执行了

/** 一级可调用语法  */
$func1 = strlen(...);
var_dump($func1('普通函数:类型安全、IDE 识别')); // 40

$staticMethod1 = Example::getStaticMsg(...);
var_dump($staticMethod1('静态方法:语法简洁、无数组冗余')); // 静态方法:语法简洁、无数组冗余

$objectMethod1 = $test->getMsg(...);
var_dump($objectMethod1('对象方法:语义直观、自动绑定作用域')); // 对象方法:语义直观、自动绑定作用域

// 闭包 / 匿名函数
$add = fn($a, $b) => $a + $b;
$callable = $add(...);
var_dump($callable(1, 2)); // 3

$arr = ['apple', 'banana', 'cherry'];
var_dump(array_map('strlen', $arr)); // 旧写法 数据[0=>5, 1=>6, 2=>6]
var_dump(array_map(strlen(...), $arr)); // 新写法 数据[0=>5, 1=>6, 2=>6]

注意:不支持通过此语法(例如 new Foo(...))创建对象,因为不会视 new Foo() 语法为调用;一级可调用语法不能与 nullsafe 运算符结合使用

四、新的初始化器

PHP 8.1 核心的语法升级之一,允许在「编译期可解析的上下文」中,直接使用 new 类名(参数) 作为默认值 / 初始值,但需要满足"常量表达式"的要求,禁止运行时变量、函数、动态值。

这一特性主要涵盖四个场景:

  1. 函数/方法参数默认值(支持箭头函数)

    示例:

    php 复制代码
    <?php
    declare(strict_types=1);
    
    class Example
    {
        public function __construct(
            public DateTime $createTime = new DateTime()
        ){}
    }
    
    $ExampleClass = new Example();
    var_dump($ExampleClass->createTime->format('Y-m-d H:i:s')); // 输出当前时间
  2. 静态变量初始化器

    php 复制代码
    <?php
    
    declare(strict_types=1);
    
    function getDateTimeStr()
    {
        static $date = new DateTime(); // 低版本会触发error
        return $date->format('Y-m-d H:i:s');
    }
    
    var_dump(getDateTimeStr()); // 当前时间
  3. 属性参数(支持嵌套属性)

    php 复制代码
    <?php
    
    declare(strict_types=1);
    
    // 普通类
    class Role {
        public function __construct(public string $name) {}
    }
    
    // 注解(Attribute) 类
    #[Attribute]
    class Auth { 
        public function __construct(public Role $role = new Role("默认管理员")) {}
    }
    
    // 用法1:不传参 → 自动使用 new 初始化的默认对象
    #[Auth]
    class Admin {}
    
    // 用法2:手动传 new 对象 → 注解参数直接传实例
    #[Auth(new Role("普通用户"))]
    class User {}
    
    echo "<pre>";
    // 获取Admin的注解
    $adminAttr = new ReflectionClass(Admin::class)->getAttributes(Auth::class)[0]->newInstance();
    echo "Admin 权限:" . $adminAttr->role->name; // Admin 权限:默认管理员
    
    // 获取User的注解
    $userAttr = new ReflectionClass(User::class)->getAttributes(Auth::class)[0]->newInstance();
    echo "User 权限:" . $userAttr->role->name; // User 权限:普通用户
  4. 全局常量(类常量存在限制)

    php 复制代码
    <?php
    
    declare(strict_types=1);
    
    class Example {
        // ❌ 非法:类常量不支持 new
        // public const OBJ = new stdClass();  // Fatal error
    
        // ❌ 非法:类属性(静态)不支持 new
        // public  $obj = new stdClass();  // Fatal error
    
        public function __construct(public string $name = 'admin') {}
    }
    
    // ✅ 合法:全局常量支持 new
    const DEFAULT_ROLE = new Example();
    print_r(DEFAULT_ROLE->name);

    补充(明确禁止的语法):

    php 复制代码
    <?php
    
    declare(strict_types=1);
    
    class Example {
        // ❌ 类属性、类常量的明确排除 均不合法
        public static $classOne = new stdClass();
        public $classTwo = new stdClass();
        public const CLASS_THREE = new stdClass(); 
    }
    
    // ❌ 禁止:动态类名
    function funOne($a = new (CLASS_NAME_CONSTANT)()){}
    // ❌ 禁止:匿名类
    function funTwo($a = new class {}){}
    // ❌ 禁止:参数解包
    function funThree($a = new A(...[])){}
    // ❌ 禁止:非常量表达式作为参数
    function funFour($a = new B($someVariable)){}

五、纯交集类型

PHP 8.1 引入了 纯交集类型(Pure Intersection Types),允许开发者使用 & 符号将多个类/接口类型 组合起来,表示一个值必须同时是所有这些类型的实例。"纯"的含义:目前 PHP 的交集类型只能包含类类型(类名、接口名),不能包含标量类型(如 intstring)。这与联合类型(可包含标量)形成对比。

可用于:参数类型、返回类型、属性类型、instanceof 操作符右侧

示例:

php 复制代码
<?php

declare(strict_types=1);

function process(Iterator & Countable $value): int {
    // $value 必须同时实现 Iterator 和 Countable
    foreach ($value as $item) { /* ... */ }
    return count($value);
}

$data = ['apple', 'banana', 'cherry'];
// ArrayIterator 既实现 Iterator,也实现 Countable
$iterator = new ArrayIterator($data);
var_dump(process($iterator)); // 输出: int(3)

补充:交集类型可以与联合类型嵌套,但不能直接在同一个类型声明中混用 &|(除非使用括号)。其中,& 的优先级高于 |,但直接书写 A&B|C 会被解释为 (A&B)|C,然而由于语法限制,这样的写法会被拒绝,必须显式使用括号。

php 复制代码
<?php

declare(strict_types=1);

// ✅ 合法:表示 $value 要么是 (A 且 B),要么是 C
function fun1((A & B) | C $value): void {}
// ❌ 错误!会解析为 (A&B)|C 吗?实际上会报错,因为优先级不明确
function fun2( A & B | C $value): void {}

六、Never 返回类型

在 PHP 8.1 之前,函数可以声明返回类型为 void,表示该函数不返回任何值(即没有 return 语句,或者 return; 不带值)。但有些函数不仅不返回值,它们根本不会正常返回------要么抛出异常,要么调用 exit/die 终止脚本执行。PHP 8.1 引入了 never 类型来明确标记这种"永不返回"的函数,让开发者和静态分析工具能够更准确地理解程序的控制流。

范围:never 作为返回类型声明,用于函数或方法定义中,也可以用于闭包和箭头函数。

规则:never 类型只能在返回类型位置使用;声明为 never 的函数或方法绝对不能正常返回(即不能有 return; 或 return $value; 语句,除非该语句在异常或 exit 之后且不可达);如果函数声明为 never 却正常返回,PHP 会抛出一个编译时错误(或运行时 TypeError)。

示例:

php 复制代码
<?php

declare(strict_types=1);

function redirect(string $url): never {
    header("Location: $url");
    exit();
}

function alwaysThrows(): never {
    throw new RuntimeException("Something went wrong");
}

$handler = function(): never {
    throw new Exception("Abort");
};

$arrow = fn(): never => throw new Exception("Abort");

七、Final 类常量

PHP 8.1 之前,类常量可以被任何继承它的子类重新定义,即使是在 final 类中定义的常量也是如此。这种行为虽然灵活,但也带来了问题:父类常量的语义可能被子类无意或有意地改变,破坏了封装性。PHP 8.1 引入了 final 修饰符用于类常量,声明后该常量 不能被子类重写。

语法:final 可以与其他可见性修饰符(publicprotectedprivate)一起使用。它的位置在可见性修饰符之前/后,常量名之前。

示例:

php 复制代码
<?php

declare(strict_types=1);

class A {
    // 两种均可用,官方示例为:final public
    final public const X = 1;
    public final const Y = 2;

    public const Z = 3;
}

class B extends A {
    public const Z = 4; // 会重写
 
    public const X = 2; // 不能被重写,抛出 Fatal error: Cannot override final constant A::X
}

八、对字符串键控数组的数组解包支持

在 PHP 8.1 之前,数组解包(...)仅支持数字索引数组,遇到字符串键名时会直接抛出错误。PHP 8.1 通过 RFC 投票正式打破了这个限制,采用 array_merge 的语义实现了对字符串键数组的解包支持。

  1. 采用 array_merge 语义,后者覆盖前者。

这是理解该特性的关键。当使用 ... 展开数组时,其行为与 array_merge 函数保持一致:对于字符串键,如果键名重复,后面出现的值会覆盖前面的值。

示例:

php 复制代码
<?php

declare(strict_types=1);

$array1 = ["a" => 1];
$array2 = ["a" => 2, "b" => 3];

$result = ["a" => 0, ...$array1, ...$array2];
var_dump($result); // 输出:Array ( [a] => 2 [b] => 3 )
  1. 数字键的例外:保持"追加"语义。

对于数字索引(或数字字符串键),PHP 8.1 依然保留了原有的"重编号(Renumbering)"行为,不会保留原有的数字键名,而是像列表一样追加。

示例:

php 复制代码
<?php

declare(strict_types=1);

$arr1 = [1 => "one", 2 => "two"];
$arr2 = ["3" => "three"]; // 字符串数字键,会被转换为整数 3

$result = [...$arr1, ...$arr2];
var_dump($result); // 输出:Array ( [0] => one [1] => two [2] => three )
  1. 与 + 运算符的核心区别:前者"后覆盖",后者"前保留"。

数组解包 (...) => 行为逻辑:后者覆盖前者 (类似 array_merge);数字键:重新编号,不保留原键;关联键:后面覆盖前面。

+ 运算符 => 行为逻辑:前者保留,后者忽略 (类似"First Wins");数字键:保留原数字键,但仅当键不存在时才追加;关联键:前面优先,后面被丢弃。

示例:

php 复制代码
<?php

declare(strict_types=1);

$arr1 = ["a" => 1, 1 => "one"];
$arr2 = ["a" => 2, 2 => "two"];
// 使用 ... 解包 字符串键覆盖,数字键重排
$unpack = [...$arr1, ...$arr2];
print_r($unpack); // 输出:Array ( [a] => 2 [0] => one [1] => two )

// 使用 + 运算符 字符串键保留第一个,数字键保留原样且不冲突的追加
$plus = $arr1 + $arr2;
print_r($plus); // 输出:Array ( [a] => 1 [1] => one [2] => two )
  1. 为什么是 array_merge 而非"直接丢弃"?

在开发该特性时,社区曾讨论过另一种方案:直接丢弃字符串键,将其视为普通值重排(类似 [...$arr1] 仅提取值)。但最终选择 array_merge 语义,主要有两个原因:

直觉一致性:解包操作符 ... 在字面量中可以被理解为把数组内容"写"进去。例如 ["a" => 1, ...["a" => 2]],就像手动写入了两次 "a" 键,后写的值(2)理应生效。

与参数解包对齐:在 PHP 8.0 中,参数解包(func(...$args))已经支持了字符串键(映射为命名参数)。为了保持语法统一,数组解包也不应简单丢弃这些键。

九、纤程(Fiber)

PHP 8.1 正式引入了纤程(Fiber) 特性,这是 PHP 在语言层面首次原生支持协作式多任务(cooperative multitasking)的轻量级并发机制。在此之前,PHP 开发者主要依靠生成器(Generator)或第三方扩展(如 Swoole、ReactPHP)来实现异步非阻塞编程。纤程的加入,使得 PHP 能够以更优雅、更灵活的方式处理 I/O 密集型任务,并为构建高并发应用提供了新的可能性。

定义:纤程是一种协程(coroutine)的实现,它允许在单线程内实现多个执行流的切换。与线程不同,纤程的切换完全由开发者显式控制(协作式),而非操作系统抢占式调度。每个纤程拥有自己的调用栈,可以在任意位置挂起(suspend),并将控制权交还给主调用者,稍后再从挂起点恢复(resume) 继续执行。

部分应用场景示例:

1、并发调用第三方 API :同时发起 3 个请求,挂起等待,所有响应返回后自动恢复,总耗时 = 最慢的那个接口的耗时

2、并行数据库查询:避免 "查完 A 表再查 B 表" 的串行等待,数据库查询时间从 T1+T2+T3 缩短为 max(T1,T2,T3)

3、非阻塞缓存操作:缓存操作是典型的网络 IO,纤程能让等待缓存响应的时间不浪费。例如:同时从 Redis/Memcached 获取多个 key 的值(如get('user:1') + get('product:100')

4、文件上传与处理:文件 IO 是慢操作,纤程能避免阻塞进程,同时处理多个文件任务。

5、后台任务队列:相比传统的 "多进程消费队列",纤程能在一个进程内同时处理成百上千个任务,内存占用极低。

6、定时任务调度:避免 "一个定时任务阻塞其他任务",无需为每个任务开一个进程 / 线程。

7、日志异步写入:日志写入是高频 IO 操作,纤程能让主业务逻辑不受日志写入速度影响

8、WebSocket 实时通信:比多进程,纤程能在一个进程内维护数万 WebSocket 连接,内存占用仅为多进程的几十分之一。

9、批量数据转换:据处理中往往夹杂着大量文件 / 数据库 IO,纤程能让 CPU 和 IO 设备同时忙碌

示例:

php 复制代码
<?php

declare(strict_types=1);

/**
 * 定义 Task 类,用于封装纤程任务及其当前结果
 */
class Task {
    public function __construct(
        public Fiber $fiber,   // 存储纤程对象
        public mixed $result = null  // 存储每次恢复时传入/返回的值
    ) {}
}

/**
 * 定义调度器类,管理多个任务的轮询执行
 */
class Scheduler {
    // 存储所有 Task 对象的数组
    private array $tasks = [];

    /**
     * 添加一个可调用任务到调度器
     * @param callable $fn 要执行的任务函数
     * @param mixed ...$args 传递给任务函数的参数
     */
    public function add(callable $fn, mixed ...$args): void {
        // 创建一个新的纤程,其回调是一个闭包,用于调用 $fn 并传递参数
        $fiber = new Fiber(function () use ($fn, $args) {
            // 执行用户任务并返回结果
            return $fn(...$args);
        });
        // 将任务封装为 Task 对象,存入任务数组
        $this->tasks[] = new Task($fiber);
    }

    /**
     * 运行调度器,轮询执行所有任务直到完成
     */
    public function run(): void {
        // 当还有未完成的任务时持续循环
        while (!empty($this->tasks)) {
            // 遍历当前所有任务
            foreach ($this->tasks as $i => $task) {
                // 获取当前任务关联的纤程对象
                $fiber = $task->fiber;

                // 情况1:纤程已启动且尚未终止(即处于挂起状态) -> 恢复执行
                if ($fiber->isStarted() && !$fiber->isTerminated()) {
                    // 调用 resume() 恢复纤程,并将上次挂起时保存的 result 作为参数传入
                    // resume() 返回纤程下一次挂起时传出的值(或 null 如果纤程结束)
                    $task->result = $fiber->resume($task->result);
                }
                // 情况2:纤程尚未启动 -> 首次启动
                elseif (!$fiber->isStarted()) {
                    // 调用 start() 启动纤程,执行到第一个挂起点
                    // start() 返回第一个 Fiber::suspend() 传出的值
                    $task->result = $fiber->start();
                }

                // 如果纤程已经终止(执行完毕或抛出异常),则输出返回值并从任务列表中移除
                if ($fiber->isTerminated()) {
                    // 获取纤程的返回值(即任务函数的 return 值)
                    echo "Task finished with return: ", $fiber->getReturn(), "\n";
                    // 从任务数组中删除当前任务
                    unset($this->tasks[$i]);
                }
            }
            // 一轮遍历结束后,继续 while 循环,处理可能剩余的任务
        }
    }
}

// 使用示例:创建调度器
$scheduler = new Scheduler();
echo '<pre>';
// 添加任务 A:先输出 step1,挂起,然后输出 step2,返回字符串
$scheduler->add(function () {
    echo "Task A: step 1\n";
    Fiber::suspend();          // 挂起,控制权交回调度器
    echo "Task A: step 2\n";
    return "A done";
});

// 添加任务 B:结构与任务 A 相同
$scheduler->add(function () {
    echo "Task B: step 1\n";
    Fiber::suspend();
    echo "Task B: step 2\n";
    return "B done";
});

// 启动调度器,开始轮询执行
$scheduler->run();
// 执行结果:
// Task A: step 1
// Task B: step 1
// Task A: step 2
// Task finished with return: A done
// Task B: step 2
// Task finished with return: B done
相关推荐
SEO_juper6 小时前
CDN 地域节点优化:匹配 GEO 信号,提升加载速度
服务器·ai·php·seo·cdn·geo·谷歌优化
dog2506 小时前
解析几何的现代范式-算力,拟合与对偶
服务器·开发语言·网络·线性代数·php
淘矿人7 小时前
【AI大模型】AI 大模型推理平台完整测评:8 家主流聚合服务对比分析
人工智能·sql·gpt·学习·github·php
XiYang-DING10 小时前
【Java EE】TCP—滑动窗口
tcp/ip·java-ee·php
.千余10 小时前
【Linux】网络基础2---Socket编程预备
linux·网络·php
雪度娃娃11 小时前
Asio异步读写——简单服务器和客户端异步通信
运维·服务器·网络·c++·php
中科三方12 小时前
域名解析修改后,用户仍访问旧IP?原因排查与高效解决指南
网络协议·tcp/ip·php
码农老李1 天前
openEuler2403服务器版 原生官方镜像和飞腾定制镜像
开发语言·php