PHP7 新特性

PHP7都发布好几年了,你确定不了解一下?

PHP7新特性语法

标量类型声明

1
2
3
4
5
6
7
8
9
// 强制模式
function sumOfInts(int ...$ints)
{
return array_sum($ints);
}

var_dump(sumOfInts(2, '3', 4.1));

// echo int(9)

强制模式(默认,既强制类型转换)下还是会对不符合预期的参数进行强制类型转换,
严格模式下则触发 TypeError 的致命错误。

返回值类型声明

1
2
3
4
5
6
7
8
9
10
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]));

// Array ( [0] => 6 [1] => 15 [2] => 24 )

NULL 合并运算符: ??

由于日常使用中存在大量同时使用三元表达式isset()的情况,
NULL 合并运算符使得变量存在且值不为NULL, 它就会返回自身的值,否则返回它的第二个操作数。

1
2
3
4
5
// 如果 $_GET['user'] 不存在返回 'nobody',否则返回 $_GET['user'] 的值
$username = $_GET['user'] ?? 'nobody';

// 类似的三元运算符
$username = isset($_GET['user']) ? $_GET['user'] : 'nobody';

太空船操作符(组合比较符)

太空船操作符用于比较两个表达式。当$a大于、等于或小于$b时它分别返回-1、0或1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 整型
echo 1 <=> 1; //0 等于返回0
echo 1 <=> 2; //-1 小于返回-1
echo 2 <=> 1; //1 大于返回1

// 浮点型
echo 1.5 <=> 1.5; // 0
echo 1.5 <=> 2.5; // -1
echo 2.5 <=> 1.5; // 1

// 字符串
echo "a" <=> "a"; // 0
echo "a" <=> "b"; // -1
echo "b" <=> "a"; // 1

通过 define() 定义常量数组

1
2
3
4
5
6
7
8
define('ANIMALS', [
'dog',
'cat',
'bird'
]);

echo ANIMALS[1];
// echo cat

匿名类

现在支持通过new class 来实例化一个匿名类,实例如下:

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
interface 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());
// object(class@anonymous)#2 (0) { }

Unicode codepoint 转译语法

这接受一个以16进制形式的 Unicode codepoint,并打印出一个双引号或heredoc包围的 UTF-8 编码格式的字符串。
可以接受任何有效的 codepoint,并且开头的 0 是可以省略的。

1
2
3
4
echo "\u{aa}";
echo "\u{0000aa}";
echo "\u{9999}";
// a a 香

Closure::call()

Closure::call() 现在有着更好的性能,简短干练的暂时绑定一个方法到对象上闭包并调用它。

1
2
3
4
5
6
7
8
9
10
11
12
class A {private $x = 1;}

// Pre PHP 7
$getXCB = function () {return $this->x;};
$getX = $getXCB->bindTo(new A, 'A'); //中间闭合 ???
echo $getX();
// echo 1

// New PHP 7
$getX = function () {return $this->x;};
echo $getX->call(new A);
// echo 1

unserialize()提供过滤

这个特性旨在提供更安全的方式解包不可靠的数据。它通过白名单的方式来防止潜在的代码注入。

1
2
3
4
5
6
7
8
// 转换对象为 __PHP_Incomplete_Class 对象
$data = unserialize($foo, ["allowed_classes" => false]);

// 转换对象为 __PHP_Incomplete_Class 对象,除了 MyClass 和 MyClass2
$data = unserialize($foo, ["allowed_classes" => ["MyClass", "MyClass2"]]);

// 默认接受所有类
$data = unserialize($foo, ["allowed_classes" => true]);

use 加强

从同一 namespace 导入的类、函数和常量现在可以通过单个 use 语句 一次性导入了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//  PHP 7 之前版本用法
use some\namespace\ClassA;
use some\namespace\ClassB;
use some\namespace\ClassC as C;

use function some\namespace\fn_a;
use function some\namespace\fn_b;
use function some\namespace\fn_c;

use const some\namespace\ConstA;
use const some\namespace\ConstB;
use const some\namespace\ConstC;

// 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};

Generator 加强

增强了Generator的功能,这个可以实现很多先进的特性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
function gen()
{
yield 1;
yield 2;

yield from gen2();
}

function gen2()
{
yield 3;
yield 4;
}

foreach (gen() as $val)
{
echo $val,PHP_EOL;
}

// 1 2 3 4

整除 intdiv

新增了整除函数 intdiv(),使用实例:

1
var_dump(intdiv(10, 3)); //int(3)

PHP7废弃特性

PHP4 风格的构造函数

在 PHP4 中类中的函数可以与类名同名,这一特性在 PHP7 中被废弃,同时会发出一个 E_DEPRECATED 错误。当方法名与类名相同,且类不在命名空间中,
同时PHP5的构造函数(__construct)不存在时,会产生一个 E_DEPRECATED 错误。

1
2
3
4
5
6
7
8
class A {
function A() {
print ('Style Constructor');
}
}

// Deprecated: Methods with the same name as their class will not be constructors in a future version of PHP;
// A has a deprecated constructor in...

以静态的方式调用非静态方法

以静态的方式调用非静态方法,不再支持:

1
2
3
4
5
6
7
8
9
class A {
function b() {
print('Non-static call');
}
}

A::b();
// Deprecated: Non-static method A::b() should not be called statically in...
// Non-static call

password_hash() 随机因子选项

函数原 salt 量不再需要由开发者提供了。函数内部默认带有 salt 能力,无需开发者提供 salt 值。

