PHP 8 相较于 PHP 7 带来了诸多显著的变化和改进,涵盖了性能、语法、类型系统、错误处理等多个方面。以下是一些主要的变化:

1. 即时编译 (JIT Compiler):

  • PHP 8 引入了 JIT 编译器,这是 PHP 发展的一个重要里程碑。虽然 JIT 对典型的 Web 请求场景带来的性能提升可能不总是非常显著,但它为 CPU 密集型任务(例如数学计算、大数据分析等)带来了显著的性能提升,并为 PHP 的未来发展开辟了新的可能性。

2. 联合类型 (Union Types):

  • PHP 8 允许在类型声明中使用联合类型,这意味着一个变量、参数或返回值可以是多种不同类型之一。例如,一个函数可以接受一个整数或一个浮点数作为参数:function process(int|float $number) {}。这增强了 PHP 的类型系统的灵活性和表达能力。

3. 命名参数 (Named Arguments):

  • 调用函数或方法时,可以为其参数指定名称,而不必严格按照参数定义的顺序传递。这使得代码更具可读性,尤其是在处理具有多个可选参数的函数时,可以清晰地表明每个参数的含义,并且可以跳过可选参数。例如:htmlspecialchars($string, double_encode: false);

4. Match 表达式 (Match Expression):

  • PHP 8 引入了 match 表达式,它提供了一种更简洁、更安全的 switch 语句替代方案。match 表达式使用严格的类型比较(===),而不是 switch 的松散比较(==)。它的返回值可以直接赋给变量,并且每个分支只允许单行表达式,使得代码更易读。如果没有匹配到任何条件且没有 default 分支,match 表达式会抛出 UnhandledMatchError 异常。

5. Nullsafe 运算符 (Nullsafe Operator):

  • 新的 ?-> 运算符允许你在调用链中安全地访问对象的方法或属性,而无需显式检查每一级是否为 null。如果链中的任何部分为 null,整个表达式会短路并返回 null,从而避免了潜在的 null 引用错误。例如:$country = $session?->user?->getAddress()?->country;

6. 注解 (Attributes / Annotations):

  • PHP 8 引入了现代化的注解语法,称为属性 (Attributes)。属性允许开发者为类、方法、属性、参数等添加元数据。这为框架和库提供了一种标准化的方式来声明配置信息或行为,取代了之前通常使用的 PHPDoc 注解。

7. 构造函数属性提升 (Constructor Property Promotion):

  • 这是一种更简洁的声明类属性并在构造函数中初始化的语法。通过在构造函数参数前添加可见性修饰符(public, protected, private),PHP 会自动将这些参数提升为同名的类属性,并进行赋值。这减少了样板代码。

8. 更严格的类型检查和错误处理:

  • PHP 8 对内部函数的参数类型检查更加严格。许多之前会产生警告的类型错误现在会抛出 TypeError 异常。
  • 算术和位运算符在遇到无效类型时会抛出 TypeError,而不是尝试类型转换或返回 null
  • 错误处理方面,默认的错误报告级别改为 E_ALL。许多之前是通知 (Notice) 或警告 (Warning) 级别的问题现在被提升为更严重的错误。

9. 字符串处理函数改进:

  • 引入了一些新的字符串处理函数,如 str_contains() (检查字符串是否包含另一个字符串)、str_starts_with() (检查字符串是否以指定子串开头) 和 str_ends_with() (检查字符串是否以指定子串结尾),使得这些常见的操作更加便捷和易读。

10. 弱映射 (WeakMap):

  • PHP 8 引入了 WeakMap,它允许创建对象的弱引用映射。这意味着当一个对象不再有其他强引用指向它时,它可以被垃圾回收,即使它仍然是 WeakMap 中的键。这有助于防止内存泄漏,尤其是在处理缓存或对象关系时。

11. 其他变化:

  • throw 可以作为表达式使用: throw 现在可以在箭头函数、合并运算符 (??) 或三元运算符等表达式上下文中使用。
  • 允许参数列表中的尾随逗号: 在函数或方法的参数列表末尾添加逗号现在是合法的,这在版本控制中合并代码时很有用。
  • 静态返回类型 (static): 方法可以声明返回 static 类型,表示返回调用该方法的类的实例。
  • mixed 类型: 引入了 mixed 类型,它可以表示任何值。虽然这降低了类型检查的严格性,但在某些情况下,当一个值确实可以是任何类型时,它比不声明类型或使用联合类型更为清晰。
  • Non-capturing catches: try-catch 块中的 catch 语句现在可以不捕获异常对象到变量中,如果不需要使用该对象的话:catch (MyException) { /* ... */ }

