整理一下 PHP-7.4.0 提供的一些改进和新特性。
有类型的类属性
类属性现在支持类型声明。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
| <?php
class User
{
public int $id;
public string $name;
}
$user = new User();
$user->id = '123';
$user->name = 123;
var_dump($user->id, $user->name);
// 结果
int(123)
string(3) "123"
|
箭头函数
箭头函数为使用隐式按值范围绑定定义函数提供了一种简写语法。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
| <?php
$factor = 10;
$nums = array_map(fn($n) => $n * $factor, [1, 2, 3, 4]);
var_dump($nums);
// 结果
array(4) {
[0]=>
int(10)
[1]=>
int(20)
[2]=>
int(30)
[3]=>
int(40)
}
|
有限返回类型协变和参数类型逆变
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
| <?php
class A
{
}
class B extends A
{
}
class Producer
{
public function method(): A
{
echo __METHOD__, PHP_EOL;
return new A();
}
}
class ChildProducer extends Producer
{
public function method(): B
{
echo __METHOD__, PHP_EOL;
return new B();
}
}
$producer = new Producer();
$childProducer = new ChildProducer();
if ($producer->method() instanceof A) {
var_dump('我特么就返回 A 的实例');
}
if ($childProducer->method() instanceof B) {
var_dump('我特么就返回 B 的实例');
}
// 结果
Producer::method
string(30) "我特么就返回 A 的实例"
ChildProducer::method
string(30) "我特么就返回 B 的实例"
|
NULL 合并运算符
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
| <?php
function defaultValue(): string
{
return '';
}
$array = $_REQUEST;
// PHP74 之前
if (! isset($array['key'])) {
$array['key'] = defaultValue();
}
// PHP74 开始
$array['key'] ??= defaultValue();
// 虽然以下代码也可以,但是本人强烈反对这样写,不要问我为什么。代码块我总是用 {} 包起来
if (! isset($array['key'])) $array['key'] = defaultValue();
|
在数组内部展开元素
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
| <?php
$parts = ['apple', 'pear'];
$fruits = ['banana', 'orange', ...$parts, 'watermelon'];
var_dump($fruits);
// 结果
array(5) {
[0]=>
string(6) "banana"
[1]=>
string(6) "orange"
[2]=>
string(5) "apple"
[3]=>
string(4) "pear"
[4]=>
string(10) "watermelon"
}
|
数字字面量分隔符
人眼并未针对快速解析长数字序列进行优化。 因此,缺少视觉分隔符会使读取和调试代码花费更长的时间,并可能导致意外错误。
所以 数字字面量分隔符 就是解决人眼快速识别而做出的优化,你看,代码的的确确是机器去执行的,但更重要的是 可读、可写、可赏、可赞 😂。
1
2
3
4
5
6
7
8
9
10
11
12
| 6.674_083e-11; // float
299_792_458; // decimal
0xCAFE_F00D; // hexadecimal
0b0101_1111; // binary
0137_041; // octal
1_000_000; // versus 1000000
3.141_592; // versus 3.141592
0x02_56_12; // versus 0x025612
0b0010_1101; // versus 0b00101101
0267_3432; // versus 02673432
1_123.456_7e2 // versus 1123.4567e2
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
| <?php
usleep(345126); // without separator
usleep(345_126); // with separator
if (12345678989876 === 12345678998876) {
echo 'Equal';
} else {
echo 'Unequal';
}
echo PHP_EOL;
if (12_345_678_989_876 === 12_345_678_998_876) {
echo 'Equal';
} else {
echo 'Unequal';
}
|
弱引用
允许来自 toString() 的异常
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
| <?php
class CustomException extends \Exception
{
}
class Foo
{
public function __toString()
{
throw new CustomException('Oops!');
}
}
$foo = new Foo();
try {
var_dump((string) $foo);
} catch (CustomException $e) {
var_dump($e);
}
// 结果
// PHP56
PHP Fatal error: Method Foo::__toString() must not throw an exception in /path/to/User.php on line 0
// PHP73
PHP Fatal error: Method Foo::__toString() must not throw an exception, caught CustomException: Oops! in /path/to/a.php on line 0
// PHP74
object(CustomException)#2 (7) {
["message":protected]=>
string(5) "Oops!"
["string":"Exception":private]=>
string(0) ""
["code":protected]=>
int(0)
["file":protected]=>
string(47) "/Users/xxx/Codes/example/untitled/User.php"
["line":protected]=>
int(11)
["trace":"Exception":private]=>
array(1) {
[0]=>
array(6) {
["file"]=>
string(47) "/Users/xxx/Codes/example/untitled/User.php"
["line"]=>
int(18)
["function"]=>
string(10) "__toString"
["class"]=>
string(3) "Foo"
["type"]=>
string(2) "->"
["args"]=>
array(0) {
}
}
}
["previous":"Exception":private]=>
NULL
}
|
Opcache 预加载
opcache.preload
string
:指定要在服务器启动时期进行编译和缓存的 PHP 脚本文件,这些文件也可能通过 include 或者 opcache_compile_file() 函数来预加载其他文件。所有这些文件中包含的实体,包括函数、类等,在服务器启动的时候就被加载和缓存,对于用户代码来讲是『开箱可用』的。
一些不推荐
Deprecated Features
从核心中移除的扩展
Removed Extensions