已经2025年不会还没尝试过 PHP8 吧!

0x0 工作中有正式把 PHP8 投入生产吗?

2016 年的时候第一次接触到 PHP,貌似是 PHP5.6 的版本,采用LAMP 架构快速构建 WEB 应用;当时的互联网公司使用 PHP 的应该还是蛮多的,百度、微博也都在使用,鸟哥应该算是国内 PHP 明星级别的人物;后面 2019年的时候记得当时面试中必不可少的是会问到 PHP5和PHP7的区别是什么, 性能上来说确实是非一般的提升,主要是对类型的底层结构都进行了调整;后来 2020 年似乎整个世界环境都不太好,PHP 在国内也走下坡路,虽然推出了 PHP8 ,但国内也开始了一阵 PHP转Golang的风,不少公司的技术也开始转型;2021年,核心贡献者 Nikita Popov 离开 PHP,迫使基金会的事项不得不加速提上进程,也让 PHP 再一次续命;此后每年 PHP 迭代一个大版本,2024年底也发布了 PHP8.4,按照计划 2025 年也会推出 PHP8.5 。

所以你有用到 PHP8 ,或者说你有在公司级项目推 PHP8 的落地吗?我之前工作的地方依然还有 PHP5.6,当然那是比较早的项目,目前公司如果还在用PHP,应该大多数是 PHP7 了吧。so 即使工作中没用到 PHP8,但是你可以用PHP8为自己带来财富,不是么,如果你想要自己做一些什么,PHP绝对是效率。PHP Is Not Dead !

0x1 PHP8.0

PHP 8.0 是 PHP 语言的一次重大更新。 它包含了很多新功能与优化项, 包括命名参数、联合类型、注解、构造器属性提升、match 表达式、nullsafe 运算符、JIT,并改进了类型系统、错误处理、语法一致性。

1.1 命名参数(Named arguments)

  • php8.0 允许您按名称指定参数,而不是按位置指定。这在调用具有许多参数的函数时特别有用,使代码更具可读性。再也不用担心可能由于参数数量繁多,导致位置传递错误。
  • 仅仅指定必填参数,跳过可选参数
  • 参数的顺序无关、自己就是文档(self-documented)
// Named arguments
$min = 3600;
$max = 7200;
echo 'rand-' . random_int($min, $max) . PHP_EOL;
echo 'rand-' . random_int(max:$max, min:$min) . PHP_EOL;

1.2 注解(Attributes)

  • 注解在代码中为类和属性提供元数据。这些元数据可以在运行时通过反射(Reflection)读取,并作出相应处理。
  • 注解 PHP 原生语法来使用结构化的元数据,而非 PHPDoc 声明。
  • 注解用于软件架构中常见的需求,例如依赖注入、验证、日志记录等。

简单的注解

  • #[Attribute]声明注解类
    • 这个注解类被声明为可以用于类和属性(TARGET_CLASS | TARGET_PROPERTY)
// 定义一个简单的注解类
#[Attribute(Attribute::TARGET_CLASS | Attribute::TARGET_PROPERTY)]
class MyAttribute
{
// 它定义了两个属性name和value
    public function __construct(
        public string $name,
        public int $value
    ) {}
}
  • 使用注解
    • 把自定义的 MyAttribute 注解类,使用到TestClass类和它的$property属性上。
// 另一个类中使用这个注解
#[MyAttribute(name: 'TestClass', value: 10)]
class TestClass
{
    #[MyAttribute(name: 'TestProperty', value: 20)]
    public string $property;
}
  • 读取注解
    • 可以使用反射对象 ReflectionClass
// 创建一个ReflectionClass对象,用来获取 TestClass 相关信息
$reflectionClass = new ReflectionClass(TestClass::class);
// 获取某个类的注解
$classAttributes = $reflectionClass->getAttributes(MyAttribute::class);
foreach ($classAttributes as $attribute) {
    $instance = $attribute->newInstance();
    echo "Class Attribute: name = {$instance->name}, value = {$instance->value}" . PHP_EOL;
}