总的来说,PHP 8 在保持向后兼容性的同时,通过引入 JIT 编译器提升了性能潜力,并通过新的语法特性和更严格的类型系统显著增强了语言的表达能力、健壮性和可维护性,使得 PHP 向着更现代化、更高效的语言迈进了一大步。从 PHP 7 升级到 PHP 8 通常会带来益处,但也需要注意一些不向后兼容的变更和更严格的错误处理机制。 PHP 8 相较于 PHP 7 引入了多项显著变化,涵盖性能、语法、错误处理、类型系统等多个方面。这些更新旨在提升开发效率、代码可读性和应用性能。

以下是 PHP 8 对比 PHP 7 的主要显著变化:

一、性能提升:JIT 编译器

PHP 8 最引人注目的变化之一是引入了即时编译 (JIT) 编译器。JIT 编译器可以将 PHP 代码在运行时编译为机器码,从而在某些类型的应用(尤其是计算密集型任务)中带来显著的性能提升。虽然对于典型的 Web 应用,其性能提升可能不像从 PHP 5 到 PHP 7 那样巨大,但在特定场景下,JIT 能够提供实质性的速度改进。

二、新增和改进的语法特性

PHP 8 引入了大量新的语法糖和特性,使得代码更简洁、更具表达力:

  • 命名参数 (Named Arguments): 允许在调用函数时通过参数名指定参数值,无需关心参数顺序,提高了代码的可读性和可维护性,尤其对于拥有多个可选参数的函数非常有用。

    // PHP 7
    htmlspecialchars($string, ENT_COMPAT | ENT_HTML401, 'UTF-8', false);
    
    // PHP 8
    htmlspecialchars(string: $string, encoding: 'UTF-8', double_encode: false);
  • 属性 (Attributes / Annotations): 允许向类、方法、属性、参数等添加结构化的元数据。这为框架和工具提供了更强大的代码分析和扩展能力。
    // PHP 8
    #[Route("/api/posts/{id}", methods: ["GET"])]
    public function getPost(int $id) { /* ... */ }
  • 构造函数属性提升 (Constructor Property Promotion): 简化了在构造函数中声明和初始化类属性的样板代码。

    // PHP 7
    class Point {
        public float $x;
        public float $y;
        public float $z;
    
        public function __construct(float $x, float $y, float $z) {
            $this->x = $x;
            $this->y = $y;
            $this->z = $z;
        }
    }
    
    // PHP 8
    class Point {
        public function __construct(
            public float $x,
            public float $y,
            public float $z,
        ) {}
    }
  • Match 表达式 (Match Expression): 作为 switch 语句的增强版,match 表达式提供更简洁、更安全的条件判断。它进行严格比较(===),并且是一个表达式,其结果可以直接赋值或返回。

    // PHP 7 (switch)
    switch ($httpCode) {
        case 200:
        case 300:
            $message = 'OK';
            break;
        case 400:
            $message = 'Not Found';
            break;
        default:
            $message = 'Unknown status code';
    }
    
    // PHP 8 (match)
    $message = match ($httpCode) {
        200, 300 => 'OK',
        400 => 'Not Found',
        default => 'Unknown status code',
    };
  • Nullsafe 运算符 (Nullsafe Operator): 允许在链式属性或方法调用中安全地处理 null 值,避免了冗长的 null检查。

    // PHP 7
    $country = null;
    if ($session !== null) {
        $user = $session->user;
        if ($user !== null) {
            $address = $user->getAddress();
            if ($address !== null) {
                $country = $address->country;
            }
        }
    }
    
    // PHP 8
    $country = $session?->user?->getAddress()?->country;
  • 联合类型 (Union Types): 允许声明一个变量、参数或返回值可以是多种不同类型之一。

    // PHP 8
    class Number {
        private int|float $number;
    
        public function setNumber(int|float $number): void {
            $this->number = $number;
        }
    
        public function getNumber(): int|float {
            return $this->number;
        }
    }
  • Mixed 类型 (Mixed Type): mixed 类型等价于 array|bool|callable|int|float|null|object|resource|string。它表明一个参数或返回值可以是任何类型。
  • Static 返回类型 (Static Return Type): 允许在方法中返回一个 static 类型,表示该方法将返回调用它的类的实例。
  • Throw 表达式 (Throw Expression): throw 现在可以作为表达式使用,例如在箭头函数或 null 合并操作符中使用。
    // PHP 8
    $user = $session->user ?? throw new UserNotFoundException();
    $callable = fn() => throw new Exception('Something went wrong');
  • 参数列表和闭包 use 列表中的尾随逗号 (Trailing Commas): 允许在函数或方法的参数列表以及闭包的 use 列表的最后一个元素后面添加逗号,方便版本控制和代码修改。

