PHP8新特性

命名参数

PHP 8.0.0 开始引入了命名参数作为现有位置参数的扩展。命名参数允许根据参数名而不是参数位置向函数传参。这使得参数的含义自成体系,参数与顺序无关,并允许任意跳过默认值。
命名参数通过在参数名前加上冒号来传递。允许使用保留关键字作为参数名。参数名必须是一个标识符,不允许动态指定。

示例1:

// 使用顺序传递参数:
array_fill('hello', 'hi', 'hello world'); //hi world

// 使用命名参数:
str_replace(subject:'hello world',search:'hello',replace:'hi');  //hi world

示例2:解包后使用命名参数

function foo($a, $b, $c = 3, $d = 4) {
  return $a + $b + $c + $d;
}

var_dump(foo(...[1, 2], d: 40)); // 46
var_dump(foo(...['b' => 2, 'a' => 1], d: 40)); // 46

var_dump(foo(...[1, 2], b: 20)); // Fatal error。命名参数 $b 覆盖之前的参数

注解(Attributes)

注解功能提供了代码中的声明部分都可以添加结构化、机器可读的元数据的能力, 注解的目标可以是类、方法、函数、参数、属性、类常量。 通过 反射 API 可在运行时获取注解所定义的元数据。 因此注解可以成为直接嵌入代码的配置式语言。

注解语法

注解语法包含以下几部分。 首先,注解声明总是以#[开头,以]结尾来包围。 内部则是一个或以逗号包含的多个注解。 注解的名称可以是非限定、限定、完全限定的名称。 注解的参数是可以选的,以常见的括号()包围。 注解的参数可以是字面值或者常量表达式。 它同时接受位置参数和命名参数两种语法。

通过反射API请求注解实例时,注解的名称会被解析到一个类,注解的参数则传入该类的构造器中。 因此每个注解都需要引入一个类。

示例:

namespace MyExample;

use Attribute;

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

    private $value;

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

使用反射 API 读取注解

反射 API 提供了getAttributes()方法, 类、方法、函数、参数、属性、类常量的反射对象可通过它获取相应的注解。 该方法返回了 ReflectionAttribute实例的数组, 可用于查询注解名称、参数、也可以实例化一个注解。
示例 #1 通过反射 API 读取注解:

#[Attribute]
class MyAttribute
{
    public $value;

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

#[MyAttribute(value: 1234)]
class Thing
{
}

function dumpAttributeData($reflection) {
    $attributes = $reflection->getAttributes();

    foreach ($attributes as $attribute) {
       var_dump($attribute->getName());
       var_dump($attribute->getArguments());
       var_dump($attribute->newInstance());
    }
}

dumpAttributeData(new ReflectionClass(Thing::class));
/*
string(11) "MyAttribute"
array(1) {
  ["value"]=>
  int(1234)
}
object(MyAttribute)#3 (1) {
  ["value"]=>
  int(1234)
}
*/

示例 #2 使用反射 API 读取指定的注解

function dumpMyAttributeData($reflection) {
    $attributes = $reflection->getAttributes(MyAttribute::class);

    foreach ($attributes as $attribute) {
       var_dump($attribute->getName());
       var_dump($attribute->getArguments());
       var_dump($attribute->newInstance());
    }
}

dumpMyAttributeData(new ReflectionClass(Thing::class));

声明注解类

虽然没有严格要求,推荐为每个注解创建一个实际的类。 在这个最简单的例子中,通过use语法从全局命名空间引入#[Attribute]注解所需要全空的类。
示例 #1 简单的 Attribute 类

namespace Example;

use Attribute;

#[Attribute]
class MyAttribute
{
}

构造器属性提升

PHP 8.0.0 起,构造器的参数也可以相应提升为类的属性。 构造器的参数赋值给类属性的行为很普遍,否则无法操作。 而构造器提升的功能则为这种场景提供了便利。

常规写法:

class Point {
    protected int $x;
    protected int $y;

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

上面的例子可以用以下方式重写:

class Point {
    public function __construct(protected int $x, protected int $y = 0) {
    }
}

联合类型

联合类型是PHP8中的一个新特性,它允许一个变量可以拥有多个不同的类型。具体来说,当一个变量的类型是一个联合类型时,它可以是其中任意一个类型。例如:

function foo(string|array $var)
{
    // $var可以是一个字符串或者数组
}

Match 表达式

match 表达式基于值的一致性进行分支计算。 match表达式和 switch 语句类似, 都有一个表达式主体,可以和多个可选项进行比较。 与 switch 不同点是,它会像三元表达式一样求值。 与 switch 另一个不同点,它的比较是严格比较( ===)而不是松散比较(==)。 Match 表达式从 PHP 8.0.0 起可用。
示例 #1 match 的基础用法

$food = 'cake';

$return_value = match ($food) {
    'apple' => 'This food is an apple',
    'bar' => 'This food is a bar',
    'cake' => 'This food is a cake',
}; //注意: match 表达式必须使用分号 ; 结尾。

var_dump($return_value);

以上示例会输出:

string(19) "This food is a cake"

match 表达式跟 switch 语句相似,但是有以下关键区别:
– match 比较分支值,使用了严格比较 (===), 而 switch 语句使用了松散比较。
– match 表达式会返回一个值。
– match 的分支不会像 switch 语句一样, 落空时执行下个 case。
– match 表达式必须彻底列举所有情况。

示例2:

$condition = 5;
$expressionResult = match ($condition) {
    1, 2 => foo(),
    3, 4 => bar(),
    default => baz(),
};
var_dump($expressionResult);die;

function foo()
{
    return 'foo';
}
function bar()
{
    return 'bar';
}
function baz()
{
    return 'baz';
}

以上示例会输出:

string(3) "baz"

Nullsafe 运算符(?->)

自 PHP 8.0.0 起,类属性和方法可以通过 “nullsafe” 操作符访问: ?->。 使用上与原来的->操作符访问类的属性和方法是一致的,特别之处是当对象引用解析为null时不抛出异常,而是返回null。 并且如果是链式调用中的一部分,剩余链条会直接跳过。
此操作的结果,类似于在每次访问前使用is_null()函数判断方法和属性是否存在,但更加简洁。
示例:

$result = $repository?->getUser(5)?->name;

等价于以下代码:

if (is_null($repository)) {
    $result = null;
} else {
    $user = $repository->getUser(5);
    if (is_null($user)) {
        $result = null;
    } else {
        $result = $user->name;
    }
}

任意数量的函数参数都可以用一个可变参数替换

例如允许编写下面的代码:

class A {
     public function method(int $many, string $parameters, $here) {}
}
class B extends A {
     public function method(...$everything) {}
}

str_contains

确定字符串是否包含指定子串。区分大小写。
示例:

$string = 'The lazy fox jumped over the fence';

if (str_contains($string, 'lazy')) {
    echo "The string 'lazy' was found in the stringn";
}

if (str_contains($string, 'Lazy')) {
    echo 'The string "Lazy" was found in the string';
} else {
    echo '"Lazy" was not found because the case does not match';
}

以上示例会输出:

The string 'lazy' was found in the string
"Lazy" was not found because the case does not match

str_starts_with

检查字符串是否以指定子串开头。区分大小写。

示例:

$string = 'The lazy fox jumped over the fence';

if (str_starts_with($string, 'The')) {
    echo "The string starts with 'The'n";
}

if (str_starts_with($string, 'the')) {
    echo 'The string starts with "the"';
} else {
    echo '"the" was not found because the case does not match';
}

以上示例会输出:

The string starts with 'The'
"the" was not found because the case does not match

str_ends_with

检查字符串是否以指定子串结尾。区分大小写。

$string = 'The lazy fox jumped over the fence';

if (str_ends_with($string, 'fence')) {
    echo "The string ends with 'fence'n";
}

if (str_ends_with($string, 'Fence')) {
    echo 'The string ends with "Fence"';
} else {
    echo '"Fence" was not found because the case does not match';
}

MurmurHash3

MurmurHash是一种经过广泛测试且速度很快的非加密哈希函数。MurmurHash3可以产生32位或128位哈希。
MurMurHash3 128 位版本的速度是 MD5 的十倍。MurMurHash3 生成 32 位哈希的用时比生成 128 位哈希的用时要长。原因在于生成 128 位哈希的实现受益于现代处理器的特性。32 位哈希值发生碰撞的可能性就比 128 位的要高得多,当数据量达到十万时,就很有可能发生碰撞。

PHP8.1新增对MurmurHash3(支持流)的支持。有以下形式提供:
murmur3a, 32-bit hash
murmur3c, 128-bit hash for x86
murmur3f, 128-bit hash for x64
hash 初始状态可以通过键为 seed 的 options 数组传递,例如:

$data = 'hello';
$h = hash("murmur3f", $data, options: ["seed" => 42]);
var_dump($h);

seed 的有效值范围为 0 到系统定义的 UINT_MAX,通常是 4294967295 。

PHP7性特性

http://www.884358.com/php7-new-feature/

发表评论

邮箱地址不会被公开。 必填项已用*标注