// 获取某个类的属性注解
$reflectionProperty = $reflectionClass->getProperty('property');
$propertyAttributes = $reflectionProperty->getAttributes(MyAttribute::class);

foreach ($propertyAttributes as $attribute) {
    $instance = $attribute->newInstance();
    echo "Property Attribute: name = {$instance->name}, value = {$instance->value}" . PHP_EOL;
}

具体的例子

  • 定义一个Validation注解类,利用注解自动验证数据;
  • helpValidate 方法被修改为对 rules 数组中的每一个规则进行迭代并进行验证。这种设计允许您轻松添加更多规则而无需修改现有的代码逻辑。
#[Attribute(Attribute::TARGET_PROPERTY)]
class Validation
{
    public function __construct(
        public string $rule
    ) {}
}

class User
{
    #[Validation('required|string')]
    public string $username;

    #[Validation('required|email')]
    public string $email;
}

/**
 * 使用注解判断某个对象的属性是否合法
 *
 * @param object $object
 * @return void
 */
function helpValidate(object $object): void
{
    $reflectionClass = new ReflectionClass($object);
    // 获取某个对象所有的属性
    foreach ($reflectionClass->getProperties() as $property) {
        // 获取这个注解的属性
        $attributes = $property->getAttributes(Validation::class);
        // 对所有属性进行检查
        foreach ($attributes as $attribute) {
            $validation = $attribute->newInstance();
            $value = $property->getValue($object);
            $rules = explode("|", $validation->rule);
            foreach ($rules as $rule) {
                if ($rule === 'required') {
                    if (empty($value)) {
                        throw new Exception("{$property->getName()} is required.");
                    }
                } elseif ($rule === 'email') {
                    if (!filter_var((string)$value, FILTER_VALIDATE_EMAIL)) {
                        throw new Exception("{$property->getName()} is not a valid email.");
                    }
                }
            }
        }
    }
}

$user = new User();
$user->username = 'mochi';
$user->email = 'mochi.com';
try {
    helpValidate($user);
    echo "Validation passed.";
} catch (Exception $e) {
    echo $e->getMessage();
}

1.3 构造器属性提升(Constructor property promotion)

  • 更少的代码来定义并初始化属性;
  • 语法糖,相当于省略构造函数的参数作为类的成员变量的定义;
  • 使用构造器属性提升可以减少重复代码,从而使代码更简洁和更具可读性;
class Point {
    public function __construct(
      public float $x = 0.0,
      public float $y = 0.0,
      public float $z = 0.0,
    ) {}
}

1.4 联合类型(Union types)

  • 相较于以前的 PHPDoc 声明类型的组合, 现在可以用原生支持的联合类型声明取而代之,并在运行时得到校验;
  • 通过 declare(strict_types=1); 强制执行严格类型检查,确保传递的类型符合预期;
  • 联合类型(Union Types)允许变量、参数和返回值同时接受多个类型;
  • 通过联合类型的功能,可以简化代码中类型的定义,提升代码的灵活性;
<?php
// 记得加上
declare(strict_types=1);
class Number {
    public function __construct(
      private int|float $number
    ) {}

    function getNumber() :int|float {
        return $this->number;
    }
}
echo gettype((new Number(1))->getNumber()) .PHP_EOL;  // integer
echo gettype((new Number(3.14))->getNumber()).PHP_EOL; // double
// 如果没有 strict_types = 1 PHP就会强转成 integer
// Fatal error: Uncaught TypeError: Number::__construct(): Argument #1 ($number) must be of type int|float, string given, called 
echo gettype((new Number('0'))->getNumber()).PHP_EOL; // TypeError