capture_session_meta SSL 上下文选项

废弃了 "capture_session_meta" SSL 上下文选项。
在流资源上活动的加密相关的元数据可以通过 stream_get_meta_data() 的返回值访问。

PHP7移除的扩展

  • ereg
  • mssql
  • mysql
  • sybase_ct

PHP7: 再深入一点~~

PHP7引擎( What will be in PHP 7 / PHPNG )

  • Performance Improvements with the addition of PHPNG engine.(使用PHPNG引擎来提升性能)
  • PHPNG不再使用zval的二级指针。大多数出现的zval*变量和参数都将改变成zval。相应的,使用在这些变量上的宏Z_PP()也需要变成Z_P()。
  • More -> https://wiki.php.net/phpng-upgrading
  • JIT - Just in Time compiler 即时编译 (参考百度百科介绍)
  • Abstract Syntax Tree for compilation(抽象语法树编译)
  • Asynchronous refactoring of the I/O layer. 对I/O层的异步重构
  • Multi-threaded build in Web Server多线程构建Web服务器
  • Expanded use of ->, [], (), {}, and :: operators 扩展使用 ->, [], (), {}, 和 :: 符号
  • 100% increase in performance性能提升 100% (应该是QPS)
  • Cool Name: PHPNG 酷名:PHPNG引擎

Zval的改变

PHP的各种类型的变量,其实,真正存储的载体就是Zval,它特点是海纳百川,有容乃大。从本质上看,它是C语言实现的一个结构体(struct)。
对于写PHP的同学,可以将它粗略理解为是一个类似array数组的东西。

PHP5Zval,内存占据24个字节,PHP7Zval,内存占据16个字节。

不需要引用的类型:NULL、Boolean、Long、Double
需要引用的类型:String、Array、Object、Resource、Reference

内部类型zend_string

Zend_string是实际存储字符串的结构体,实际的内容会存储在val(char,字符型)中,
val是一个char数组,长度为1(方便成员变量占位)。

PHP数组的变化(HashTableZend Array

在编写PHP程序过程中,使用最频繁的类型莫过于数组,PHP5的数组采用HashTable实现。
如果用比较粗略的概括方式来说,它算是一个支持双向链表的HashTable,不仅支持通过数组的key来做hash映射访问元素,也能通过foreach以访问双向链表的方式遍历数组元素。

当我们通过key值访问一个元素内容的时候,有时需要3次的指针跳跃才能找对需要的内容。
而最重要的一点,就在于这些数组元素存储,都是分散在各个不同的内存区域的。
同理可得,在CPU读取的时候,因为它们就很可能不在同一级缓存中,会导致CPU不得不到下级缓存甚至内存区域查找,
也就是引起CPU缓存命中下降,进而增加更多的耗时。

新版本的数组结构,非常简洁,让人眼前一亮。
最大的特点是,整块的数组元素和hash映射表全部连接在一起,被分配在同一块内存内。
如果是遍历一个整型的简单类型数组,效率会非常快,因为,数组元素(Bucket)本身是连续分配在同一块内存里,
并且,数组元素的zval会把整型元素存储在内部,也不再有指针外链,全部数据都存储在当前内存区域内。
当然,最重要的是,它能够避免CPU Cache Miss(CPU缓存命中率下降)。

Zend Array的变化:

    1. 数组的value默认为zval。
    1. HashTable的大小从72下降到56字节,减少22%。
    1. Buckets的大小从72下降到32字节,减少50%。
    1. 数组元素的Buckets的内存空间是一同分配的。
    1. 数组元素的key(Bucket.key)指向zend_string。
    1. 数组元素的value被嵌入到Bucket中。
    1. 降低CPU Cache Miss。

函数调用机制(Function Calling Convention

PHP7改进了函数的调用机制,通过优化参数传递的环节,减少了一些指令,提高执行效率。

通过宏定义和内联函数(inline),让编译器提前完成部分工作

PHP7在这方面做了不少的优化,将不少需要在运行阶段要执行的工作,放到了编译阶段。
例如参数类型的判断(Parameters Parsing),
因为这里涉及的都是固定的字符常量,因此,可以放到到编译阶段来完成,进而提升后续的执行效率。

ASTAbstract Syntax Tree,抽象语法树)

AST在PHP编译过程作为一个中间件的角色,替换原来直接从解释器吐出opcode的方式,
让解释器(parser)和编译器(compliler)解耦,可以减少一些Hack代码,同时,让实现更容易理解和可维护。

PHP7

TLSNative Thread local storage,原生线程本地存储)

PHP在多线程模式下(例如,Web服务器Apache的woker和event模式,就是多线程),
需要解决“线程安全”(TS,Thread Safe)的问题,因为线程是共享进程的内存空间的,
所以每个线程本身需要通过某种方式,构建私有的空间来保存自己的私有数据,避免和其他线程相互污染。
而PHP5采用的方式,就是维护一个全局大数组,为每一个线程分配一份独立的存储空间,
线程通过各自拥有的key值来访问这个全局数据组。

而这个独有的key值在PHP5中需要传递给每一个需要用到全局变量的函数,
PHP7认为这种传递的方式并不友好,并且存在一些问题。
因而,尝试采用一个全局的线程特定变量来保存这个key值。

参考

Powered by Hexo and Hexo-theme-hiker

Copyright © 2017 - 2023 Keep It Simple And Stupid All Rights Reserved.

访客数 : | 访问量 :