php7.4.x~php8.0.x 新特性

PHP在线运行代码

PHP 核心中的新特性

命名参数

新增 命名参数 的功能。

// array_fill(int $start_index, int $count, mixed $value): array

// 使用顺序传递参数:
array_fill(0, 100, 50);

// 使用命名参数:
array_fill(start_index: 0, count: 100, value: 50);

// 参数顺序不同的示例(同上例)
array_fill(value: 50, count: 100, start_index: 0);

注解

新增注解的功能。

语法:注解声明总是以 #[ 开头,以 ] 结尾来包围。 内部则是一个或以逗号包含的多个注解。
注解是一种在类、属性、方法等声明上方添加元数据的方式,可以在运行时通过反射 API 读取和处理。

// a.php
namespace MyExample;

use Attribute;

#[Attribute]
class MyAttribute
{
	const VALUE = 'value';

	private $value;

	public function __construct($value = null)
	{
		$this->value = $value;
	}
}


// b.php

namespace Another;

use MyExample\MyAttribute;

#[MyAttribute]
#[\MyExample\MyAttribute]
#[MyAttribute(1234)]
#[MyAttribute(value: 1234)]
#[MyAttribute(MyAttribute::VALUE)]
#[MyAttribute(array("key" => "value"))]
#[MyAttribute(100 + 200)]
class Thing
{
}

#[MyAttribute(1234), MyAttribute(5678)]
class AnotherThing
{
}
// 读取注解的示例:

#[\Attribute(\Attribute::TARGET_CLASS | \Attribute::TARGET_METHOD | \Attribute::TARGET_PROPERTY)]
class MyAnnotation {
    public $value;

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

#[MyAnnotation('Class Annotation')]
class MyClass {
    #[MyAnnotation('Property Annotation')]
    public $property;

    #[MyAnnotation('Method Annotation')]
    public function myMethod() {
        // 方法体
    }
}

$reflectionClass = new ReflectionClass(MyClass::class);

// 获取类上的注解
$classAttributes = $reflectionClass->getAttributes(MyAnnotation::class);
foreach ($classAttributes as $attribute) {
    /** @var MyAnnotation $instance */
    $instance = $attribute->newInstance();
    echo "Class Annotation: " . $instance->value . PHP_EOL;
}

// 获取属性上的注解
$property = $reflectionClass->getProperty('property');
$propertyAttributes = $property->getAttributes(MyAnnotation::class);
foreach ($propertyAttributes as $attribute) {
    /** @var MyAnnotation $instance */
    $instance = $attribute->newInstance();
    echo "Property Annotation: " . $instance->value . PHP_EOL;
}

// 获取方法上的注解
$method = $reflectionClass->getMethod('myMethod');
$methodAttributes = $method->getAttributes(MyAnnotation::class);
foreach ($methodAttributes as $attribute) {
    /** @var MyAnnotation $instance */
    $instance = $attribute->newInstance();
    echo "Method Annotation: " . $instance->value . PHP_EOL;
}

构造器属性提升

新增在构造函数中声明类的属性的支持。

// 使用构造器参数
class Point {
	protected int $x;
	protected int $y;

	public function __construct(int $x, int $y = 0) {
		$this->x = $x;
		$this->y = $y;
	}
}

// **使用构造器属性提升**
class Point2 {
	public function __construct(protected int $x, protected int $y = 0) {
	}

