PHP8新特性

命名参数

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

示例1:

  1. // 使用顺序传递参数:
  2. array_fill('hello', 'hi', 'hello world'); //hi world
  3. // 使用命名参数:
  4. str_replace(subject:'hello world',search:'hello',replace:'hi'); //hi world

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

  1. function foo($a, $b, $c = 3, $d = 4) {
  2. return $a + $b + $c + $d;
  3. }
  4. var_dump(foo(...[1, 2], d: 40)); // 46
  5. var_dump(foo(...['b' => 2, 'a' => 1], d: 40)); // 46
  6. var_dump(foo(...[1, 2], b: 20)); // Fatal error。命名参数 $b 覆盖之前的参数

注解(Attributes)

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

注解语法

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

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

示例:

  1. namespace MyExample;
  2. use Attribute;
  3. #[Attribute]
  4. class MyAttribute
  5. {
  6. const VALUE = 'value';
  7. private $value;
  8. public function __construct($value = null)
  9. {
  10. $this->value = $value;
  11. }
  12. }

使用反射 API 读取注解

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

  1. #[Attribute]
  2. class MyAttribute
  3. {
  4. public $value;
  5. public function __construct($value)
  6. {
  7. $this->value = $value;
  8. }
  9. }
  10. #[MyAttribute(value: 1234)]
  11. class Thing
  12. {
  13. }
  14. function dumpAttributeData($reflection) {
  15. $attributes = $reflection->getAttributes();
  16. foreach ($attributes as $attribute) {
  17. var_dump($attribute->getName());
  18. var_dump($attribute->getArguments());
  19. var_dump($attribute->newInstance());
  20. }
  21. }
  22. dumpAttributeData(new ReflectionClass(Thing::class));
  23. /*
  24. string(11) "MyAttribute"
  25. array(1) {
  26. ["value"]=>
  27. int(1234)
  28. }
  29. object(MyAttribute)#3 (1) {
  30. ["value"]=>
  31. int(1234)
  32. }
  33. */

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

  1. function dumpMyAttributeData($reflection) {
  2. $attributes = $reflection->getAttributes(MyAttribute::class);
  3. foreach ($attributes as $attribute) {
  4. var_dump($attribute->getName());
  5. var_dump($attribute->getArguments());
  6. var_dump($attribute->newInstance());
  7. }
  8. }
  9. dumpMyAttributeData(new ReflectionClass(Thing::class));

声明注解类

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

  1. namespace Example;
  2. use Attribute;
  3. #[Attribute]
  4. class MyAttribute
  5. {
  6. }

构造器属性提升

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

常规写法:

  1. class Point {
  2. protected int $x;
  3. protected int $y;
  4. public function __construct(int $x, int $y = 0) {
  5. $this->x = $x;
  6. $this->y = $y;
  7. }
  8. }

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

  1. class Point {
  2. public function __construct(protected int $x, protected int $y = 0) {
  3. }
  4. }

联合类型

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

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

Match 表达式

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

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

以上示例会输出:

  1. string(19) "This food is a cake"

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

示例2:

  1. $condition = 5;
  2. $expressionResult = match ($condition) {
  3. 1, 2 => foo(),
  4. 3, 4 => bar(),
  5. default => baz(),
  6. };
  7. var_dump($expressionResult);die;
  8. function foo()
  9. {
  10. return 'foo';
  11. }
  12. function bar()
  13. {
  14. return 'bar';
  15. }
  16. function baz()
  17. {
  18. return 'baz';
  19. }

以上示例会输出:

  1. string(3) "baz"

Nullsafe 运算符(?->)

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

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

等价于以下代码:

  1. if (is_null($repository)) {
  2. $result = null;
  3. } else {
  4. $user = $repository->getUser(5);
  5. if (is_null($user)) {
  6. $result = null;
  7. } else {
  8. $result = $user->name;
  9. }
  10. }

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

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

  1. class A {
  2. public function method(int $many, string $parameters, $here) {}
  3. }
  4. class B extends A {
  5. public function method(...$everything) {}
  6. }

str_contains

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

  1. $string = 'The lazy fox jumped over the fence';
  2. if (str_contains($string, 'lazy')) {
  3. echo "The string 'lazy' was found in the stringn";
  4. }
  5. if (str_contains($string, 'Lazy')) {
  6. echo 'The string "Lazy" was found in the string';
  7. } else {
  8. echo '"Lazy" was not found because the case does not match';
  9. }

以上示例会输出:

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

str_starts_with

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

示例:

  1. $string = 'The lazy fox jumped over the fence';
  2. if (str_starts_with($string, 'The')) {
  3. echo "The string starts with 'The'n";
  4. }
  5. if (str_starts_with($string, 'the')) {
  6. echo 'The string starts with "the"';
  7. } else {
  8. echo '"the" was not found because the case does not match';
  9. }

以上示例会输出:

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

str_ends_with

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

  1. $string = 'The lazy fox jumped over the fence';
  2. if (str_ends_with($string, 'fence')) {
  3. echo "The string ends with 'fence'n";
  4. }
  5. if (str_ends_with($string, 'Fence')) {
  6. echo 'The string ends with "Fence"';
  7. } else {
  8. echo '"Fence" was not found because the case does not match';
  9. }

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 数组传递,例如:

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

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

PHP7性特性

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

发表评论

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

发表评论前,请滑动滚动条解锁
三十岁