从PHP7出来之后,对于PHP而言,是一个巨大的提升,虽然很多项目还是使用PHP5.6甚至更老的版本,但是作为一个技术人员来说,需要永远的去了解最新的技术和知识,学无止境。
PHP7.0-PHP7.2的变化
PHP7.0
??运算符
$foo = null;
$bar = $foo ?? 123;
// 相当于 $bar = isset($bar) ? $bar : 123
组合比较符
二者相等时返回 0;
前者大于后者返回 1;
后者大于前者返回 -1;
var_dump('PHP' <=> 'Node'); // int(1)
var_dump(123 <=> 456); // int(-1)
var_dump(['a', 'b'] <=> ['a', 'b']); // int(0)
// 注意,字符串在与数字比较时会被当作 0;
指定函数参数、返回值类型
PHP7中可以指定函数参数及返回值的类型。
原因:为了PHP7版本JIT特性做准备,增加类型之后PHP, JIT可以准确判断变量类型,生成最佳的机器指令。
function test (int $a, string $b, array $c) :int {
// code
}
匿名类
php7允许new class {} 创建一个匿名的对象。
//php7以前
class Logger
{
public function log($msg)
{
echo $msg;
}
}
$util->setLogger(new Logger());
// php7+
$util->setLogger(new class {
public function log($msg)
{
echo $msg;
}
});
命名空间按组导入
从同一个命名空间下导入的类、函数、常量支持按组一次导入
#php7以前
use app\model\A;
use app\model\B;
#php7+
use app\model{A,B}
新增整数整除的函数intdiv()
var_dump(intdiv(10, 3))
// 输出 int(3)
define支持定义数组
#php7+
define('ALLOWED_IMAGE_EXTENSIONS', ['jpg', 'jpeg', 'gif', 'png']);
随机数、随机字符函数
string random_bytes(int length);
int random_int(int min, int max);
带过滤的unserialize
提供更安全的方式解包不可靠的数据。它通过白名单的方式来防止潜在的代码注入
// 将所有的对象都转换为 __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]);
List
list 会按照原来的顺序进行赋值。不再是逆序了
list($a,$b,$c) = [1,2,3];
var_dump($a);//1
var_dump($b);//2
var_dump($c);//3
异常处理
PHP5.x 中很多操作会直接抛出 error 错误,PHP7 中将多数错误改为了异常抛出,这样一来就可以通过 try catch 捕捉到。
try {
no_func();
} catch (EngineException $e) {
echo "Exception: {$e->getMessage()}\n";
}
PHP7.1
多异常捕获处理
一个catch语句块现在可以通过管道字符(|)来实现多个异常的捕获。 这对于需要同时处理来自不同类的不同异常时很有用
try {
// some code
} catch (FirstException | SecondException $e) {
// handle first and second exceptions
}
可为空(Nullable)类型
参数以及返回值的类型现在可以通过在类型前加上一个问号使之允许为空。当启用这个特性时,传入的参数或者函数返回的结果要么是给定的类型,要么是null
#php5
function($a = null){
if($a===null) {
return null;
}
return $a;
}
#php7+
function fun() :?string
{
return null;
}
function fun1(?$a)
{
var_dump($a);
}
fun1(null);//null
fun1('1');//1
类常量可见性
class Something
{
const PUBLIC_CONST_A = 1;
public const PUBLIC_CONST_B = 2;
protected const PROTECTED_CONST = 3;
private const PRIVATE_CONST = 4;
}
list支持键名
$data = [
["id" => 1, "name" => 'Tom'],
["id" => 2, "name" => 'Fred'],
];
// list() style
list("id" => $id1, "name" => $name1) = $data[0];
var_dump($id1);//1
字符串支持负向
$a= "hello";
$a[-2];//l
传递参数过少时将抛出错误
过去我们传递参数过少 会产生warning。php7.1开始会抛出error
PHP7.2
增加新的类型object
function test(object $obj) : object
{
return new SplQueue();
}
test(new StdClass());
通过名称加载扩展
扩展文件不再需要通过文件加载 (Unix下以.so为文件扩展名,在Windows下以 .dll 为文件扩展名) 进行指定。可以在php.ini配置文件进行启用
; ini file
extension=php-ast
zend_extension=opcache
允许重写抽象方法
当一个抽象类继承于另外一个抽象类的时候,继承后的抽象类可以重写被继承的抽象类的抽象方法。
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;
}
命名分组命名空间支持尾部逗号
use Foo\Bar\{
Foo,
Bar,
Baz,
};
number_format 返回值
var_dump(number_format(-0.01)); // now outputs string(1) "0" instead of string(2) "-0"
each 被废弃
使用此函数遍历时,比普通的 foreach 更慢, 并且给新语法的变化带来实现问题。因此它被废弃了。
__autoload 被废弃
PHP新特性总结
抽象语法树
在PHP之前的版本中,PHP代码在语法解析阶段直接生成了 ZendVM 指令,也就是在 zend_language_parser.y 中直接生成 opline 指令,这使得编译器与执行器耦合在一起。
PHP7 中增加了抽象语法树,首先是将PHP代码解析生成抽象语法树,然后将抽象语法树编译为 ZendVM 指令。抽象语法树的加入使得 PHP 的编译器与执行器很好地隔离开,编译器不需要关心指令的生成规则,然后执行器根据自己的规则将抽象语法树编译为对应的指令,执行器同样不需要关心该指令的语法规则是什么样子的。
Native TLS
PHP7 中使用 Native TLS(线程局部存储)来保存线程的资源池,简单地讲就是通过 __thread 标识一个全局变量,这样这个全局变量就是线程独享的了,不同线程的修改不会相互影响。
zval 结构的变化
PHP7 将引用计数转移到了具体的 value 中,这样更合理。除此之外,zval 结构的大小也从 24byte 少到了 16byte,这是 PHP7 能够降低系统资源占用的一个优化点所在。
之前的PHP版本都是通过MAKE_STD_ZVAL动态的从堆上分配一个zval内存。而PHP7可以直接使用栈内存。
PHP5
zval *val; MAKE_STD_ZVAL(val);
PHP7
zval val;
HashTable 的变化
PHP7 中 HashTable 有非常大的变化,HashTable 结构的大小从 72byte 减小到了 56byte,同时,数组元素 Bucket 结构也从 72byte 减小到了 32byte。
执行器
在 PHP7 中不再采用传参的方式,而是将 execute_data、opline 通过寄存器来进行存储,避免了传参导致的频繁出入栈操作,同时,寄存器相比内存的访问速度更快。
新的参数解析方式
PHP5.x 通过 zend_parse_parameters() 解析函数的参数,PHP7 提供了另外一种方式,同时保留了原来的方式,但是新的解析方式速度更快。
为什么 PHP7 比 PHP5 性能提升了?
1、变量存储字节减小,减少内存占用,提升变量操作速度
2、改善数组结构,数组元素和hash映射表被分配在同一块内存里,降低了内存占用、提升了 cpu 缓存命中率
3、改进了函数的调用机制,通过优化参数传递的环节,减少了一些指令,提高执行效率