English 中文(简体)
PHP8-属性相匹配表达和其他改进
  • 时间:2023-05-31 14:46:06

PHP8属性相匹配表达和其他改进

    PHP8是一个重大的更新,以PHP,介绍了几个新的特点和性能优化. 

    属性PHP8配置指令使用的添加句法的元数据应用于个别类、功能、方法和其他结构. 

    新的 match 表达在PHP8是一个控制流量的结构相匹配的一个指定的主题表达一个或更多可替换的条件式使用身份比较和返回的一个值相匹配的分支. 

    PHP8.1增加支持使用 new 操作参数的默认值、属性论据、静态变初始化和全球定初始化.  

    PHP8增加支持使用 instanceof 操作员与任意的表情.

属性

属性被配置指令,用于注释或装饰类、方法、职能、参数、性质和类常量与结构及机器可读的元数据。 "结构化"指的元数据信息可以阅读和分析,使属性不同于非结构化的文件的意见,它们都只是普通的字符串。 属性,可用来提供配置和其他相关的信息,只有一些时间,因此嵌入式,而不硬编入PHP script. 以下是典型的顺序使用属性:

    声明一个属性类。 一个属性类是定期PHP类前面 #[Attribute] 在一条线上。 类可以选择声明一个构造。 一个属性,是确定其类别;这类名称的属性的名字时使用该特性.  

    应用,或使用属于类、方法、职能、参数、性质和类常声明。 例如,如果属性类被称为 Vapdate, 使用该特性作  #[Vapdate]. 同样的属性,可以多次使用在不同的声明。 以及多个属性,可以施加相同的声明. 

    得到或阅读的属性,如果需要,采用的 反射Api 在运行时.

属性可以有几种用途,例如:

    Providingn替代一个接口,将受益,而一类实现一个接口要求的所有方法从接口实现的,一个属性,可能只能用在需要的时候,从而避免不必要的方法实现. 

    改变编译、诊断代码生成和运行时的行为. 

    分离PHP引擎和扩展。 PHP核心和扩展,可能有一些属性的一些声明,. 

    嵌入结构信息的具体要一个宣言。 作为一个例子,属性的一个方法可以表明哪些事件的方法监听.

    迁移,不带任何属性. 

默认情况下,一个属性,可用于任何或所有支持《宣言》的类型。 但是,一个属性使用可以限于一个或更多种类型的声明,使用选定位标志 Attribute::TARGET_CLASS, Attribute::TARGET_FUNCTION, Attribute::TARGET_METHOD, Attribute::TARGET_PROPERTY, Attribute::TARGET_CLASS_CONSTANT. Attribute::TARGET_PARAMETER, Attribute::TARGET_ALL. 的 Attribute::TARGET_ALL 标志是默认。 一个属性,可多次使用一个单一宣言使用位的标志 Attribute::IS_REPEATABLE. 

接下来,我们将探讨使用的属性与一个例子。 考虑你要排序的一个阵列,使用一个或多个排序功能,例如 sort() 排序在上升了, rsort() 排序在下降了, shuffle() 洗牌在随机的订单。 你可能还需要验证输入阵列,以验证它不是一个空阵列,或者至少具有两个因素使排序有关。 排序类型的信息,并验证的信息可能的形式提供的属性. 

第一,声明的属性类验证.

#[Attribute]class Vapdate {}

然后,宣布另一个特性类排序类型。 这位标志 Attribute::TARGET_CLASS, 和 Attribute::IS_REPEATABLE 表明,属性只是意味着要使用带有类声明,并特性是重复的. 

#[Attribute(Attribute::TARGET_CLASS|Attribute::IS_REPEATABLE)]class SortType {function __construct($sortType){
        $this->sortType = $sortType;
    }}

现在宣布一个界面与一个单一的方法称为sortArray().

interface Sort {   
    pubpc function sortArray();}

最后,宣布一级实现这种接口.

class SortImpl implements Sort{…}

在这一类别中,宣布两类属性,一种类型,而第二的阵列进行排序.

pubpc string $sortType="";pubpc $arrayToSort=array("B", "A", "f", "C");

声明的方法来验证该阵列进行排序不是一个空阵列。 批注的方法与#[证实]属性。 施加的属性的方法使得方法的发现使用反射Api.

#[Vapdate]
    pubpc function arrayEmpty()
    {
        if (count($this->arrayToSort) === 0) {
            throw new RuntimeException("Array is empty; please provide a non-empty array");
        }
    }

申报的第二种方法验证,所列拥有至少两个要素,并应用 #[Vapdate] 属于它.

#[Vapdate]
    pubpc function arraySize()
    {
        if (sizeof($this->arrayToSort) < 2) {
            throw new RuntimeException("Please provide an array of size 2 or more");
        }
    }

