阿里云「飞天发布时刻」2024来啦!新产品、新特性、新能力、新方案,等你来探~ 了解详情
写点什么

PHP 8:数组、变量、操作符、异常处理

  • 2023-06-11
    北京
  • 本文字数:10145 字

    阅读完需:约 33 分钟

PHP 8:数组、变量、操作符、异常处理

本文属于专题文章《深入浅出 PHP 8》


根据w3tech的数据,PHP 仍是互联网上使用最为广泛的脚本语言之一,77.3%的网站在服务器端均使用该编程语言。PHP 8 为我们带来了许多新功能与优化,具体将在本系列文章中分析。


本篇介绍几个新特性以及与数组、变量、运算符、异常处理和 trait 等有关的改进。

数组与字符串

弃用 false 值的 Autovivification

Autovivification是指当引用数组中未定义的元素时自动创建新数组,例如:


<?php$arr['a'][1] = 'a';var_dump($arr);
复制代码


新数组$arr是自动创建出来的,它在被引用之前并不存在。输出如下:


array(1) { ["a"]=> array(1) { [1]=> string(1) "a" } }
复制代码


Autovivification 允许开发人员引用结构化变量(如数组)及其子元素,而无需首先显式地创建该结构化变量。


PHP 8.0 支持未定义变量、空值和false值的 Autovivification 。下面的脚本演示了null值的 Autovivification:


<?php$arr   = null;$arr[] = 1;var_dump($arr);
复制代码


输出如下:


array(1) { [0]=> int(1) }
复制代码


下面的脚本演示了未定义变量的 Autovivification:


<?php$arr[]                     = 'undefined value';$arr['variableNotExist'][] = 1;
var_dump($arr);
复制代码


上述脚本输出如下:


array(2) { [0]=> string(15) "undefined value" ["variableNotExist"]=> array(1) { [0]=> int(1) } }
复制代码


PHP 8.0 甚至允许false的 Autovivification。不过,PHP 8.0 不支持标量值的 Autovivification,如下面的脚本所示:


<?php$arr   = 1;$arr[] = 1;var_dump($arr);
复制代码


上述脚本输出如下:


Uncaught Error: 不能将标量值作为数组来使用在 PHP 8.1 中,Autovivification 只支持未定义的变量和null 值,已放弃支持false值的 Autovivification。想证明这一点,可以运行以下脚本:


<?php $arr = false;$arr[] = 1;
复制代码


上述脚本输出如下:


Deprecated: 从 false 到数组的自动转换已弃用

字符串键数组解包

解包的使用语境是逐项列出数组元素,或使用解包运算符...取出数组元素。PHP 8.0 不允许对数组中的字符串键进行解包,就像不允许对函数的参数进行解包一样。PHP 8.1 通过引入命名参数提供了函数参数解包支持;命名参数可以在参数解包之后使用,条件是命名参数不能覆盖已解包的参数。“PHP 8:函数和方法的新特性”一文中有一个演示函数命名参数解包的示例。


此外,PHP 8.1 还允许使用运算符将字符串键解包到数组中,如下所示:


<?php
$array1 = ["one" => 1];$array2 = ["two" => 2];$array1 = ["one" => "one"];$array2 = ["two" => "two"];$array = ["one" => 0, "two" => 10, ...$array1, ...$array2];var_dump($array);
复制代码


运算符解包$array1array2,前一个数组的键被后一个数组的键所覆盖。输出结果如下:


array(2) { ["one"]=> string(3) "one" ["two"]=> string(3) "two" }array_merge()函数用于在后台解包数组,因此,解包前面示例中的两个数组可以调用array_merge($array1,$array2)


新特性仅影响字符串键,而整数键将重新编号;原来的整数键不会保留。使用整数键的示例如下:


<?php
$array1 = [1 => 1];$array2 = [2 => 2];$array1 = [1 => "one"];$array2 = [2 => "two"];$array = [1 => 0, 2 => 10, ...$array1, ...$array2];var_dump($array);
复制代码


下面给出了解包字符串键数组的另一个示例,其中引号括起来的整数键实际上会被当作整数键。包含整数的字符串键会被强制转换为整数类型,例如:


<?php  
$array1 = ["1" => 1];$array2 = ["2" => 2];$array1 = ["1" => "one"];$array2 = ["2" => "two"];$array = ["one" => 0, "two" => 10, ...$array1, ...$array2];var_dump($array);
复制代码