	public function getX() {
        return $this->x;
    }
}

// 两个参数都传入
$p1 = new Point2(1, 5);
// 仅传入必填的参数。 $y 会默认取值 0。
$p2 = new Point2(2);
// 使用命名参数(PHP 8.0 起):
$p3 = new Point2(y: 5, x: 3);

var_dump($p1->getX());
var_dump($p2->getX());
var_dump($p3->getX());

当构造器参数带修饰符时,PHP 会同时把它当作对象属性和构造器参数, 并赋值到属性。 构造器可以是空的,或者包含其他语句。

并非所有参数都需要提升。可以混合提升或不提升参数作为属性,也不需要按顺序。 提升后的参数不影响构造器内代码调用。

联合类型

新增 联合类型。

class A {}

function f(A|string $c) {
	var_dump($c);
}
f(new A);	// object(A)#1 (0) {}
f('a');		// a

null 类型语法糖,单个基本类型声明可以通过在类型前添加问号(?)来标记可为 null,?T 和 T|null 是相同的。

// 使参数可以为 null 的旧方式

class A {}

function f(A $c = null) {
	var_dump($c);
}

f(new A);	// object(A)#1 (0) {}
f(null);	// null
class A {}

function f(?A $c) {
	var_dump($c);
}
f(new A);	// object(A)#1 (0) {}
f(null);	// null

match 表达式

新增 match 表达式。

match表达式和 switch 语句类似, 都有一个表达式主体,可以和多个可选项进行比较。 与 switch 不同点是,它会像三元表达式一样求值。 与 switch 另一个不同点,它的比较是严格比较( =)而不是松散比较()。

$food = 'cake';

$return_value = match ($food) {
	'apple' => 'This food is an apple',
	'bar' => 'This food is a bar',
	'cake' => 'This food is a cake',
};

var_dump($return_value);

Nullsafe 运算符

新增 Nullsafe 运算符(?->)。

对象引用解析(dereference)为 null 时不抛出异常,而是返回 null。 并且如果是链式调用中的一部分,剩余链条会直接跳过。

$repository = null;

// Nullsafe 运算符
$result = $repository?->getUser(5)?->name;
var_dump($result);

// 上边代码等价于以下代码
if (is_null($repository)) {
	$result = null;
} else {
	$user = $repository->getUser(5);
	if (is_null($user)) {
		$result = null;
	} else {
		$result = $user->name;
	}
}

其他新特性

  • 新增 WeakMap 类。

WeakMap 是将对象作为 key 来访问的 map(或者说字典), WeakMap 中的对象 key 不影响对象的引用计数。

class A {
	public function __destruct() {
		echo "A!\n";
	}
}

$wm = new WeakMap();

$o = new stdClass;

$wm[$o] = new A;

var_dump(count($wm));
unset($o);
var_dump(count($wm));
  • 新增 ValueError 类。
    当参数类型正确但是值不正确的时候会抛出 ValueError。

  • 现在,只要类型兼容,任意数量的函数参数都可以用一个可变参数替换。例如允许编写下面的代码:

class A {
	public function method(int $many, string $parameters, $here) {}
}
class B extends A {
	public function method(...$everything) {}
}
  • static(“后期静态绑定”中)可以作为返回类型:
class Test {
	public function create(): static {
		return new static();
	}
}
  • 现在可以通过 $object::class 获取类名,返回的结果和 get_class($object) 一致。
class A {
	public function method(int $many, string $parameters, $here) {}
}
$a = new A();
var_dump($a::class);
var_dump(get_class($a));
  • new、instanceof 可用于任何表达式,用法为 new (expression)(...$args) 和 $obj instanceof (expression)。

    ?

  • 添加对一些变量语法一致性的修复,例如现在能够编写 Foo::BAR::$baz。

  • 添加 Stringable interface,当类定义 __toString() 方法后会自动实现该接口。

  • Trait 可以定义私有抽象方法(abstract private method)。类必须实现 trait 定义的该方法。