1.5 Match 表达式(Match expression)

  • 新的 match 类似于 switch;
  • Match 是一个表达式,它可以储存到变量中亦可以直接返回;
  • Match 分支仅支持单行,它不需要一个 break; 语句;
  • Match 使用严格比较,这样对类型来说是一个不错的点,相当于三个等号=== ;
  • match 语法更简洁,更具可读性,有助于减少错误,并提高代码清晰度;
echo match (8.0) {
    '8.0' => "Oh no!",
    8.0 => "This is what I expected",
};

1.6 Nullsafe 运算符(Nullsafe operator)

  • Nullsafe 运算符 ?->,它提供了一种安全访问对象属性或方法的方法,而不会抛出错误;
  • 如果你熟悉 Null 合并运算符 (??),你可以将它视为对象方法或属性访问的版本;
  • 简洁的代码,现在可以用新的 nullsafe 运算符链式调用,而不需要条件检查 Null;
  • 防止空指针异常, 如果链条中的一个元素失败了,整个链条会中止并认定为 Null;
class Address {
    public function __construct(
        public ?string $city
    ) {}
}
class User {
    public function __construct(
        public ?Address $address
    ) {}
}

// 对象有值的情况
$user = new User(new Address("BeiJing"));
echo $user?->address?->city; // 输出: BeiJing

// 对象没有值的情况
$userWithoutAddress = new User(null);
echo $userWithoutAddress?->address?->city; // 输出: (null)

1.7 字符串与数字的比较(Saner string to number comparisons)

  • PHP 8 比较数字字符串(numeric string)时,会按数字进行比较。 不是数字字符串时,将数字转化为字符串,按字符串比较。
  • 不过针对这种,我们最好还是用强等,或者类型提前强转,不然当发生问题的时候,可能会有些奇怪;
var_dump(0 == 'foobar'); // false
var_dump(0 == '0');  // true
var_dump(0 === '0'); // false

1.8 内部函数类型错误的一致性(Consistent type errors for internal functions)

  • 传递给函数的参数类型不正确时,PHP 8 会抛出 TypeError;
  • 接收到无效参数时会抛出 ValueError;
// TypeError: strlen(): Argument #1 ($str) must be of type string, array given
strlen([]); 
// ValueError: array_chunk(): Argument #2 ($length) must be greater than 0
array_chunk([], -1); 

1.9 即时编译 JIT

  • PHP 8 引入了 JIT(Just-In-Time)编译器,这是一个显著的性能优化特性。JIT 编译器的目标是提高 PHP 的执行效率,通过将部分 Opcodes 转换为机器代码,以减少执行时间并提升性能。
  • PHP 8 引入了两个即时编译引擎, Tracing JIT / Function JIT ,Tracing JIT 在两个中更有潜力,它在综合基准测试中显示了三倍的性能, 并在某些长时间运行的程序中显示了 1.5-2 倍的性能改进。 典型的应用性能则和 PHP 7.4 不相上下;
  • OpCache 的作用 为了避免每次代码都需要经过词法分析、语法分析、解释编译,我们可以利用 PHP 的 OPcache 扩展缓存 OPcodes 来加快速度;
  • 之前 OPcache 扩展可以更快的获取 OPcodes 将其直接转到 Zend VM ,现在 JIT 让它们完全不使用 Zend VM 即可运行,Zend VM 是用 C 编写的程序,充当 OPcodes 和 CPU 之间的一层;
  • JIT在Opcache优化之后的基础上,结合Runtime的信息再次优化,直接生成机器码;
  • JIT不是原来Opcache优化的替代,是增强;

0x2 PHP8.1

PHP 8.1 是 PHP 语言的一次重大更新。 它包含了许多新功能,包括枚举、只读属性、First-class 可调用语法、纤程、交集类型和性能改进等。

2.1 枚举 (Enumerations)

  • 使用枚举而不是一组常量并立即进行验证;
  • 类型安全:枚举强制了类型检查,从而保证了传入的值是定义好的枚举之一,减少了运行时错误的可能性;
  • 避免魔法字符串:使用枚举可以避免重复和可能出错的魔法字符串。这使得代码可维护性更高,不必担心字符串拼写错误等问题。
