这篇文章大部分引用了AST的RFC文档。
我的官方小组点击这里。
本文不告诉你抽象语法树是什么。 这需要自己理解。 这里介绍了AST给PHP带来的一些变化。
新的执行过程
PHP7内核有一个重要的变化,就是内置了AST。 在php5中,从PHP脚本到opcodes的执行过程如下:
1、Lexing :词法扫描分析,将源文件转换为token流;
2、Parsing :语法分析,在此阶段生成op arrays。
3、由于PHP7在语法分析阶段不是直接生成op arrays,而是AST,所以流程进一步增加:
4、Lexing )词法扫描分析,将源文件转换为token流;
5、Parsing :语法分析,token流生成抽象语法树;
6、Compilation :由抽象语法树生成op arrays。
运行时间和内存消耗
根据以上步骤,这比上一个进程多了一步,所以从常识上来说,程序的运行时间和内存使用量会增加。 然而,实际上内存使用量在增加,但执行时间却在下降。
以下结果分别使用小(代码约100行)、中(约700行)、大(约2800行)三个脚本进行了测试,对脚本进行了测试。
每个文件编译100次的运行时间(注意文章测试时间为14年,PHP7有时也称为PHP-NG ) :
每个文件编译100次的运行时间(注意文章测试时间为14年,PHP7有时也称为PHP-NG ) :
单编译时的内存峰值:
一次编译的测试结果可能不代表实际使用情况。 使用PhpParser进行完全项目测试的结果如下所示。
测试表明,使用AST后程序的运行时间总体上提高了约10%到15%,但内存消耗也有所增加,在大文件的单次编译中明显增加,但在项目运行中并没有那么严重。
请注意,以上所有结果都是没有Opcache的情况,并且在生产环境中打开Opcache时,内存消耗增加也不是什么大问题。
意义的变化
光靠时间上的优化似乎不是使用AST的充分理由。 其实实现AST不是为了时间优化上的考虑,而是为了解决语法上的问题。 看看意义上的变化吧。
yield不需要括号
在PHP5实现中,如果在表达式上下文(例如赋值表达式的右侧)中使用yield,则必须在智能冰淇淋的两侧使用括号。
$result=yield fn (; //不合法
$result=(yieldfn ) ); //合法的
这只是PHP5实现方式的限制,在PHP7中不再需要括号。 所以以下写法也是合法的:
$result=yield;
$result=yield $v;
$result=yield $k=$v;
当然,必须遵循颐指气使的应用场景。
括号不影响动作
在PHP5中,$foo['bar']='baz '和$foo['bar']='baz '两个语句的含义不同。 前者的写法不合法。 可以得到以下错误。
($foo ) ) ) bar )=) baz );
# PHP Parse error: Syntax error,unexpected ' [ '在线1
但是,在PHP7中,两种写法表示相同的意思。
同样,如果函数的参数括在括号中,则类型检查有问题。 PHP7也解决了这个问题。
函数函数
返回[ ];
}
function ByRef (阵列$ a ) {
}
byref () ) func ) );
除非在byref(func ) )中调用上述代码,否则PHP5不会发出警告。 但是,在PHP7中,无论func ) )两侧是否有括号,都会出现以下错误:
phpstrictstandards 3360 onlyvariablesshouldbepassedbyreference .
list ()变化
list关键词的行为发生了很大的变化。 list为变量赋值的顺序(等号左右同时的顺序)以前是从右到左,现在是从左到右:
list($array[]、$array[]、$ array [ ]=[ 1,2,3 ];
var_dump($array;
//PHP 5: $ array=[ 3,2,1 ]
//PHP7: $a
rray = [1, 2, 3]# 注意这里的左右的顺序指的是等号左右同时的顺序,
# list($a, $b) = [1, 2] 这种使用中 $a == 1, $b == 2 是没有疑问的。
产生上面变化的原因正是因为在 PHP5 的赋值过程中,3 会最先被填入数组,1 最后,但是现在顺序改变了。
同样的变化还有:
$a = [1, 2];
list($a, $b) = $a;
// PHP5: $a = 1, $b = 2
// PHP7: $a = 1, $b = null + "Undefined index 1"
这是因为在以前的赋值过程中 $b 先得到 2,然后 $a 的值才变成 1,但是现在 $a 先变成了 1,不再是数组,所以 $b 就成了 null。
list 现在只会访问每个偏移量一次:
list(list($a, $b)) = $array;
// PHP5:
$b = $array[0][1];
$a = $array[0][0];
// PHP7:
// 会产生一个中间变量,得到 $array[0] 的值
$_tmp = $array[0];
$a = $_tmp[0];
$b = $_tmp[1];
空的 list 成员现在是全部禁止的,以前只是在某些情况下:
list() = $a; // 不合法
list($b, list()) = $a; // 不合法
foreach ($a as list()) // 不合法 (PHP5 中也不合法)
引用赋值的顺序
引用赋值的顺序在 PHP5 中是从右到左的,现在时从左到右:
$obj = new stdClass;
$obj->a = &$obj->b;
$obj->b = 1;
var_dump($obj);
// PHP5:
object(stdClass)#1 (2) {
["b"] => &int(1)
["a"] => &int(1)
}
// PHP7:
object(stdClass)#1 (2) {
["a"] => &int(1)
["b"] => &int(1)
}
__clone 方法可以直接调用
现在可以直接使用 $obj->__clone() 的写法去调用 __clone 方法。__clone 是之前唯一一个被禁止直接调用的魔术方法,之前你会得到一个这样的错误:
Fatal error: Cannot call __clone() method on objects - use 'clone $obj' instead in ...
变量语法一致性
在新的实现上,以前的一些语法表达的含义和现在有些不同,具体的可以参照下面的表格:
整体上还是以前的顺序是从右到左,现在从左到右,同时也遵循括号不影响行为的原则。这些复杂的变量写法是在实际开发中需要注意的。
更多学习内容请访问:八重樱:腾讯T3-T4标准精品PHP架构师教程目录大全,只要你看完保证薪资上升一个台阶(持续更新)zhuanlan.zhihu.com
以上内容希望帮助到大家,很多PHPer在进阶的时候总会遇到一些问题和瓶颈,业务代码写多了没有方向感,不知道该从那里入手去提升,对此我整理了一些资料,包括但不限于:分布式架构、高可扩展、高性能、高并发、服务器性能调优、TP6,laravel,YII2,Redis,Swoole、Swoft、Kafka、Mysql优化、shell脚本、Docker、微服务、Nginx等多个知识点高级进阶干货需要的可以免费分享给大家,需要的可以加入我的官方群点击此处。