PHP8 系列新特性

March 16, 2023 1:57 PM

PHP 8.0

命名参数

  • 仅仅指定必填参数,跳过可选参数
  • 最大的好处是传入参数的顺序是和定义无关的
htmlspecialchars($string, double_encode: false);

注解

class PostController
{
    #[Route("/api/posts/{id}", methods: ["GET"])]
    public function get($id)
    {
    }
}

构造器属性提升

class Point {
    public function __construct(
        public float $x = 0.0;
        public float $y = 0.1;
        public float $z = 0.2;
    ) {}
}

联合类型

class Number {
    public function __constract(
        private int|float $number
    ){}
}

new Number("NaN"); //TypeError

Match 表达式

Match 使用的是严格比较

echo match(8.0) {
    '8.0' => "Oh no!',
    8.0 => "This is what i expected',
}

// This is watch i expected

Nullsafe 运算符

现在可以用新的 nullsafe 运算符链式调用,而不需要条件检查 null。 如果链条中的一个元素失败了,整个链条会中止并认定为 Null

$country = $session?->user?->getAddress()?->country;

字符串与数字的比较更符合逻辑

//PHP 7
0 == 'foobar'; //true
o == 'foobar'; //false

新的 mixed 类型

mixed 本身是以下类型之一:

  • array
  • bool
  • callable
  • int
  • float
  • null
  • object
  • resource
  • string 可用于参数、属性类型、返回类型

由于mixed已经包含了null,因此不允许将其设置为nullable

// Fatal error: Mixed types cannot be nullable, null is already part of the mixed type. 
function bar(): ?mixed {} 

新的字符串函数

str_contains('string with lots of words', 'words');
str_starts_with('haystack', 'hay'); // true
str_ends_with('haystack', 'stack'); // true 

traits 中的抽象方法改进

Traits 可以指定抽象方法,这些方法必须由使用它们的类实现。在PHP8,必须保持一致的方法定义,包括参数类型和返回类型。

PHP 8.1 新特性

枚举

enum Status
{
    case Draft;
    
    case Published;
    
    case Archived;
}

只读属性

读属性不能在初始化后更改,即在为它们分配值后。它们可以用于对值对象和数据传输对象建模

class BlogData
{
    public readonly Status $status;
    
    public function __construct(Status $status)
    {
        $this->status = $status;
    }
}

新的初始化器

对象现在可以用作默认参数值、静态变量和全局常量,以及属性参数。 这有效地使使用 嵌套属性 成为可能

class Service
{
    private Logger $logger;
    
    public function __constract(
        Logger $logger = new NullLogger()
    ) {
        $this->logger = $logger;
    }
}

Never 返回类型

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

function redirect(string $uri): never {
    header('Location: ' . $uri);
    exit();
}
 
function redirectToLoginPage(): never {
    redirect('/login');
    echo 'Hello'; // <- dead code detected by static analysis 
}

Final 类常量

可以声明 final 类常量,以禁止它们在子类中被重写。

class Foo
{
    final public const XX = "foo";
}

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

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

PHP 以前支持通过扩展运算符在数组内部解包,但前提是数组具有整数键。现在也可以使用字符串键解包数组

$arrayA = ['a' => 1];
$arrayB = ['b' => 2];

$result = ['a' => 0, ...$arrayA, ...$arrayB];

// ['a' => 1, 'b' => 2]

PHP 8.2 新特性

只读类

readonly class BlogData
{
    public string $title;

    public Status $status;

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

PHP < 8.2 :

class BlogData
{
    public readonly string $title;

    public readonly Status $status;

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

析取范式 (DNF)类型

PHP < 8.2

class Foo {
    public function bar(mixed $entity) {
        if ((($entity instanceof A) && ($entity instanceof B)) || ($entity === null)) {
            return $entity;
        }

        throw new Exception('Invalid entity');
    }
}

PHP 8.2.*

class Foo {
    public function bar((A&B)|null $entity) {
        return $entity;
    }
}

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

class Falsy
{
    public function alwaysFalse(): false { /* ... */ *}

    public function alwaysTrue(): true { /* ... */ *}

    public function alwaysNull(): null { /* ... */ *}
}

Traits 中的常量

trait Foo
{
    public const CONSTANT = 1;
}

class Bar
{
    use Foo;
}

var_dump(Bar::CONSTANT); // 1
var_dump(Foo::CONSTANT); // Error