// 创建枚举
enum Status: string
{
    case Draft = 'draft';
    case Published = 'published';
    case Archived = 'archived';
}

// 创建一个方法,接受 Status 枚举类型作为参数
function acceptStatus(Status $status): void
{
    match ($status) {
        Status::Draft => print "Status is Draft" . PHP_EOL,
        Status::Published => print "Status is Published". PHP_EOL,
        Status::Archived => print "Status is Archived". PHP_EOL,
    };
}
// 使用枚举调用方法
acceptStatus(Status::Draft);     // 输出 "Status is Draft"
acceptStatus(Status::Published); // 输出 "Status is Published"

2.2 只读属性 (Readonly Properties)

  • 只读属性不能在初始化后更改,即在为它们分配值后。它们可以用于对值对象和数据传输对象建模;
class Geolocation
{
    public readonly float $latitude;
    public readonly float $longitude;

    public function __construct(float $latitude, float $longitude)
    {
        $this->latitude = $latitude;
        $this->longitude = $longitude;
    }
}
// 示例:创建不同的地理位置对象
$nyLocation = new Geolocation(40.7128, -74.0060);  // 纽约
$laLocation = new Geolocation(34.0522, -118.2437); // 洛杉矶

echo "New York Location - Latitude: " . $nyLocation->latitude . ", Longitude: " . $nyLocation->longitude;
// 输出 "New York Location - Latitude: 40.7128, Longitude: -74.0060"

echo "Los Angeles Location - Latitude: " . $laLocation->latitude . ", Longitude: " . $laLocation->longitude;
// 输出 "Los Angeles Location - Latitude: 34.0522, Longitude: -118.2437"

2.3 First-class 可调用语法 (First-class Callable Syntax)

  • 现在可以获得对任何函数的引用。这统称为 First-class 可调用语法;
  • 那些接受其他函数作为参数的函数,可以更简洁地将方法或函数引用传递给这些高阶函数;
  • First-class 是一项非常强大的功能,通过这个语法,开发者能够更简洁地获取和使用函数或方法引用;
  • 这对编写更清晰、可维护的代码,以及更高效地处理回调函数和高阶函数提供了很大的帮助;
    class StringHelper
    {
      public static function toUpperCase(string $value): string
      {
          return strtoupper($value);
      }
    }
    // 示例数组
    $words = ["hello", "world", "php8.1"];
    // 使用 First-class Callable Syntax 将方法引用传递给 array_map
    $uppercaseWords = array_map(StringHelper::toUpperCase(...), $words);
    // 输出结果
    print_r($uppercaseWords);

2.4 新的初始化器 (New in initializers)

  • 对象现在可以用作默认参数值、静态变量和全局常量,以及属性参数

    class Notifier
    {
      public function notify(string $message): void
      {
          echo "Notification: $message" . PHP_EOL;
      }
    }
    class User
    {
      private Notifier $notifier;
    
      public function __construct(
          Notifier $notifier = new Notifier(),
      ) {
          $this->notifier = $notifier;
      }
    
      public function notify(string $message): void
      {
          $this->notifier->notify($message);
      }
    }
    $user = new User();
    $user->notify('Hello, default notifier');

2.5 纯交集类型 (Pure Intersection Types)

  • 当一个值需要同时满足多个类型约束时,使用交集类型。

    function handle(Iterator&Countable $value) {
      foreach ($value as $val) {
          echo $val;
      }
    
      count($value);
    }

    2.6 Never 返回类型 (Never return type)

  • 使用 never 类型声明的函数或方法表示它不会返回值,并且会抛出异常或通过调用 die()、exit()、trigger_error() 或类似的东西来结束脚本的执行。

function redirect(string $uri): never {
    header('Location: ' . $uri);
    exit();
}
function redirectToLoginPage(): never {
    redirect('/login');
    echo 'Hello';
}

