2天时间,聊今年最热的 Agent、上下文工程、AI 产品创新等话题。2025 年最后一场~ 了解详情
写点什么

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:005314

评论

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

论利润中心内部核算和集团核算

秋去冬来春未远

阿米巴 利润中心 集团成本

Android C/C++层hook和java层hook原理以及比较

云智慧AIOps社区

Java android 开发技能 hook

图数据库|正反向边的最终一致性——TOSS 介绍

NebulaGraph

图数据库 知识图谱

什么是代码加密?基于云效 Codeup的代码仓库加密是如何实现的

阿里云云效

云计算 阿里云 代码管理 Codeup 代码加密

【ELT.ZIP】OpenHarmony啃论文俱乐部——这些小风景你不应该错过

ELT.ZIP

神经网络 OpenHarmony ELT.ZIP

HLP分词后的文本如何在web端高亮显示

lo

前端 4月月更

博云 BeyondCMP 云管理平台 5.6 版本发布

BoCloud博云

云管理平台

OceanBase 杨传辉参与数据库技术与应用发展研讨会

OceanBase 数据库

oceanbase

Apache Doris (incubating) 1.0 Release 版本正式发布!

ApacheDoris

数据库 大数据 开源 OLAP apache doris

深圳助力建设全国「数据交易」大市场,「隐私计算」技术赋能数据要素安全流通

洞见科技

Java 操作 Office:POI word 之文档信息提取

程序员架构进阶

内容审核 4月日更 文档识别 4月月更

企业管理理念之人本善还是本恶

秋去冬来春未远

企业管理 人性本善 人性本恶 一念之差

TDesign 更新周报(2022 年 4 月第 3 周)

TDesign

如何做好任务管理,手把手教你怎么做最高效的任务管理

阿里云云效

云计算 阿里云 云原生 研发团队 项目协作

安全之花如何盛开在华为云空间的每个角落?

脑极体

过去一周热点回顾|Hoo虎符研究院 区块链简报 20220418期

区块链前沿News

虎符交易所

优秀程序员的30种思维(29/100)

hackstoic

技术思维

【ELT.ZIP】OpenHarmony啃论文俱乐部——浅析稀疏表示医学图像

ELT.ZIP

OpenHarmony 医学影像 稀疏矩阵 ELT.ZIP

在线YAML转CSV工具

入门小站

工具

【愚公系列】2022年04月 二十三种设计模式(零)-简单工厂模式(Simple Factory Pattern)

愚公搬代码

4月月更

国产化云平台如何实现多云管控,黄河云来“打样儿”

BoCloud博云

国产化 云管理平台

物联网低代码平台常用《组件介绍》

AIRIOT

开发 物联网 平台搭建、

移动端日历组件设计与实现

CRMEB

用css制作旋转的立方体

云智慧AIOps社区

CSS 前端 大前端 3D css特效

TASKCTL 连接不到服务器的4种情况

敏捷调度TASKCTL

分布式 调度引擎 ETL 自动化运维 调度任务

高效进行接口测试,简单易懂!

Liam

测试 Jmeter Postman swagger 测试工具

易周金融观点:遏制NFT金融化等打下监管良基

易观分析

NFT

Serverless 让我们的运维更轻松

领创集团Advance Intelligence Group

#Serverless

火遍全网的MBTI人格测试,为什么会有那么多人相信?

小炮

MBTI

以OceanBase为例,分析事务型评测基准对分布式数据库的适用性

OceanBase 数据库

分布式数据库 oceanbase

linux之rpm命令

入门小站

Linux

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