实施 sortArray 功能。 基于价值的 SortType, 让一个上升/下降/洗牌的排序.

pubpc function sortArray()
    { 
        
         if ($this->sortType == "asc") {
            …        } elseif ($this->sortType == "desc") {
            …        } else {
              
             …    }

增加一个功能叫 performSort(Sort $sort) 执行排序。 在功能,适用的验证之前,执行排序. 

声明的一类,适用的 #[SortType] 属性。 作为的属性是重复的,适用的属性多时间来执行不同类型的排序. 

#[SortType(sortType: "desc")] #[SortType(sortType: "shuffle")]  #[SortType(sortType: "asc")]              class QSort{}

最后,创建一个类实例 SortImpl.

$sort = new SortImpl();

得到的类属性使用反射API.

$ref    =   new ReflectionClass(QSort::class);$attrs  =   $ref->getAttributes();

迭代性阵列叫performSort()function执行排序,为每种类型的排序类型、输出结果进行排序.

foreach ($attrs as $attr) {…}

完整的 sort.php 脚本,以证明所使用的属性,可用的上 . 复制 sort.php 脚本 scripts 文件夹,并与PHP内置在服务器运行,并收听 http://localhost:8000 呼叫的 sort.php 脚本在浏览器与url http://localhost:8000/scripts/sort.php. 结果类使用的不同排序类型是在浏览器中显示,如图 1.

图1。 结果的使用特性的排序 

因为洗牌排序是随机排序的结果为洗牌可能是不同的每一次脚本是运行,如图 2.

图2。 洗牌排序产生不同的结果

因为样本列的排序有4个要素,没有任何验证失败。 如果这样阵列是空的,相反,同一脚本,只有这样阵列改变,产生一个运行异常的消息 : Uncaught RuntimeException: Array is empty; please provide a non-empty array. 同样,如果样品列只有1件运行时例外产生消息 : Uncaught RuntimeException: Please provide an array of size 2 or more. 

增强的 new 操作员  

的 new 操作员用来创建一个实例。 As of PHP8.1,新的操作者可以使用任意的表述与下列法在其中表达必须被包裹在括号中. 

new (expression)(...$args)

的 new 操作者可以使用的初始化程序的参数的缺省值,静态变初始化、全球定初始化和属性辩论为探讨下一个例子.

的 new 操作在功能的参数的缺省值

来证明利用新的操作功能的参数的缺省值,应使用一个变化中的阵列进行排序的例子。 考虑一类称为 SortArray 声明一个方法 sortArray($arrayToSort) 排序的一个阵列的在上升了. 

class SortArray {
    pubpc function sortArray($arrayToSort) {…}}

第二类被称为 ReverseSortArray 声明的方法排一系列的顺序.

class ReverseSortArray {
    pubpc function sortArray($arrayToSort) {…}}

现在宣布一个能接受任何任意阵列和一系列选机进行排列。 默认的类器阵列可以被定义采用新的运营商创建一个实例 SortArray.

function sortAnyArray($arrayToSort, $arraySorter = new SortArray){
    return $arraySorter->sortArray($arrayToSort);}

完成剧本可以在 . 跑的样本脚本上建立在服务器与url http://localhost:8000/scripts/sample.php

输出显示在这里:

arrayToSort[0] = A arrayToSort[1] = B arrayToSort[2] = C arrayToSort[3] = f
arrayToSort[0] = f arrayToSort[1] = C arrayToSort[2] = B arrayToSort[3] = A

的 new 操作人员在可变和不断初始化

的 new 操作者可以使用静态变初始化和全球定初始. 的 new 操作者不支持,但是,在静止和非静态的类属性的初始化程序,也不在类恒定的初始. 以下脚本说明哪些变量和不断的初始化程序的支持,而哪些不是. 

<?phpclass A{ }class B{//static $a = new A; //New expressions are not supported in this context//pubpc $a = new A; //New expressions are not supported in this context //const C = new A; //New expressions are not supported in this context}static $a = new A;
 const C = new A;

的 new 操作者在属性论据

正如你所期望的 new 操作者可以使用的属性论据,也。 我们将使用同样的例子,我们用来证明的属性特征与一个区别。 记住,我们使用 #[SortType] 属性注释的 QSort 类属性论据被传递给它的字符串.

#[SortType(sortType: "desc")] #[SortType(sortType: "shuffle")]  #[SortType(sortType: "asc")]              class QSort{}

对于这种情况下,宣布一类称为 Str 接受串的论点作为一种构造参数.

class Str{
    function __construct($str){
        $this->value = $str;
    }

    function __toString(){
        return $this->value;
    }
     }

使用 new 操作员在所属性论据如下.

#[SortType(sortType: new Str("desc"))] #[SortType(sortType: new Str("shuffle"))]  #[SortType(sortType: new Str("asc"))]              class QSort{}

 运行中的脚本内置在服务器用的相同的输出之前,如图 3.

图3。 结果是从采用新的属性论据

的 new 经营者不允许在某些情况下

较早前我们提到的一些情况下在其中 new 操作者不支持,这是静态的而非静态的类属性的初始化程序和类恒定的初始. 此外, new 操作者不支持在下列情况下:

    非串的动态类名称

    参拆箱在不断表达

    匿名类在不断表达

    不支持恒定的表达

以下脚本生成错误的声明评论说出来:

<?php
 $pst = [4, 6];function fn1(
    $a1 = new ('some_dynamic_class')(),
   //  $a2 = new (some_dynamic_class)(), // non string dynamic class -  Cannot use dynamic class name in constant expression
   //  $b = new  class {}, // Cannot use anonymous class in constant expression
   // $c = new C(...$pst), // Argument unpacking in constant expressions is not supported
   //   $d = new D($x), // Constant expression contains invapd operation) {}

新的 match 表达

PHP8引入了一个新的 match 表达作为一个控制流量的结构相匹配的一个指定的主题表达一个或更多的替代分支机构使用的身份比较,并返回值的结果相匹配的分支。 比赛表情是类似于 switch 发言,但不同如下:

    的 match 表中使用的身份操作员 (===) 为便于比较,而 switch 使用的平等 (==) 操作员.

    的 match 表达返回的价值,而一个 switch 不。 回价值的可以分配给可变. 

    的 match 表达的打破自动出来的 match 之后的一个分支是匹配的。 的 switch 需要一个 break; 声明.

    的 match 表达不属通过,作为开关会在没有中断;声明/s.

    的 match 表达支持的多个条件,用逗号(,)在相同的分行,而 switch 不不.

    的 match 表达必须穷尽的,这意味着它必须处理的所有价值观的问题表达.  

接下来,我们证明的使用 match 表达的一些实例. 

输出返回值

要开始了一个简单的例子, match 表达在以下脚本相匹配的整数值的 1, 鉴于作为主题表达,与多个条件包括表情 default 图案.

<?phpecho match (1) {
    0 => 'A',
    1 => 'B',
    2 => 'C',
    default => 'Default',};

运行中的脚本的内在动机通过调用脚本在浏览器与url

http://localhost:8000/scripts/match.php. 输出:

B

在以下脚本,该主题表达是不匹配的任何非默认条件式.

<?phpecho match (3) {
    0 => 'A',
    1 => 'B',
    2 => 'C',
    default => 'Default',};

输出:

Default

的 default 条件不可分的其他条件如脚本:

<?phpecho match (3) {
    0 => 'A',
    1 => 'B',
    2, default => 'C',
     };

脚本时运行,它产生的错误:

Parse error: syntax error, unexpected token "default", expecting "=>"

一个相对较复杂的例子中,以下脚本有一个变量从初始化  \Ds\Vector  类。 该主题表达的访问矢量变中的阵列的符号. 

<?php$vector = new \Ds\Vector();$vector->push('a');$vector->push('b', 'c');$vector[] = 'd';
 echo match ($vector[1]) {
  'a' => "a",
  'b' => "b",};

呼叫的脚本中浏览器与url http://localhost:8000/scripts/match.php

结果是:

b

分配返回价值的可变

返回值也可以分配给可变的,而匹配的条件可以是任何任意的表达方式。 在以下脚本,相匹配表达相匹配的boolean true值作为主题表达有的条件式,呼吁其他内串职能. 

<?php$text = 'A B C D';$result = match (true) {
    str_word_count($text)==3 || str_word_count($text)==2 => '2 or 3',
    str_word_count($text)==4 || str_word_count($text)==5 => '4 or 5',
    };var_dump($result);

输出:

string(6) "4 or 5"

没有类型的胁迫

不像松比较过 switch 声明, match 表达使一个严格的比较并没有类型的胁迫而成。 第一,一个例子的一个松散的比较 switch 发言。 以下脚本相匹配的第一个条件和产出的价值 a

<?php$var = 0;switch((string)$var) {
    case  0  : echo 'a'; break; // This tests for NULL or empty string   
    default : echo 'b'; break; // Everything else, including zero}

相比之下, match 在以下脚本,使一个严格的比较并与默认条件的输出 Default.

<?php$var = 0;
 echo match ((string)$var) {
    0 => 'a',
    default => 'Default',};

甚至 NULL 值相匹配使用身份比较

的 match 表达使的身份比较使用的身份操作员 (===), 这意味着,即使是 NULL 值相匹配。 作为 Ds\Vector::push() 方法返回 NULL, 比赛中表达的以下脚本实际上的匹配 NULL 值返回的 Ds\Vector::push() 方法.  

<?php$vector = new \Ds\Vector();$vector->push('a'); 
 match ($vector->push('b')) {
  $vector->push('d') => $vector->push('b'),
  $vector->pop() => $vector->pop(),};print_r($vector);

第一个条件得到匹配和输出:

Ds\Vector Object ( [0] => a [1] => b [2] => d [3] => b )

身份比较 ( === ) 可以适用于任意的价值观,甚至在没有价值的返回。 的 NULL 值返回的比赛可以分配给可变的。 以下脚本相匹配 NULL 值,第一个条件得到匹配的.

<?php$vector = new \Ds\Vector();$vector->push('a'); 
 $vector = match ($vector->push('b')) {
  $vector->push('c') => $vector->push('b'),
  $vector->pop() => $vector->pop(),};var_dump($vector);

呼叫脚本用的url http://localhost:8000/scripts/sample.php 输出:

NULL

多种条件下可以用逗号分开

多条件式可以逗号分开。 首先,一例与单一条件如下的脚本. 

<?php$vector = new \Ds\Vector();$vector->push('a'); 
 match ('push') {
  'push' => $vector->push('b'),
  'pop' => $vector->pop(),};print_r($vector);

输出 :

Ds\Vector Object ( [0] => a [1] => b )

采取同样的例子,并添加了多个条件,用逗号.

<?php$vector = new \Ds\Vector();$vector->push('a'); 
 match ('puush') {
  'push','puush' => $vector->push('b') 
   };print_r($vector);

拼写错误'puush'被列为第二种选择在第一个条件式名单得到匹配和输出:

Ds\Vector Object ( [0] => a [1] => b )

完整性

的 match 表达必须详尽无遗的。 在以下脚本主题表达是不匹配的任何条件.

<?php$vector = new \Ds\Vector();$vector->push('a'); 
 match ('set') {
  'push' => $vector->push('b'),
  'pop' => $vector->pop(),};print_r($vector);

其结果是,错误是输出:

Uncaught UnhandledMatchError: Unhandled match case 'set'

的 instanceof 操作者的支持任意的表情

另一个新特征是,实例的操作者接受任何任意的表达。 只有两个要求 :

    表达必须被包裹在括号内,并且

    该表必须评估一个字符串. 

展示新的 instanceof 操作员、创建一个PHP script sample.php. 宣布三个变数的集合不同的类型,例如 \Ds\Vector, 和 \Ds\Set.

$collection_a = new \Ds\Vector([1, 2, 3]);$collection_b = new \Ds\Vector();$collection_c = new \Ds\Set();

添加一个任意的功能将返回的一类,例如\Ds\矢量::类作为一个字符串. 

function getSomeClass(): string{
    return \Ds\Vector::class;}

输出结果的使用 instanceof 操作员用不同的集合变量。 的 instanceof 操作者采取一种表达式串在每个呼吁。 的sample.php 被列.

<?php$collection_a = new \Ds\Vector([1, 2, 3]);$collection_b = new \Ds\Vector();$collection_c = new \Ds\Set();function getSomeClass(): string{
    return \Ds\Vector::class;}var_dump($collection_a instanceof ('\Ds'.'\Vector'));var_dump($collection_a instanceof ('\Ds'.'\Hashtable'));var_dump($collection_b instanceof ('\Ds'.'\Vector'));var_dump($collection_b instanceof ('\Ds'.'\Set'));var_dump($collection_c instanceof ('\Ds'.'\Set'));var_dump(new \Ds\Vector instanceof (getSomeClass()));var_dump($collection_a instanceof ('\Ds'.'\Set'));

脚本运行"确定"PHP8和产生输出:

bool(true) bool(false)bool(true) bool(false) bool(true) bool(true) bool(false)

JIT(刚刚在时间)的编译器

PHP8介绍 只是时(JIT)汇编 与以下目标:

    提高性能和可用性.

    让PHP适用于非网CPU密集的使用情况,其实质性能好处是可以预期.

    创建的潜在可能使用PHP,而不是C,开发内在职能。 PHP可能是一个更好的选择,因为它不具有相同的存储管理和溢出问题,作为在C会. 

两个JIT编译引擎的介绍:跟踪JIT和功能JIT。 功能JIT仅优化码范围内的一个单一功能的,而追踪JIT优化整个堆栈跟踪。 跟踪JIT示,以改善性能的3倍于综合基准,并1.5到2倍以上的长期运行查询。 跟踪JIT示,以改善性能超过4次 Mandelbrot的基准

在本文中,我们引入一些最相关的改善PHP8语法,包括属性,运营者的新的、匹配的表达,以及更多。 在下文中,我们应当探索改进课程和构造