2.7 Final 类常量 (Final class constants)

  • 可以声明 final 类常量,以禁止它们在子类中被重写
class Foo
{
    final public const XX = "foo";
}

class Bar extends Foo
{
    public const XX = "bar"; // Fatal error
}

2.8 显式八进制数字表示法 (Explicit Octal numeral notation)

  • 现在可以使用显式 0o 前缀表示八进制数
var_dump(0o16 === 16); 
var_dump(0o16 === 14);
var_dump(0o16);

2.9 纤程 (Fibers)

Fibers 是用于实现轻量级协作并发的基础类型。它们是一种创建可以像生成器一样暂停和恢复的代码块的方法,但可以从堆栈中的任何位置进行。Fibers 本身并没有提供并发性,仍然需要一个事件循环。但是,它们允许通过阻塞和非阻塞实现共享相同的 API。
Fibers 允许摆脱以前在 Promise::then() 或基于生成器的协程中看到的样板代码。库通常会围绕 Fiber 构建进一步的抽象,因此无需直接与它们交互。

// 确保你的 PHP 版本是 8.1 或更高版本,因为 Fiber 是 PHP 8.1 引入的特性
$fiber = new Fiber(function() {
    echo "Fiber started\n";
    $value = Fiber::suspend('Fiber paused');
    echo "Fiber resumed with value: $value\n";
    return 'Fiber ended';
});
// 启动 Fiber,并获取它暂停时传递的值
$value = $fiber->start();
echo "Main resumed with value: $value\n";

// 恢复 Fiber 的执行,并传递一个值
$returnedValue = $fiber->resume('Resuming fiber with this value');
echo "Fiber returned with value: $returnedValue\n";

echo "Main ended\n";

2.10 对字符串键控数组的数组解包支持 (Array unpacking support for string-keyed arrays)

  • PHP 以前支持通过扩展运算符在数组内部解包,但前提是数组具有整数键。现在也可以使用字符串键解包数组;
$arrayA = ['a' => 1];
$arrayB = ['b' => 2];
$result = ['a' => 0, ...$arrayA, ...$arrayB];
var_dump($result);

0x3 PHP8.2

3.1 只读类

  • readonly 类中的所有属性将自动标记为 readonly,不需要单独声明每个属性;
readonly class BlogData
{
    public string $title;

    public Status $status;

    public function __construct(string $title, Status $status)
    {
        $this->title = $title;
        $this->status = $status;
    }
}

3.2 析取范式 (DNF)类型

  • DNF 类型允许我们组合 union 和 intersection类型,遵循一个严格规则;
  • 组合并集和交集类型时,交集类型必须用括号进行分组。
    class Foo {
      public function bar((A&B)|null $entity) {
          return $entity;
      }
    }

3.3 允许 null、false 和 true 作为独立类型

class Falsy
{
    public function alwaysFalse(): false {
        return false;
    }
    public function alwaysTrue(): true {
        return true;
    }
    public function alwaysNull(): null {
        return null;
    }
}

3.4 新的“随机”扩展

  • “随机”扩展为随机数生成提供了一个新的面向对象的 API;
  • 这个面向对象的 API 提供了几个类(“引擎”),提供对现代算法的访问,这些算法在对象中存储其状态,以允许多个独立的可播种序列,而不是依赖于使用 Mersenne Twister 算法的全局种子随机数发生器(RNG);
    use Random\Randomizer;
    $randomizer = new Randomizer();
    $randomInt = $randomizer->getInt(1, 100);
    

var_dump($randomInt);


## 3.5 Traits 中的常量

- 您不能通过 trait 名称访问常量,但是您可以通过使用 trait 的类访问常量;