输出如下:


array(4) { ["one"]=> int(0) ["two"]=> int(10) [0]=> string(3) "one" [1]=> string(3) "two" }
复制代码

确定数组是否是列表的新函数

数组类型支持字符串键和整数键。有时候,我们需要知道数组键的实际编号是否为0…count($array)-1。在这种情况下,我们将数组称为列表。新增函数array_is_list(array $array): bool就是为了完成这项工作。如果数组是一个列表,则该函数会返回一个booltrue,如果不是,则返回false。下面的例子演示了这个新函数:


<?php  $x = [1 => 'a', 0 => 'b', 2=>'c'];
$y = [0 => 'a', 1 => 'b', 2=>'c'];var_export(array_is_list($x)); var_export(array_is_list($y));
复制代码


输出如下:


falsetrue

数组排序变得稳定

在 PHP 7 中,数组的排序操作是不稳定的。“不稳定”意味着在连续排序中,不能保证“相等”的元素顺序一致。PHP 8.0 中排序变得稳定。如果输入数组中有多个元素相等,则它们在排序完成后总是邻接。换句话说,相等的元素会保持它们在原数组中的顺序。当按照复杂数据的特定属性进行排序时,这一特性特别有用。在这种情况下,如果排序不稳定,则可能会导致输出不一致。下面的脚本演示了稳定排序:


<?php $array = [    'd' => 'c',    'c' => 'c',    'b' => 'a',    'a' => 'a',]; asort($array);
foreach ($array as $key => $val) { echo "array[" . $key . "] = " . $val . "\n"; }
复制代码


在稳定排序中,结果总是:


array[b] = a array[a] = a array[d] = c array[c] = c
复制代码

弃用 ${}字符串插值