三、更严格的类型系统和错误处理

PHP 8 在类型检查和错误处理方面变得更加严格:

  • 更严格的类型检测: 算术和位运算符在遇到不兼容类型时会抛出 TypeError,而不是尝试隐式转换或产生警告。
  • 内部函数更严格的参数检查: 许多内部函数现在对其参数进行更严格的验证,并在提供无效输入时抛出 TypeErrorValueError
  • 错误处理的改变:
    • 许多之前产生警告 (Warning) 的情况现在会产生错误 (Error) 异常。
    • 一些之前产生通知 (Notice) 或警告的情况现在被提升为警告或致命错误 (Fatal Error)。
    • 默认情况下,断言失败 (assert()) 现在会抛出 AssertionError
  • 不兼容的方法签名导致 Fatal 错误: 当子类的方法签名与父类或接口的方法签名不兼容时,将产生 Fatal 错误。

四、向后不兼容的变化和移除的功能

PHP 8 引入了一些向后不兼容的变更,并移除了一些过时的功能:

  • 保留关键字: matchmixed 现在是保留关键字。
  • 移除的函数:
    • create_function() 已被移除。
    • each() 已被移除。
    • money_format() 已被移除。
    • get_magic_quotes_gpc()get_magic_quotes_runtime() 已被移除。
    • 一些已弃用的 mbstring 函数别名已被移除。
  • mbstring.func_overload 指令被移除。
  • MySQLi 扩展的默认错误模式更改为异常。
  • GD 库中一些函数的变更和移除。 例如,移除了 image2wbmp()png2wbmp()jpeg2wbmp()
  • == 运算符的调整: 字符串与数字的比较逻辑有所调整,更偏向于数字比较或将数字转为字符串进行比较。

五、PHP 7 的重要特性回顾

为了更好地对比,我们回顾一下 PHP 7 相对于早期版本的主要特性:

  • 显著的性能提升: Zend Engine 3 带来了巨大的性能改进,通常比 PHP 5.6 快两倍以上。
  • 标量类型声明 (Scalar Type Declarations): 允许为函数参数和返回值声明 int, float, string, 和 bool 类型。
  • 返回值类型声明 (Return Type Declarations): 允许指定函数应返回的类型。
  • Null 合并运算符 (Null Coalescing Operator ??): 简化了检查变量是否存在并为其提供默认值的操作。
  • 太空船操作符 (Spaceship Operator <=>): 用于进行三路比较,如果左边小于、等于或大于右边,则分别返回 -1、0 或 1。
  • 通过 define() 定义常量数组。
  • 匿名类 (Anonymous Classes)。
  • Throwable 接口: 所有错误和异常都实现了这个接口,使得错误处理更加统一。
  • 许多致命错误转换为异常 (Exceptions)。

总结

PHP 8 是一个重要的主版本更新,它不仅通过 JIT 编译器带来了潜在的性能飞跃,还通过引入命名参数、属性、Match 表达式和更强大的类型系统等特性,极大地改善了开发体验和代码质量。虽然存在一些向后不兼容的变更,但迁移到 PHP 8 通常会带来更现代化、更健壮和更高性能的应用程序。而 PHP 7 本身也是一个里程碑式的版本,它为 PHP 的现代化奠定了坚实的基础,尤其是在性能和类型系统方面。