```php
trait Foo
{
    public const CONSTANT = 1;
}

class Bar
{
    use Foo;
}
var_dump(Bar::CONSTANT);

3.6 弃用动态属性

  • 动态属性的创建已被弃用,以帮助避免错误和拼写错误;
    class User
    {
      public $name;
    }
    $user = new User();
    $user->last_name = 'Doe'; // Deprecated notice
    $user = new stdClass();
    $user->last_name = 'Doe'; // Still allowed

0x4 PHP8.3

PHP 8.3 是 PHP 语言的一次重大更新。 它包含了许多新功能,例如:类常量显式类型、只读属性深拷贝,以及对随机性功能的补充。一如既往,它还包括性能改进、错误修复和常规清理等。

4.1 类型化类常量 (Typed class constants)

  • PHP 8.3 ,增加了类常量的类型定义,如果你给了不符合类型的值,将会抛出 Fatal error 致命错误;
  • 当然这不是必须的,你依然可以不参用类型声明;
    class BeforeFoo
    {
      // php83 之前,可以直接这么定义
      const BAR = 'bar'; 
    }
    class Foo
    {
      // php83 时,可以给常量也加上类型声明
      const string BAR = 'bar'; 
    }
    class ErrFoo
    {
      // php83 时,你可以给常量加类型声明,但如果错误,将会抛出异常
      // Fatal error: Cannot use string as value for class constant ErrFoo::BAR of type int
      const int BAR = 'bar'; 
    }

4.2 动态获取类常量 (Dynamic class constant fetch)

class Foo 
{
    const BAR = 'bar';
    public $name = '1';
}
$name = 'BAR';

// php8.3 之前
echo constant(Foo::class . '::' . $name) , PHP_EOL;

// php8.3 现在
echo Foo::{$name} , PHP_EOL;

// php8.3 现在 切记给变量带上 {} ,它标识先解析 name 变量,再获取类常量
// 下面是错误用法:Fatal error: Uncaught Error: Access to undeclared static property Foo::$name
// echo Foo::$name;

4.3 新增 #[\Override] 属性

  • 通过给方法添加 #[\Override] 属性,PHP 将确保在父类或实现的接口中存在同名的方法。
  • 添加该属性表示明确说明覆盖父方法是有意为之,并且简化了重构过程,因为删除被覆盖的父方法将被检测出来。

4.4 只读属性深拷贝 (Deep Clone readonly properties)

readonly class People
{
    public function __construct(
        public string $name,
        public string $age,
        public DateTime $createdAt,
    ) {}


    public function __clone()
    {
        $this->createdAt = new DateTime(); 
    }
}

$tacks = new People(
    name: 'Mochi',
    age: 18,
    createdAt: new DateTime(),
);

var_dump($tacks);

$nextMe = clone $tacks;

// php8.3 之前 Fatal error: Uncaught Error: Cannot modify readonly property People::$createdAt
// php8.3 可用 在克隆过程中可以重新初始化只读属性
var_dump($nextMe);

4.5 新增 json_validate() 函数

/**
 * json 验证 (php83之前)
 *
 * @param string $string
 * @return boolean|string
 */
function jsonValidate(string $string): bool|string {
    $data = json_decode($string);
    if($data === null || json_last_error() !== JSON_ERROR_NONE) {
        return json_last_error_msg();
    } 
    return true;
}


// php8.3
json_validate('{ "test": { "foo": "bar" } }'); // true
json_validate('{ "test": { "foo": "bar" , "test"} }'); // false

4.6 新增 Randomizer::getBytesFromString() 方法

  • 在 PHP 8.2 中新增的 Random 扩展 通过一个新方法生成由特定字节组成的随机字符串。
  • 这种方法可以使开发者更轻松的生成随机的标识符(如域名),以及任意长度的数字字符串。
$randomizer = new \Random\Randomizer();
$randomDomain = sprintf(
    "%s.example.com",
    $randomizer->getBytesFromString(
        'abcdefghijklmnopqrstuvwxyz0123456789',
        16,
    ),
);
echo $randomDomain;

4.7 新增 Randomizer::getFloat() 和 Randomizer::nextFloat() 方法

  • 由于浮点数的精度有限和隐式舍入,生成位于特定区间内的无偏浮点数并非易事,并且常用的用户态解决方案可能会生成有偏差的结果或超出请求范围的数字;
  • 所以说官方出手了,还是比自己封装的要高效好用,之后随机浮点数可以来参考这个了
//  新增 getFloat() nextFloat()
$randomizer = new \Random\Randomizer();

// getFloat($min, $max) 返回之间的浮点数
// Closed表示包含该值,表示Open排除该值
$temperature = $randomizer->getFloat(
    -89.2,
    56.7,
    \Random\IntervalBoundary::ClosedClosed,
);
var_dump($temperature);

// nextFloat() 它将为您提供 0 到 1 之间的随机浮点数,其中 1 被排除
var_dump($randomizer->nextFloat());

$chanceForTrue = 0.8;
$myBoolean = $randomizer->nextFloat() < $chanceForTrue;
var_dump($myBoolean);

4.8 命令行 linter 支持多个文件

  • 说实话,用 php 也挺久的了,竟然没发现,或者说没用过 -l 选项;
  • 要不是这次看了 php8.3 的新功能首页 ,把这个功能明显的列出来,我还真不知道,哈哈哈哈;
$ php -l test1.php test2.php

Parse error: syntax error, unexpected end of file in test1.php on line 21
Errors parsing test1.php

Parse error: syntax error, unexpected token "{", expecting identifier in test2.php on line 5
Errors parsing test2.php 

0x5 PHP8.4

PHP 8.4 是 PHP 语言的一次重大更新。 它包含许多新功能,例如属性钩子、不对称可见性、更新的 DOM API、性能改进、错误修复和常规清理等。

5.1 属性钩子 (Property hooks)

  • 属性钩子提供对计算属性的支持,这些属性可以被 IDE 和静态分析工具直接理解,而无需编写可能会失效的 docblock 注释。
  • 此外,它们允许可靠地预处理或后处理值,而无需检查类中是否存在匹配的 getter 或 setter。
class LocaleClass
{
    public string $languageCode;

    public string $countryCode
    {
        set (string $countryCode) {
            $this->countryCode = strtoupper($countryCode);
        }
    }

    public string $combinedCode
    {
        get => sprintf("%s_%s", $this->languageCode, $this->countryCode);
        set (string $value) {
            [$this->languageCode, $this->countryCode] = explode('_', $value, 2);
        }
    }

    public function __construct(string $languageCode, string $countryCode)
    {
        $this->languageCode = $languageCode;
        $this->countryCode = $countryCode;
    }
}
$brazilianPortuguese = new LocaleClass('pt', 'br');
var_dump($brazilianPortuguese->countryCode); // BR
var_dump($brazilianPortuguese->combinedCode); // pt_BR

5.2 不对称可见性 (Asymmetric Visibility)

  • 现在可以独立地控制写入属性的作用域和读取属性的作用域,减少了需要编写繁琐的 getter 方法来公开属性值而不允许从类外部修改属性的需求

  • 该类 PhpVersion 定义了一个私有版本属性,并通过公共方法访问该属性。

  • 提供 increment 方法递增次版本号。通过正确的保护和访问控制实现属性的只读特性。

  • 并保证了版本属性只能通过类内部的方法被修改,外部只能读取。

    class PhpVersion{
      public private(set) string $version = '8.4';
    
      public function increment(): void{
          [$major, $minor] = explode('.', $this->version);
          $minor++;
          $this->version = "{$major}.{$minor}";
      }
    }
    // 使用示例
    $obj = new PhpVersion();
    $obj->increment();
    var_dump($obj->getVersion()); // 输出 string(3) "8.5"

5.3 #[\Deprecated] 属性

  • 新的 #[\Deprecated] 属性使 PHP 的现有弃用机制可用于用户定义的函数、方法和类常量

5.4 新的 ext-dom 功能和 HTML5 支持

  • 新的 DOM API 包括符合标准的支持,用于解析 HTML5 文档,修复了 DOM 功能行为中的几个长期存在的规范性错误,并添加了几个函数,使处理文档更加方便
  • 新的 DOM API 可以在 Dom 命名空间中使用。使用新的 DOM API 可以使用 Dom\HTMLDocument 和 Dom\XMLDocument 类创建文档

5.5 BCMath 的对象 API (Object API for BCMath)

  • 新的 BcMath\Number 对象使在处理任意精度数字时可以使用面向对象的方式和标准的数学运算符。
  • 这些对象是不可变的,并实现了 Stringable 接口,因此可以在字符串上下文中使用,如 echo $num。
use BcMath\Number;

$num1 = new Number('0.12345');
$num2 = new Number('2');
$result = $num1 + $num2;

echo $result; // '2.12345'
var_dump($num1 > $num2); // false

5.6 新的 array_*() 函数

  • 使用 array_find 查找第一个以字母 ‘c’ 开头的元素。
  • 传入的回调函数是一个静态匿名函数 static fn (string $value): bool => str_starts_with($value, ‘c’),它使用 str_starts_with 函数检查字符串是否以 c 开头。
    $animal = array_find(
      ['dog', 'cat', 'cow', 'duck', 'goose'],
      static fn (string $value): bool => str_starts_with($value, 'c'),
    );
    

var_dump($animal); // string(3) “cat”

## 5.7 PDO 驱动程序特定子类

## 5.8 new MyClass()->method() 不需要括号
- 现在可以在不使用括号包裹 new 表达式的情况下访问新实例化对象的属性和方法。
```php
class PhpVersion
{
    public function getVersion(): string
    {
        return 'PHP 8.4';
    }
}
var_dump(new PhpVersion()->getVersion());

