美文网首页
PHP学习笔记-PHP8.X的新特性

PHP学习笔记-PHP8.X的新特性

作者: 赵客缦胡缨v吴钩霜雪明 | 来源:发表于2022-01-10 17:00 被阅读0次

随着2020年的PHP开发者峰会结束,8.X将在2020年11月26发布。

PHP 8.0 是 PHP 语言的主要更新。它包含了许多新特性和优化,包括命名参数、联合类型、属性、构造函数属性提升、匹配表达式、nullsafe 操作符、JIT,以及对类型系统、错误处理和一致性的改进。

有别于PHP7,万众瞩目的Just In Time Compilation(即时编译)功能成为了大家期待的重点。

命名参数 Named arguments

PHP 7

htmlspecialchars($string, ENT_COMPAT | ENT_HTML401, 'UTF-8', false);

PHP 8

htmlspecialchars($string, double_encode: false);
  • 只指定必需参数,跳过可选参数。
  • 参数是独立于顺序并且是自描述的。

php8支持命名参数,这样靠前的有默认的参数,就不用必须明确写出,如下php8跳过第二和第三个默认参数,直接指定第四个参数。开发者可以按自己的意愿更改参数顺序,这样的好处是,摆脱了php函数有些不经常用的参数靠前,代码中又必须明确写出才能给后面的参数赋值的困扰。

属性 Attributes

属性,在很多语言中亦称作注解。

PHP 7

class PostsController
{
    /**
     * @Route("/api/posts/{id}", methods={"GET"})
     */
    public function get($id) { /* ... */ }
}

PHP 8

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

不再使用 PHPDoc 注释,现在可以使用 PHP 原生语法的结构化元数据。

构造函数属性提升 Constructor property promotion

PHP 7

class Point {
  public float $x;
  public float $y;
  public float $z;

  public function __construct(
    float $x = 0.0,
    float $y = 0.0,
    float $z = 0.0
  ) {
    $this->x = $x;
    $this->y = $y;
    $this->z = $z;
  }
}

PHP 8

class Point {
  public function __construct(
    public float $x = 0.0,
    public float $y = 0.0,
    public float $z = 0.0,
  ) {}
}
  • 定义和初始化属性可使用更少的样板代码。

联合类型 Union types

PHP 7

class Number {
  /** @var int|float */
  private $number;

  /**
   * @param float|int $number
   */
  public function __construct($number) {
    $this->number = $number;
  }
}

new Number('NaN'); // Ok

PHP 8

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

new Number('NaN'); // TypeError

可使用联合类型声明在运行时验证类型来代替使用 PHPDoc 注释说明。

Match 表达式Match expression

PHP 7

switch (8.0) {
  case '8.0':
    $result = "Oh no!";
    break;
  case 8.0:
    $result = "This is what I expected";
    break;
}
echo $result;
//> Oh no!

PHP 8

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

match 类似于 switch,具有如下特性:

  • match 为表达式,意味着其结果可以存储在变量中或用于返回。
  • match 分支仅支持单行表达式,同时不需要 break; 语句。
  • match 使用严格比较。

实例说明:

PHP7

$result = NULL;

switch ($input) {
    case "true":
        $result = 1;
    break;
    case "false":
        $result = 0;
    break;
    case "null":
        $result = NULL;
    break;
}

PHP8

$result = match($input) {
        "true" => 1,
        "false" => 0,
        "null" => NULL,
};

相比switch, match会直接返回值,可以直接赋值给$result了。

并且,类似switch的多个case一个block一样,match的多个条件也可以写在一起,比如:

$result = match($input) {
    "true", "on" => 1,
    "false", "off" => 0,
    "null", "empty", "NaN" => NULL,
};
需要注意的和switch不太一样的是,以前我们用switch可能会经常遇到这种诡异的问题:

$input = "2 person";
switch ($input) {
    case 2:
        echo "bad";
    break;
}