  • 可作为表达式使用 throw。使得可以编写以下用法:

$fn = fn() => throw new Exception('Exception in arrow function');
$user = $session->user ?? throw new Exception('Must have user');
  • 参数列表中的末尾逗号为可选。
function functionWithLongSignature(
	Type1 $parameter1,
	Type2 $parameter2, // <-- 这个逗号也被允许了
) {
  • 现在允许 catch (Exception) exception 而无需捕获到变量中。
try {
	throw new \Exception('AAA!');
} catch (\Exception) {
}
  • 支持 mixed 类型。
    mixed 类型接受每个值。等同于联合类型 object|resource|array|string|float|int|bool|null。自 PHP 8.0.0 起可用。
    在类型理论中,mixed 是顶级类型。这意味着其它所有类型都是它的子类型。

  • 父类中声明的私有方法不在对子类中的方法执行任何继承规则(final private 构造方法除外)。下列示例说明删除了那些限制:

class ParentClass {
	private function method1() {}
	private function method2() {}
	private static function method3() {}
	// private final function method4() {}
}
class ChildClass extends ParentClass {
	// 现在允许以下所有内容,即使修饰符与父类中的私有方法不同。
	public function method1() {}
	public static function method2() {}
	public function method3() {}
	public function method4() {}
}
  • 新增 get_resource_id() 函数,返回值跟 (int) $resource 相同。其在更清晰的 API 下提供了相同的功能。

  • 新增 InternalIterator 类。

标准库

  • 新增 str_contains()、str_starts_with() 和 str_ends_with(),分别检查 haystack 是否包含 needle 或以 needle 开头/结尾。

  • 新增 fdiv() 在 IEEE 754 语义下执行浮点除法。认为除以零已经明确定义,将返回 Inf、-Inf 或 NaN。

$b = fdiv(10, 0);
echo $b; // INF
  • 新增 get_debug_type() 返回对错误消息有用的类型。与 gettype() 不同的是,它使用规范的类型名称,为对象返回类名,为资源表示资源类型。

  • printf() 和相关函数现在支持 %h 和 %H 格式说明符。它们与 %g 和 %G 相同,但始终使用 "." 作为小数点分隔符,而不是通过 LC_NUMERIC 区域确定。

  • 现在,printf() 和相关函数支持使用 "*" 作为宽度或精度,此时宽度/精度将作为参数传递给 printf。这也允许在 %g、%G、%h 和 %H 中使用精度 -1。例如,以下代码可用于重现 PHP 的默认浮点数格式化:

printf("%.*H", (int) ini_get("precision"), $float);
printf("%.*H", (int) ini_get("serialize_precision"), $float);
  • 现在,proc_open() 支持伪终端(PTY)描述符。以下将 stdin、stdout 和 stderr 附加到同一个 PTY.
$proc = proc_open($command, [['pty'], ['pty'], ['pty']], $pipes);
  • proc_open() 现在支持套接字对描述符。以下将独立的套接字对附加到 stdin、stdout 和 stderr.
$proc = proc_open($command, [['socket'], ['socket'], ['socket']], $pipes);
  • 排序函数现在已稳定,这意味着相等的元素比较将保留其原始顺序。

  • array_diff() 和 array_intersect() 及其变体现在可以接受单个数组作为参数。

// 如果 $excludes 为空也可以:
array_diff($array, ...$excludes);

// 如果 $arrays 仅包含单个数组也可以:
array_intersect(...$arrays);
var_dump(array_diff(['a','b']));
  • ob_implicit_flush() 的 flag 参数已经从接受 int 变更为接受 bool。

DOM

Filter

Enchant

FPM

Hash

LDAP

OPcache

OpenSSL

正则表达式(兼容 Perl)

反射

SQLite3

Tokenizer

Zip


PHP 8.0 废弃的功能

PHP 核心中废弃的功能

  • 如果带有默认值的参数后面跟着一个必要的参数,那么默认值就会无效。这在 PHP 8.0.0 中已被废弃,通常可以通过删除默认值,不影响现有功能:
function test($a = [], $b) {} // 之前
function test($a, $b) {}      // 之后

PHP8.2:
Deprecated: Optional parameter $a declared before required parameter $b is implicitly treated as a required parameter

标准库

  • 排序比较函数现在返回 true 或者 false 将会引发弃用警告,应替换为返回小于、等于或者大于零的 int 值。
// 替换
usort($array, fn($a, $b) => $a > $b);
// 为
usort($array, fn($a, $b) => $a <=> $b);

Enchant

LibXML

PGSQL/PDO PGSQL

Zip

反射


https://www.php.net/manual/zh/migration80.new-features.php

https://www.php.net/manual/zh/migration80.deprecated.php


PHP在线运行代码

posted on 2024-12-05 17:56  ercom  阅读(12)  评论(0编辑  收藏  举报