0x6 其他 PHP 相关资讯

6.1 开国元老级别

  • Rasmus Lerdorf(拉斯马斯・勒德尔夫),PHP 语言之父:1995年首次发布 PHP。在多家知名企业担任技术领导角色,包括 Yahoo! 和 WePay。 负责开发和维护 Yahoo! 的核心基础设施。
  • Andi Gutmans,创立 Zend Technologies:与 Zeev Suraski 一起创立了 Zend Technologies,用于 PHP 的商业化应用和性能优化。通过开发 PHP 3 和 Zend Engine,对 PHP 4 和 PHP 5 的推进起到关键作用,并参与管理 PHP 7 的开发。目前是 Google 数据库工程的副总裁。
  • Zeev Suraski,与 Andi Gutmans 一起创建了 PHP 3,开发了 Zend Engine,并推动了 PHP 4 和 PHP 5 的发展。 职业经历:曾为 Zend Technologies 的首席技术官,并且自 2019 年起担任 Strattic 的首席技术官。
  • Zend 这个名字是他们的名字 Zeev 和 Andi 的合成词。是的,没错,每次你输入的 php -v 后面显示 zend 引擎就是这个。

6.2 国内的开发者

6.2.1 惠新宸

6.2.2 韩天峰

6.3 国外的开发者

6.4 关注的 PHP 博主

6.5 关注的活跃PHP项目

6.6 关注的站点

Reference

php
本作品采用《CC 协议》,转载必须注明作者和本文链接
明天我们吃什么 悲哀藏在现实中 Tacks
讨论数量: 9

至今不喜欢注解

1个月前 评论
野生码农在线co腚 1个月前
Tacks (楼主) 1个月前

在模仿Java的道路上越走越偏, 最终将消失在互联网. :joy:

1个月前 评论
Tacks (楼主) 1个月前
tuesdays (作者) 1个月前

极简主义 golang 加各种语法 真实蛋疼的

1个月前 评论
Tacks (楼主) 1个月前
tuesdays 1个月前

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!