导语:最近在工作中遇到项目迁移,遇到一个坑:php7.1.7 的代码在php7.3环境编译下报错。所以想着应该开始整理并注意一下各个php版本之间的特性和函数变化。
参考:PHP:附录 https://www.php.net/manual/zh/appendices.php
博客园:PHP 7系列版本(7.0、7.1、7.2、7.3、7.4)新特性
- 标量参数类型声明[7.0]
- 返回值类型声明[7.0]
- Nullable类型[7.1]
- 属性值类型声明[7.4]
- Void 函数[7.1]
- 箭头函数[7.4]
- 类常量可见性[7.1]
- iterable 伪类[7.1]
- 新的object类型[7.2]
- 允许重写抽象方法[7.2]
- 类在实现接口方法时参数类型扩展[7.2]
- null合并运算符[7.0]
- 空值连写赋值运算符[7.4]
- 组合比较符[7.0]
- 通过 define() 定义常量数组[7.0]
- 支持匿名类[7.0]
- Unicode codepoint 转译语法[7.0]
- Closure::call()[7.0]
- 断言[7.0]
- use 分组写法[7.0]
- 允许分组命名空间的尾部逗号[7.2]
- 生成器可以返回表达式[7.0]
- 生成器委托[7.0]
- 可以使用 list() 函数来展开实现了 ArrayAccess 接口的对象[7.0]
- list()现在支持键名[7.1]
- 对称性数组解构[7.1]
- 数组的解构支持引用赋值[7.3]
- 多异常捕获处理[7.1]
- 支持为负的字符串偏移量[7.1]
- 通过名称加载扩展 dl()[7.2]
- 更灵活的Heredoc 与 Nowdoc 语法[7.3]
- Instanceof 运算符支持字面量[7.3]
- 允许函数和方法被调用时参数最后的空逗号收尾[7.3]
- 多字节字符串的相关函数[7.3]
- 数组内展开[7.4]
- 数值型字面量分隔符[7.4]
- 弱引用[7.4]
- __toString() 方法允许抛出异常[7.4]
新特性
版本 | 特性名称 | 说明 | 示例 |
7.0 | 1、标量参数类型声明 | 标量类型声明 有两种模式: 强制 (默认) 和 严格模式。 现在可以使用下列类型参数(无论用强制模式还是严格模式): 字符串(string), 整数 (int), 浮点数 (float), 以及布尔值 (bool)。 它们扩充了PHP5中引入的其他类型:类名,接口,数组和 回调类型。 | <?php// Coercive modefunction sumOfInts(int …$ints){ return array_sum($ints);} var_dump(sumOfInts(2, ‘3’, 4.1)); |
2、返回值类型声明 | 返回类型声明指明了函数返回值的类型。可用的类型与参数声明中可用的类型相同。 | <?php function arraysSum(array …$arrays): array{ return array_map(function(array $array): int { return array_sum($array); }, $arrays);} print_r(arraysSum([1,2,3], [4,5,6], [7,8,9])); | |
3、null合并运算符 | 如果变量存在且值不为NULL, 它就会返回自身的值,否则返回它的第二个操作数。 | <?php// Fetches the value of $_GET[‘user’] and returns ‘nobody’// if it does not exist.$username = $_GET[‘user’] ?? ‘nobody’;// This is equivalent to:$username = isset($_GET[‘user’]) ? $_GET[‘user’] : ‘nobody’; // Coalesces can be chained: this will return the first// defined value out of $_GET[‘user’], $_POST[‘user’], and// ‘nobody’.$username = $_GET[‘user’] ?? $_POST[‘user’] ?? ‘nobody’;?> | |
4、太空船操作符(组合比较符) | 用于比较两个表达式。当$a小于、等于或大于$b时它分别返回-1、0或1 | <?php// 整数echo 1 <=> 1; // 0echo 1 <=> 2; // -1echo 2 <=> 1; // 1 // 浮点数echo 1.5 <=> 1.5; // 0echo 1.5 <=> 2.5; // -1echo 2.5 <=> 1.5; // 1 // 字符串echo “a” <=> “a”; // 0echo “a” <=> “b”; // -1echo “b” <=> “a”; // 1 | |
5、通过 define() 定义常量数组 | 在 PHP5.6 中仅能通过 const 定义。 | <?phpdefine(‘ANIMALS’, [ ‘dog’, ‘cat’, ‘bird’]); echo ANIMALS[1]; // 输出 “cat” | |
6、匿名类 | <?phpinterface Logger { public function log(string $msg);} class Application { private $logger; public function getLogger(): Logger { return $this->logger; } public function setLogger(Logger $logger) { $this->logger = $logger; }} $app = new Application;$app->setLogger(new class implements Logger { public function log(string $msg) { echo $msg; }}); var_dump($app->getLogger()); | ||
7、Unicode codepoint 转译语法 | 接受一个以16进制形式的 Unicode codepoint,并打印出一个双引号或heredoc包围的 UTF-8 编码格式的字符串 | echo “\u{aa}”;echo “\u{0000aa}”;echo “\u{9999}”; | |
8、Closure::call() | 简短干练的暂时绑定一个方法到对象上闭包并调用它。 | <?phpclass A {private $x = 1;} // PHP 7 之前版本的代码$getXCB = function() {return $this->x;};$getX = $getXCB->bindTo(new A, ‘A’); // 中间层闭包echo $getX(); // PHP 7+ 及更高版本的代码$getX = function() {return $this->x;};echo $getX->call(new A); | |
9、为unserialize()提供过滤 | 通过白名单的方式来防止潜在的代码注入。 | <?php // 将所有的对象都转换为 __PHP_Incomplete_Class 对象$data = unserialize($foo, [“allowed_classes” => false]); // 将除 MyClass 和 MyClass2 之外的所有对象都转换为 __PHP_Incomplete_Class 对象$data = unserialize($foo, [“allowed_classes” => [“MyClass”, “MyClass2”]); // 默认情况下所有的类都是可接受的,等同于省略第二个参数$data = unserialize($foo, [“allowed_classes” => true]); | |
10、断言 | assert()现在是一个语言结构,它允许第一个参数是一个表达式,而不仅仅是一个待计算的 string或一个待测试的boolean。 | <?phpini_set(‘assert.exception’, 1); class CustomError extends AssertionError {} assert(false, new CustomError(‘Some error message’)); | |
11、Group use declarations | 从同一 namespace 导入的类、函数和常量现在可以通过单个 use 语句 一次性导入了。 | // PHP 7+ 及更高版本的代码use some\namespace\{ClassA, ClassB, ClassC as C};use function some\namespace\{fn_a, fn_b, fn_c};use const some\namespace\{ConstA, ConstB, ConstC}; | |
12、生成器可以返回表达式 | 允许在生成器函数中通过使用 return 语法来返回一个表达式 (但是不允许返回引用值), 可以通过调用 Generator::getReturn() 方法来获取生成器的返回值, 但是这个方法只能在生成器完成产生工作以后调用一次。 | <?php $gen = (function() { yield 1; yield 2; return 3;})(); foreach ($gen as $val) { echo $val, PHP_EOL;} echo $gen->getReturn(), PHP_EOL; | |
13、生成器委托 | 只需在最外层生成器中使用 yield from, 就可以把一个生成器自动委派给其他的生成器, Traversable 对象或者 array。 | <?php function gen(){ yield 1; yield 2; yield from gen2();} function gen2(){ yield 3; yield 4;} foreach (gen() as $val){ echo $val, PHP_EOL;} | |
14、整数除法函数 intdiv() | 进行 整数的除法运算。 | <?php var_dump(intdiv(10, 3)); | |
15、可以使用 list() 函数来展开实现了 ArrayAccess 接口的对象 | |||
7.1 | 1、Nullable类型 | 参数以及返回值的类型通过在类型前加上一个问号使之允许为空 | <?php function testReturn(): ?string{ return ‘elePHPant’;} var_dump(testReturn()); function testReturn(): ?string{ return null;} var_dump(testReturn()); function test(?string $name){ var_dump($name);} test(‘elePHPant’);test(null);test(); |
2、Void 函数 | 方法要么干脆省去 return 语句,要么使用一个空的 return 语句。 对于 void 函数来说,NULL 不是一个合法的返回值。 | <?phpfunction swap(&$left, &$right) : void{ if ($left === $right) { return; } $tmp = $left; $left = $right; $right = $tmp;} $a = 1;$b = 2;var_dump(swap($a, $b), $a, $b); | |
3、对称性数组解构 | 短数组语法([])现在作为list()语法的一个备选项,可以用于将数组的值赋给一些变量(包括在foreach中) | <?php$data = [ [1, ‘Tom’], [2, ‘Fred’],]; // list() stylelist($id1, $name1) = $data[0]; // [] style[$id1, $name1] = $data[0]; // list() styleforeach ($data as list($id, $name)) { // logic here with $id and $name} // [] styleforeach ($data as [$id, $name]) { // logic here with $id and $name} | |
4、类常量可见性 | <?phpclass ConstDemo{ const PUBLIC_CONST_A = 1; public const PUBLIC_CONST_B = 2; protected const PROTECTED_CONST = 3; private const PRIVATE_CONST = 4;} | ||
5、iterable 伪类 | <?phpfunction iterator(iterable $iter){ foreach ($iter as $val) { // }} | ||
6、多异常捕获处理 | <?phptry { // some code} catch (FirstException | SecondException $e) { // handle first and second exceptions} | ||
7、list()现在支持键名 | 这意味着它可以将任意类型的数组 都赋值给一些变量 | <?php$data = [ [“id” => 1, “name” => ‘Tom’], [“id” => 2, “name” => ‘Fred’],]; // list() stylelist(“id” => $id1, “name” => $name1) = $data[0]; // [] style[“id” => $id1, “name” => $name1] = $data[0]; // list() styleforeach ($data as list(“id” => $id, “name” => $name)) { // logic here with $id and $name} // [] styleforeach ($data as [“id” => $id, “name” => $name]) { // logic here with $id and $name} | |
8、支持为负的字符串偏移量 | 一个负数的偏移量会被理解为一个从字符串结尾开始的偏移量。 | <?phpvar_dump(“abcdef”[-2]);var_dump(strpos(“aabbcc”, “b”, -3)); | |
7.2 | 1、新的object类型 | 这种新的类型 object, 引进了可用于逆变(contravariant)参数输入和协变(covariant)返回任何对象类型。 | <?php function test(object $obj) : object{ return new SplQueue();} test(new StdClass()); |
2、通过名称加载扩展 | 使用 dl() 函数进行启用 | ||
3、允许重写抽象方法(Abstract method) | <?php abstract class A{ abstract function test(string $s);}abstract class B extends A{ // overridden – still maintaining contravariance for parameters and covariance for return abstract function test($s) : int;} | ||
4、扩展了参数类型 | 重写方法和接口实现的参数类型现在可以省略了。不过这仍然是符合LSP,因为现在这种参数类型是逆变的。 | <?php interface A{ public function Test(array $input);} class B implements A{ public function Test($input){} // type omitted for $input} | |
5、允许分组命名空间的尾部逗号 | <?php use Foo\Bar\{ Foo, Bar, Baz,}; | ||
6、更灵活的Heredoc 与 Nowdoc 语法 | |||
7、数组的解构支持引用赋值 | [&$a, [$b, &$c]] = $d | ||
8、Instanceof 运算符支持字面量 | 判断结果总是 FALSE | ||
9、允许函数和方法被调用时参数最后的空逗号收尾 | |||
10、多字节字符串的相关函数 | mb_convert_case():mb_strtolower())mb_strtoupper())<?phpmb_ereg(‘(?<word>\w+)’, ‘国’, $matches);// => [0 => “国”, 1 => “国”, “word” => “国”]; <?phpmb_ereg_replace(‘\s*(?<word>\w+)\s*’, “_\k<word>_\k’word’_”, ‘ foo ‘);// => “_foo_foo_” | ||
7.4 | 1、属性值类型声明 | <?phpclass User { public int $id; public string $name;} | |
2、箭头函数 | <?php$factor = 10;$nums = array_map(fn($n) => $n * $factor, [1, 2, 3, 4]);// $nums = array(10, 20, 30, 40); | ||
3、空值连写赋值运算符 | <?php$array[‘key’] ??= computeDefault();// is roughly equivalent toif (!isset($array[‘key’])) { $array[‘key’] = computeDefault();} | ||
4、数组内展开 | <?php$parts = [‘apple’, ‘pear’];$fruits = [‘banana’, ‘orange’, …$parts, ‘watermelon’];// [‘banana’, ‘orange’, ‘apple’, ‘pear’, ‘watermelon’]; | ||
5、数值型字面量分隔符 | <?php6.674_083e-11; // float299_792_458; // decimal0xCAFE_F00D; // hexadecimal0b0101_1111; // binary | ||
6、弱引用 | 引用对象使其不被销毁 | ||
7、__toString()方法允许跑出异常 | |||
8.0 | 命名参数 | 新增命名参数的功能 | |
注解(Attributes) | 新增注解的功能 | ||
构造器属性提升 | |||
联合类型 | |||
Match表达式 | |||
Nullsafe运算符(?->) | <?php // 自 PHP 8.0.0 起可用 $result = $repository?->getUser(5)?->name; // 上边那行代码等价于以下代码 if (is_null($repository)) { $result = null; } else { $user = $repository->getUser(5); if (is_null($user)) { $result = null; } else { $result = $user->name; } } ?> | ||
新增WeekMap类 | <?php $wm = new WeakMap(); $o = new StdClass; class A { public function __destruct() { echo “Dead!\n”; } } $wm[$o] = new A; var_dump(count($wm)); echo “Unsetting…\n”; unset($o); echo “Done\n”; var_dump(count($wm)); | ||
新增ValueError类 | |||
参数列表中的末尾逗号为可选 | <?php function functionWithLongSignature( Type1 $parameter1, Type2 $parameter2, // <– 这个逗号也被允许了 ) { } | ||
可作为表达式使用 throw | <?php $fn = fn() => throw new Exception(‘Exception in arrow function’); $user = $session->user ?? throw new Exception(‘Must have user’); | ||
现在,只要类型兼容,任意数量的函数参数都可以用一个可变参数替换现在,只要类型兼容,任意数量的函数参数都可以用一个可变参数替换 | <?php class A { public function method(int $many, string $parameters, $here) {} } class B extends A { public function method(…$everything) {} } ?> | ||
其它特性 | 现在可以通过 $object::class 获取类名,返回的结果和 get_class($object) 一致。现在允许 catch (Exception) 一个 exception 而无需捕获到变量中 |