你会发现,bad竟然被输出了,这是因为switch使用了宽松比较(==)。match就不会有这个问题了, 它使用的是严格比较(===),就是值和类型都要完全相等。

还有就是,当input并不能被match中的所有条件满足的时候,match会抛出一个UnhandledMatchError exception:

$input = "false";
$result = match($input) {
        "true" => 1,
};

会得到:Fatal error: Uncaught UnhandledMatchError: Unhandled match value of type string

这样就不用担心万一match条件没写全导致了不可预知的错误。

另外还是要说明,match是关键字,也就是从PHP8开始它不能出现在namespace或者类名中,如果你的项目中有用match作为类名的: class Match {}

在PHP8开始将会得到语法错误了, 当然,方法名中还是可以用的。

Nullsafe 操作符Nullsafe operator

PHP 7

// PHP 7
$country =  null;

if ($session !== null) {
  $user = $session->user;

  if ($user !== null) {
    $address = $user->getAddress();

    if ($address !== null) {
      $country = $address->country;
    }
  }
}

PHP 8

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

可使用 nullsafe 操作符完成链式调用来代替 null 的验证。当对链中的一个元素求值失败时,整个链的执行将中止,整个链的求值为 null。

更合理的字符串与数值的比较 Saner string to number comparisons

PHP 7

// PHP 7
0 == 'foobar' // true

PHP 8

// PHP 8
0 == 'foobar' // false

当数值与数值字符串比较时,PHP 8 使用数值比较。否则将数值转换为字符串并采用字符串比较。

内置函数的一致错误类型 Consistent type errors for internal functions

PHP 7

// PHP 7
strlen([]); // Warning: strlen() expects parameter 1 to be string, array given

array_chunk([], -1); // Warning: array_chunk(): Size parameter expected to be greater than 0

PHP 8

// PHP 8
strlen([]); // TypeError: strlen(): Argument #1 ($str) must be of type string, array given

array_chunk([], -1); // ValueError: array_chunk(): Argument #2 ($length) must be greater than 0

大部分内置函数在参数验证失败后会抛出 Error 异常。

php8如果参数验证失败,大多数内部函数将引发Error异常。

这个改进对开发者提出了更高的要求,原来的warning错误,会直接升级为error错误。

JIT 编译 Just-In-Time compilation

PHP 8 引入了两个 JIT 编译引擎。Tracing JIT 是其中最有前景的,它在合成基准测试上的性能提高了3倍,在一些特定的长时间运行的应用程序上的性能提高了1.5-2倍。

典型的应用程序性能与 PHP 7.4 相当。

JIT的新特性,则是将PHP代码转化为传统的机器码,而并非通过zend虚拟机来运行,这大大增加了运行速度。

但是缺点是向下不兼容。

# JIT 可以通过php.ini中设置
opcache.jit = on // on 开; off 关

左图是PHP8之前的Opcache流程示意图, 右图是PHP8中的Opcache示意图, 可以看出几个关键点:

  • Opcache会做opcode层面的优化,比如图中的俩条opcode合并为一条
  • PHP8的JIT目前是在Opcache之中提供的
  • JIT在Opcache优化之后的基础上,结合Runtime的信息再次优化,直接生成机器码
  • JIT不是原来Opcache优化的替代,是增强
  • 目前PHP8只支持x86架构的CPU

事实上JIT共用了很多原来Opcache做优化的基础数据结构,比如data flow graph, call graph, SSA等

类型系统和错误处理的改进 Type system and error handling improvements

  • 算术/位操作中更严格的类型检查 RFC
  • 抽象 trait 方法验证 RFC
  • 魔术方法的正确签名 RFC
  • 重分类的引擎警告 RFC
  • 不兼容方法签名的致命错误 RFC
  • @ 操作符不在静默致命错误。
  • 私有方法的继承 RFC
  • 混合类型 RFC
  • 静态返回类型 RFC
  • 内部函数 email_thread 的类型
  • 用于代替 Curl, Gd, Sockets, OpenSSL, XMLWriterXML 扩展资源的封装对象