在双引号(")中的字符串里嵌入变量可以有多种形式。PHP 8.2 弃用了两种字符串插值形式:${var}${expr}${var}形式与其他两种形式("$var")("{$var}")语法上存在重叠,并且功能不如其他形式强大。${expr}(string) ${expr}等价,很少使用。


下面的例子展示了允许的字符串插值形式,以及不允许的形式${var}${expr}


<?php $str = 'hello'; var_dump("$str");var_dump("{$str}");var_dump("${str}");
var_dump("${str}"); var_dump("${(str)}");
复制代码


上述脚本输出如下:


Deprecated: 字符串插值形式 {var} 已弃用,请使用{var} 代替 in /home/deepakvohra/php-src/scripts/php-info.php on line 8Deprecated: 字符串插值形式 {var}已弃用,请使用{var} 代替 in /home/deepakvohra/php-src/scripts/php-info.php on line 10Deprecated: 字符串插值形式 {expr} (variable variables)已弃用 ,请使用 {{expr}} 代替 in /home/deepakvohra/php-src/scripts/php-info.php on line 12string(5) "hello" string(5) "hello" string(5) "hello" string(5) "hello"Fatal error: Uncaught Error: 未定义常量 "str"

异常处理

PHP 8.0 引入了非捕获catch。以前,每个catch语句都必须为被捕获的异常声明一个变量。例如,下面的脚本在catch语句中声明了Exception类型的变量$exc


<?php
function sortArray(array $arrayToSort){ try { if (count($arrayToSort) === 0) { throw new Exception("Array is empty; please provide a non-empty array"); } } catch (Exception $exc) { echo $exc; }}
$arrayToSort = array();
复制代码


执行上述脚本会输出下面这条异常信息:


Exception: 数组为空,请提供一个非空数组虽然前面的示例使用了$exc变量,但也不是一定要使用异常变量。对于非捕获catch,异常变量是可选的;不声明异常变量,因此也就不能使用,如下所示:


<?php
function sortArray(array $arrayToSort){ try { if (count($arrayToSort) === 0) { throw new Exception("Array is empty; please provide a non-empty array"); } } catch (Exception) { }}
复制代码


多捕获catch语句也可以是非捕获catch,如下所示:


<?php
class Exception1 extends Exception{}
class Exception2 extends Exception{}
class A{ public function fn1() { try { throw new Exception1(); } catch (Exception1 | Exception2) { } }}
复制代码

抛出异常

throw语句以前不能在表达式中使用。PHP 8.0 增加了在表达式中使用throw的支持。例如,在以下脚本中,match 表达式在default中使用了throw表达式。


<?php
$vector = new \Ds\Vector();
$vector->push('a');
try {match ('set') { 'push' => $vector->push('b'), 'pop' => $vector->pop(), default => throw new Exception()}; }catch (Exception $exc) { echo $exc;}print_r($vector);
复制代码


输出如下:


Exception in C:\php-8.1.9-nts-Win32-vs16-x64\scripts\sample.php:11 Stack trace: #0 {main}Ds\Vector Object ( [0] => a )
复制代码


下面的例子将throw与空值合并运算符(??)一起使用:


<?php $name = $_GET['name'] ?? throw new Exception("请提供请求参数'name'");
echo "Hello " . htmlspecialchars($name)."<br>";
复制代码


输出如下:


Uncaught Exception: 请提供请求参数'name'在下面的例子中,throw 和三元运算符(?)一起使用:


<?php
try { function fn1(bool $param1) { $value = $param1 ? true: throw new InvalidArgumentException(); } fn1(true); fn1(false);}catch (Exception $exc) { echo $exc;}
复制代码


输出如下:


InvalidArgumentException in C:\php-8.1.9-nts-Win32-vs16-x64\scripts\sample.php:5 Stack trace: #0 C:\php-8.1.9-nts-Win32-vs16-x64\scripts\sample.php(9): fn1(false) #1 {main}
复制代码

变量

整型字面量的显式八进制表示法

字面量八进制表示法可能产生误导性结果,例如12 === 012的计算结果为false。PHP 8.1 增加了对整型字面量显式八进制表示法0o/0O 的支持,类似于十六进制的0x/0x表示法和二进制的0b/0b表示法。下面的脚本演示了显式八进制表示法:


<?php   var_export(0o12 === 10);   var_export(0o26 === 22);
var_export(0O12 === 10); var_export(0O26 === 22);


var_export(012 === 0o12); var_export(012 === 0O12);
复制代码


输出如下:


truetruetruetruetruetrue
复制代码

限制 $GLOBALS 的使用

通过$GLOBALS变量可以直接访问内部符号表,新版本对它的使用增加了一些限制。从 PHP 8.1 开始,$GLOBALS只能使用$GLOBALS[$name] = $value语法来修改。为了证明这一点,可以运行下面这个直接访问$GLOBALS的脚本:


<?php$x=1;  $GLOBALS = 1;$GLOBALS += 1;$GLOBALS =& $x;$x =& $GLOBALS;unset($GLOBALS);
复制代码


上述脚本会导致以下错误信息:


GLOBALS[value 语法来修改下面这种使用GLOBALS 的方法就没问题:


<?php$GLOBALS['a'] = 1;$GLOBALS['a']--;var_dump($GLOBALS['a']);
复制代码


输出如下:


int(0)
复制代码

将命名空间名称视为单个标记

为了使保留关键字可以出现在命名空间名称中,PHP 8.0 将把命名空间名称视为单个标记。这降低了引入新的保留字时,因为现有命名空间名称已使用该保留字而导致向后不兼容的可能性。


为了说明这一点,下面的脚本在命名空间名称中使用了保留字fn。该脚本还使用了ReflectionClass来输出类的属性,比如它是否是一个命名空间、类名、命名空间和类方法:


<?phpnamespace  do\while\fn\iter;
function fn1(){}class C{ static function fn2() { }}
$class = new \ReflectionClass('do\while\fn\iter\C');
var_dump($class->inNamespace());var_dump($class->getName());var_dump($class->getNamespaceName());
$methods = $class->getMethods();var_dump($methods);
复制代码


输出如下:


bool(true) string(18) "do\while\fn\iter\C" string(16) "do\while\fn\iter" array(1) { [0]=> object(ReflectionMethod)#2 (2) { ["name"]=> string(3) "fn2" ["class"]=> string(18) "do\while\fn\iter\C" } }
复制代码

运算符

PHP 8 增加了许多与新运算符相关的特性。

非严格字符串数字比较变得更加有用

在 PHP 8.0 之前,非严格字符串数字比较都是假设字符串实际上是一个数字,并将字符串转换为数字后进行数字比较。PHP 8.0 会在转换类型并进行数字比较之前确保字符串是一个数字。否则,它会将数字转换为字符串,并进行字符串比较。新特性不适用于严格比较运算符===!==。这些运算符要求两个操作数具有相同的类型,并且不执行隐式类型转换。受影响的只有非严格比较运算符==!=>>=<<=。下面的脚本演示了新的字符串数字比较:


<?php var_dump(1 == "001");         var_dump(1 == "1.0");           var_dump(1.0 == "+1.0E0");  
var_dump(1 == "1 ");
var_dump(1 == " 1");


var_dump(1 == " 1 "); var_dump("one" == "1");
var_dump("one" != "1");
复制代码


输出如下:


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

空值安全运算符

你是不是经常调用方法或获取表达式结果的属性并假设结果非空?由于结果可能为空,所以最好首先确保它不是空的。你可以显式地使用if(result!=null)进行比较,但它可能涉及层次化的多重比较。下面的脚本使用传统的if比较,对整数值的加法进行空值安全的比较:


<?php class Sum{    public int $i;
function __construct() { $this->i = 0; } function addA(Sum $sum,int $a):?Sum { $sum->i= $a+$sum->i; return $sum; } function addB(Sum $sum,int $b):?Sum { $sum->i= $b+$sum->i; return $sum; } function addC(Sum $sum,int $c):?Sum { $sum->i= $c+$sum->i; return $sum; }
function getSum(Sum $sum):int { return $sum->i; }
}


$a = new Sum();
if ($a->addA($a,1) !== null) { if ($a->addB($a,2) !== null) { if ($a->addC($a,3) !== null) { echo $a->getSum($a); } }}
复制代码


上述脚本的结果是6


新运算符?->可用于链接调用以进行空值安全比较,当运算符的左操作数计算结果为null时,它将停止所有后续的比较。对于上述加法操作,以下脚本演示了链接操作数,使用新运算符?-> 进行空值安全比较。


echo $a->addA($a,1)?->addB($a,2)?->addC($a,3)?->getSum($a);
复制代码

与语言环境无关的浮点数字符串转换

在 PHP 8.0 之前,浮点数到字符串类型的转换依赖于语言环境,也就是说,小数分隔符会因语言环境而异。这可能会导致一些不一致,例如将字符串解释为格式错误,或将字符串解释为数值。开发人员非常需要一致的浮点数字符串表示,而 PHP 8.0 正好提供了这一点。下面的脚本演示了与本地语言环境无关的浮点数字符串转换。


<?php setlocale(LC_ALL, "de_DE");$f = 1.23; echo (string) $f;      echo strval($f);
复制代码


输出结果如下:


1.231.23
复制代码

对算术/位运算符进行更严格的类型检查

算术/位运算符+-*/**%<<>>&|^~++-只能应用于支持这些运算符的操作数。这些运算符不能用于数组、资源或非重载对象操作数。PHP 8.0 会进行严格的类型检查,如果操作数与算术/位运算符不兼容,则抛出TypeError。为了演示这一点,下面的脚本对数组使用了减法运算符(-):


<?php  $arrayToSort = array(3, 1, 0, 2); var_dump($arrayToSort - [1]);
复制代码


上述脚本会导致以下错误:


Uncaught TypeError: 不支持的操作数类型: array - array 
复制代码

在常量表达式中使用->/?- >运算符获取枚举属性

枚举对象不允许出现在常量表达式中,如数组键,这样你就无法在常量表达式中获取枚举属性的名称和值。为了演示这一点,请使用 8.1 版本运行以下脚本:


<?php
enum Sort: string { case ASC = 'ASC'; const SortType = [self::ASC->name => self::ASC->value];}
复制代码


上述脚本会导致如下错误信息:


常量表达式包含无效操作 PHP 8.2 允许在常量表达式中使用-> ?->运算符获取枚举属性,如下所示:


<?php
enum Sort: string { case ASC = 'ASC'; const SortType = [self::ASC->name => self::ASC->value];}function get(){ static $g = Sort::ASC->value;}
#[Attr(Sort::ASC->name)]class SortClass{}
function set($s = Sort::ASC->value,){}
class SortClass2{ public string $n = Sort::ASC->name;}// The rhs of -> allows other constant expressionsconst DESC = 'DESC';class SortClass3{ const C = Sort::ASC->{DESC};}
复制代码

Trait

抽象 trait 方法验证

PHP 8.0 会在组合/使用类中验证抽象 trait 方法,以确保它们的签名匹配。实现方法必须与 trait 方法兼容,这里的兼容被定义为签名兼容:


  • 参数数量兼容:函数参数的数量必须相同

  • 逆变参数类型兼容

  • 协变返回类型兼容另外,静态方法必须保持静态。抽象 trait 方法可以是私有的。下面的脚本演示了抽象 trait 方法的一个准确实现:


<?php trait HelloTrait {    abstract private function hello(): string;     public function getMsgLength() {        return strlen($this->hello());    }} class A {    use HelloTrait;   private function hello(): string {return "Hello John"; }}
复制代码


为了演示不兼容的情况,将实现方法修改如下:


private function hello(): stdClass { }
复制代码


在这种情况下,会报以下错误信息:


A::hello(): stdClass的声明必须与HelloTrait::hello(): string兼容
复制代码


不能在类中将 trait 中的非静态方法变成静态。为了演示这一点,修改实现如下:


private static function hello(): string { }
复制代码


上述脚本会报以下错误信息:


无法在类A中将非静态方法HelloTrait::hello()变成静态
复制代码

弃用在 Trait 上调用静态元素的特性

PHP 8.1.0 放弃在 trait 上调用静态元素的支持,也就是说,不能直接在 trait 上调用静态方法或静态属性。只能通过使用 trait 的类访问 trait 的静态方法和属性。下面的脚本演示了这种情况:


<?php trait HelloTrait {
public static $a = 'static property in trait'; public static function hello(): string {return "Hello";} } class A { use HelloTrait; }
echo A::$a; echo A::hello();
echo HelloTrait::$a;echo HelloTrait::hello();
复制代码


输出如下:


Deprecated: 不能直接访问静态 trait 属性 HelloTrait::$a,只能通过使用该 trait 的类访问 Deprecated: 不能直接访问静态 trait 方法 HelloTrait::hello,只能通过使用该 trait 的类访问

Trait 中的常量

PHP 8.1 不允许在 trait 中使用不变量(也称为常量)。PHP 8.2 增加了对在 trait 中使用常量的支持。这些常量可以由 trait 的方法使用,也可以在组合类中使用。为了演示常量在 trait 中的用处,请看下面的示例。其中,组合类中声明了一个名为MAX_ARRAY_SIZE的常量:


<?php
trait SortTrait{ public function sortArray(array $arrayToSort): void { if (count($arrayToSort) > self::MAX_ARRAY_SIZE) { throw new \Exception("array size out of range"); } else { sort($arrayToSort); foreach ($arrayToSort as $key => $val) { echo "$key = $val "; } echo "<br/>"; } }}
class SortClass{ private const MAX_ARRAY_SIZE = 10; use SortTrait;}
$arrayToSort = ["B", "A", "f", "C", 1, "a", "F", "B", "b", "d"];$obj = new SortClass();$obj->sortArray($arrayToSort);
复制代码


运行上述脚本会生成以下输出:


0 = 1 1 = A 2 = B 3 = B 4 = C 5 = F 6 = a 7 = b 8 = d 9 = f 下面是同一脚本的 8.2 版本,在 trait 中声明了常量MAX_ARRAY_SIZE


<?php
trait SortTrait{ public const MAX_ARRAY_SIZE = 10;
public function sortArray(array $arrayToSort): void { if (count($arrayToSort) > self::MAX_ARRAY_SIZE) { throw new \Exception("array size out of range"); } else { sort($arrayToSort); foreach ($arrayToSort as $key => $val) { echo "$key = $val "; } echo "<br/>"; } }}
class SortClass{ use SortTrait;}
$arrayToSort = ["B", "A", "f", "C", 1, "a", "F", "B", "b", "d"];$obj = new SortClass();$obj->sortArray($arrayToSort);
复制代码


输出相同:


0 = 1 1 = A 2 = B 3 = B 4 = C 5 = F 6 = a 7 = b 8 = d 9 = f 再看一个例子。下面的脚本在 trait 中声明了 3 个常量,并在 trait 中使用了它们:


<?php
trait SortTrait{ public const SORT_TYPE_1 = "ASC"; public const SORT_TYPE_2 = "DESC"; public const SORT_TYPE_3 = "SHUFFLE";
public function getSortType(string $sortType): void { if (str_contains($sortType, self::SORT_TYPE_1)) { echo "Sort type is ASC"; } if (str_contains($sortType, self::SORT_TYPE_2)) { echo "Sort type is DESC"; } if (str_contains($sortType, self::SORT_TYPE_3)) { echo "Sort type is SHUFFLE"; } }}
class SortClass{ use SortTrait;}
$obj = new SortClass();
$obj->getSortType("ASCending");
复制代码


输出如下:


Sort type is ASCTrait 常量无法通过TRAIT_NAME::CONSTANT 语法直接访问,就像下面的脚本这样:


<?php
trait SortTrait{ public const SORT_TYPE_1 = "ASC"; public const SORT_TYPE_2 = "DESC"; public const SORT_TYPE_3 = "SHUFFLE";
public function getSortType(string $sortType): void { if (str_contains($sortType, SortTrait::SORT_TYPE_1)) { echo "Sort type is ASC"; } if (str_contains($sortType, self::SORT_TYPE_2)) { echo "Sort type is DESC"; } if (str_contains($sortType, self::SORT_TYPE_3)) { echo "Sort type is SHUFFLE"; } }}
class SortClass{ use SortTrait;}
$obj = new SortClass();
$obj->getSortType("ASCending");
复制代码


执行上述脚本会输出以下错误信息:


Uncaught Error: 不能直接访问 trait 常量 SortTrait::SORT_TYPE_1 使用$this就可以,如下所示:


if (str_contains($sortType, $this::SORT_TYPE_1)) {            echo 'Sort type is ASC';        }
复制代码


Trait 常量可以声明为 final 类常量。适用于 trait 属性的兼容性限制也适用于它的常量。


枚举可以使用包含常量的 trait,和直接在枚举中定义它们一样,如下所示:


<?php
trait SortTrait{ private const SortType = "ASC";}
enum Enum1: int{ use SortTrait;
case CaseA = self::SortType;}
复制代码

逐步淘汰 Serializable

PHP 7.4 引入了自定义序列化机制,借助两个新的魔法方法:__serialize(): array__unserialize(array $data): void__serialize()方法返回一个包含对象所有必要状态的数组,__unserialize()方法从给定的数据数组中恢复对象状态。新的自定义序列化机制旨在逐步淘汰Serializable接口。如果一个非抽象类实现了Serializable,但没有实现__serialize()__unserialize(), PHP 8.1 就会生成一条弃用警告。这样的一个类被称为“only Serializable”。为了演示这一点,可以运行下面的脚本:


<?php class A implements Serializable {}
复制代码


执行上述脚本会显示以下弃用信息:


Deprecated: A 实现了 Serializable 接口,该接口已弃用。如果需要支持旧的 PHP 版本,请实现__serialize()和__unserialize()Fatal error: 类 A 包含 2 个抽象方法,因此必须声明为抽象的,或者实现其余的方法 (Serializable::serialize, Serializable::unserialize)

弃用动态属性

动态类属性是在声明之前被引用的属性。动态属性是自动创建的。PHP 8.2 已弃用动态属性。这主要是为了避免这样一种情况:用户无意创建新属性,但却因为输入了错误的属性名称而创建了新属性。为了演示这一点,在 PHP 8.2 中运行下面的脚本创建一个动态属性:


<?php
class A{ public $name;}
$a = new A();
// 给已声明的属性User::$name赋值$a->name = "John";
$a->firstname = "John";
复制代码


执行上述脚本会输出以下弃用信息:


Deprecated: 已弃用创建动态属性 A::$firstname 如果你仍然希望动态属性实现魔术方法__get/__set,或使用新属性#[AllowDynamicProperties],则预打包类stdClass已经用#[AllowDynamicProperties]属性标记。

弃用向内置函数的非可空参数传递 null 值的特性

当强类型模式设置为(strict_types=1)时,用户定义函数不接受向非空参数传递null值。在 PHP 8.1 中,即使是内置函数也不会接受向非空参数传递null值,如下所示,它会生成弃用通知:


<?php$var=null; strlen($var);
复制代码


输出如下:


Deprecated: strlen(): 向 string 类型的参数 #1 ($string)传递 null 的特性已弃用在 PHP 9.0 中,TypeError弃用通知将被替换为错误。


在本文中,我们讨论了 PHP 8 中与数组、变量、运算符和异常处理相关的新特性。我们还讨论了一些与 trait、类和函数相关的特性。


原文链接:

https://www.infoq.com/articles/php8-arrays-variables-operators/


相关阅读:

PHP 8:注解、match 表达式及其他改进

PHP 8:类和枚举

PHP 8:函数和方法

2023-06-11 08:004020

评论

发布
暂无评论
发现更多内容

STC89C52+AT24C02实现设备开机次数记录

DS小龙哥

6 月 优质更文活动

推荐几款可以大幅提高开发效率的vscode插件 | 京东云技术团队

京东科技开发者

Vue 前端 vscode

再见Navicat,dbeaver才是真香

程序员小毕

Java 数据库 程序员 后端 架构师

快上车,搭乘HUAWEI HiCar驶向未来

HMS Core

HMS Core

Intellij IDEA 插件开发 | 京东云技术团队

京东科技开发者

Java IntelliJ IDEA 企业号 6 月 PK 榜 插件工程

软件测试/测试开发丨Python内置库学习笔记

测试人

Python 软件测试 io 科学计算 内置库

强化学习从基础到进阶--案例与实践[7.1]:深度确定性策略梯度DDPG算法、双延迟深度确定性策略梯度TD3算法详解项目实战

汀丶人工智能

人工智能 深度学习 强化学习 6 月 优质更文活动 DDPG算法

华为云专家出品《从零到一•Python图像处理入门》电子书

华为云PaaS服务小智

Python 华为 华为云 华为开发者大会2023

图文结合带你搞懂GreatSQL体系架构

GreatSQL

greatsql greatsql社区

构建系列之新一代利器Esbuild(下)

江湖修行

前端 cli 构建 #web esbuild

G1垃圾回收参数调优及MySQL虚引用造成GC时间过长分析 | 京东云技术团队

京东科技开发者

MySQL G1 GC 企业号 6 月 PK 榜

MaxCompute湖仓一体近实时增量处理技术架构揭秘

阿里云大数据AI技术

sql 大数据 分布式计算 数据处理 企业号 6 月 PK 榜

安全专家们看过来,易安联EnSRC第二期众测启动

权说安全

直播系统源码知识分享:解你忧愁!降低直播延迟的实现

山东布谷科技

软件开发 源码搭建 直播系统源码 直播源码

【网络安全】堡垒机对于企业的重要性你知道吗?

行云管家

云计算 运维 网络安全 堡垒机

瓴羊Quick BI四度入选魔力象限报告,标志着BI系统的国产化进程加速

对不起该用户已成仙‖

BI分析能力:当今企业必备核心竞争力

夜雨微澜

CSS中常用的颜色格式

南城FE

CSS css3 前端 设计

Redis跳跃表是如何添加元素的?

小小怪下士

Java redis 面试

程序员用哪一种IDE写代码比较好?

没有用户名丶

一图讲清楚公众号扫码关注绑定手机号自动登录

越长大越悲伤

微信 公众号接入

SQL 优化(二):避免隐式转换

hungxy

HTML5 游戏开发实战 | 黑白棋

TiAmo

html html5 6 月 优质更文活动

【直播预告】HarmonyOS极客松赋能直播第三期:一次开发多端部署与ArkTS卡片开发

HarmonyOS开发者

HarmonyOS

2023银川市等级保护测评中心地址在哪里?有几家?

行云管家

等保 等保测评 等级测评 银川

C++的重载运算符和重载函数

智趣匠

重磅新品全球公测!华为云数据库又有大动作

平平无奇爱好科技

强化学习从基础到进阶--案例与实践[7]:深度确定性策略梯度DDPG算法、双延迟深度确定性策略梯度TD3算法详解

汀丶人工智能

人工智能 深度学习 强化学习 6 月 优质更文活动 DDPG算法

强化学习从基础到进阶-常见问题和面试必知必答[7]:深度确定性策略梯度DDPG算法、双延迟深度确定性策略梯度TD3算法详解

汀丶人工智能

人工智能 深度学习 强化学习 6 月 优质更文活动 DDPG算法

大语言模型的开发利器langchain

程序那些事

程序那些事 AIGC ChatGPT 大语言模型

Spring Boot配置文件加载顺序详解

2756

PHP 8:数组、变量、操作符、异常处理_编程语言_Deepak Vohra_InfoQ精选文章