其他的语法微调和改进 Other syntax tweaks and improvements

  • 允许在参数列表 RFC 和闭包 use 列表 RFC 后尾随逗号
  • 未使用的捕获 RFC
  • 变量语法微调 RFC
  • 命名空间名称视为一个 token RFC
  • Throw 调整为表达式 RFC
  • 允许对象上使用 ::class 语法 RFC

新类、接口、和函数

New Classes, Interfaces, and Functions·

注解语法

通过重复使用现有标记T_SL和T_SR,注解是用“ <<”和“ >>”括起来的特殊格式的文本。

注解可以用该语言应用于许多事物:

  • 函数(包括闭包和短闭包)
  • 类(包括匿名类),接口,特征
  • 类常量
  • 类属性
  • 类方法
  • 功能/方法参数
namespace My\Attributes {
 
    <<PhpAttribute>>
    class SingleArgument {
        public $argumentValue;
 
        public function __construct($argumentValue) {
             $this->argumentValue = $argumentValue;
        }
    }
}
 
namespace {
    <<SingleArgument("Hello World")>>
    class Foo {
    }
 
    $reflectionClass = new \ReflectionClass(Foo::class);
    $attributes = $reflectionClass->getAttributes();
 
    var_dump($attributes[0]->getName());
    var_dump($attributes[0]->getArguments());
    var_dump($attributes[0]->newInstance());
}
 
/**
string(28) "My\Attributes\SingleArgument"
array(1) {
  [0]=>
  string(11) "Hello World"
}
object(My\Attributes\SingleArgument)#1 (1) {
  ["argumentValue"]=>
  string(11) "Hello World"
}
**/

PHP8之前PHP实现注解可以通过php-parser来实现,但现在可以直接通过Reflection 来获取。

/**
* @param Foo $argument
* @see https:/xxxxxxxx/xxxx/xxx.html
*/    
function dummy($Foo) {}
# 现在获取这段注解则可以使用
$ref = new ReflectionFunction("dummy");
var_dump($ref->getAttributes("See")[0]->getName());
var_dump($ref->getAttributes("See")[0]->getArguments());

相关文章

  • PHP学习笔记-PHP8.X的新特性

    随着2020年的PHP开发者峰会结束,8.X将在2020年11月26发布。 PHP 8.0 是 PHP 语言的主要...

  • 学习笔记《php新特性》

    我以前用的最熟的PHP版本是php5.2,对php5.3的新增特性也略有了解,但是之后的就没有系统的学习过,今天发...

  • Modern PHP 笔记(二):良好实践

    系列笔记:Modern PHP 笔记(一):语言特性Modern PHP 笔记(二):良好实践Modern PHP...

  • Modern PHP 笔记(一):语言特性

    系列笔记:Modern PHP 笔记(一):语言特性Modern PHP 笔记(二):良好实践Modern PHP...

  • Modern PHP 笔记(三):部署测试和调优

    系列笔记:Modern PHP 笔记(一):语言特性Modern PHP 笔记(二):良好实践Modern PHP...

  • PHP新特性笔记

    1. 命名空间 使用namespace进行定义,导入时可以使用use 2. 接口 像定义类一样使用 interfa...

  • php5.5 新特性

    php5.5新特性

  • 生成器

    PHP Manual手册对于生成器的概述:PHP Manual Generator PHP Manual手册新特性...

  • php新特性

    php5.6新特性 参考 使用表达式定义常量,使用const定义常量数组 使用 ... 运算符定义变长参数函数 使...

  • PHP新特性

    PHP5.5新特性 字符串直接表达式 直接通过中括号获取字符串中的单个字符。 foreach和list() for...

网友评论

      本文标题:PHP学习笔记-PHP8.X的新特性

      本文链接:https://www.haomeiwen.com/subject/sugmcrtx.html