PHP界最近最热门的消息就是:PHP 7已经来临!Sitepoint的Bruno适时地写了一篇文章,列出了一些资源和回顾。 我用百度搜索了一下国内的相关内容,发现相关的讨论还是非常非常少。所以觉得有必要结合我的实践,写点东西,以求推动国内的PHP7的落地。
安装
PHP创始人Rasmus Lerdorf弄了一个PHP 7的Vagrant盒子,供大家下载尝鲜使用PHP 7。其Github的地址:https://github.com/rlerdorf/php7dev。安装过程应该说很简单的,大家可以参照仓库里的指引。
有一个需要提示的地方。我相信很多人和我一样,是用Vagrant+VirtualBox的方式来安装虚拟机的。如果vagrant up这个PHP 7的虚拟机时出现问题,可以通过在VirtualBox中直接启动这个盒子的手段帮助解决。VB中的启动会给出更多、更详细的出错信息。我也是通过这个方法解决了这个盒子无法启动的问题:需要禁用这个虚拟机的USB 2.0功能。
安装完成并启动后,可以通过Putty登录到虚拟机中,进行一次apt-get的更新,然后用php -v检验:
或者用浏览器访问这个虚拟机,会得到一个标准的PHP信息页面:
在这篇名为What to Expect的文章中,作者Davey Shafik列出了一些PHP7的重要特点。
首先提到的是抽象语法树(Abstract Syntax Tree,简称AST),它将取代目前直接从解析器里产生操作代码的做法。
将解析器和编译器分离将允许我们取消众多黑客手段,而且允许实现仅靠一次过编译(single-pass compilation)无法实现的语法特性。
第一,解析器和编译器将更易于维护。
第二,将语法确定与技术问题分开。在目前的处理中,有些语法元素非常难以实现——如果不是不可能的话。比如对yield表达式的限制: $result = yield fn(); //不合法$result = (yield fn()); //合法
另外,当前的编译器结构不允许我们实现某些类型的语法。比如:
- 数组解构:
[$a, $b, $c]=$array,而不需要使用一个特定的list()语法。 - 结果表达式在前的列表推导和生成子表达式,例如Python中的
[x * x for x in list]。目前的PHP中,只支持反过来的语法:foreach ($list as $x) yield $x*$x。 - C#类型的表达式树和LINQ。
AST对运行时的性能或者内存占用只有很少的影响。但是确实影响了编译过程中的性能和内存使用。但需要强调的是,这样的差别只在不使用opcode cache的时候才存在。
PHP的官方Wiki中给出了一个对照表,针对不同大小的PHP文件各编译1000次的时间差异:
| 文件 | 7之前 | 7 | 提升 |
|---|---|---|---|
| 小(100行) | 0.180s | 0.160s | -12.5% |
| 中(700行) | 1.492s | 1.268s | -17.7% |
| 大(2800行) | 6.703s | 5.736s | -16.9% |
和峰值内存使用:
| 文件 | 7之前 | 7 | 增加 |
|---|---|---|---|
| 小(100行) | 378K | 414K | +9.5% |
| 中(700行) | 507K | 643K | +26.8% |
| 大(2800行) | 1084K | 1857K | +71.3% |
还有一个编译PhpParser项目的实例。总体而言,AST要快10%-15%,但需要更多的内存。多用多少内存取决于文件大小。小文件只要多用10%,而大文件需要多用70%以上。在比较实际的情形中,内存差异在5%左右。
最后谈到了语法和行为的改变。
yield不用括号了。以下语法都是对的:
$result = yield;
$result = yield $v;
$result = yield $k => $v;
括号不影响行为:一个问题是($foo)['bar']='baz'和$foo['bar']='baz'表现出的行为不同。与之类似的还有byRef(func())和byRef((func()))现在都会抛出一个严格标准下的需注意情况(如果byRef引用其参数,而func并不返回引用变量)。对list()的改变目前list()赋值是从右到左。在AST下,将是从左到右。
list($array[], $array[], $array[]) = [1, 2, 3];
var_dump($array);
// OLD: $array = [3, 2, 1]
// NEW: $array = [1, 2, 3]
另一个赋值顺序有关系的例子是,列表赋值的左边和右边是不是用一个变量:
$a = [1, 2];
list($a, $b) = $a;
// OLD: $a = 1, $b = 2
// NEW: $a = 1, $b = null + Undefined index 1
$b = [1, 2];
list($a, $b) = $b;
// OLD: $a = null + Undefined index 0, $b = 2
// NEW: $a = 1, $b = 2
现在的list()将只存取一个偏移量一次:
list(list($a, $b)) = $array;
// OLD:
$b = $array[0][1];
$a = $array[0][0];
// NEW:
$_tmp = $array[0];
$a = $_tmp[0];
$b = $_tmp[1];
空的list()现在不被允许了。
按引用赋值的自动赋值顺序AST中将调整为从左到右
$obj = new stdClass;
$obj->a = &$obj->b;
$obj->b = 1;
var_dump($obj);
// OLD:
object(stdClass)#1 (2) {
[b]=>
&int(1)
[a]=>
&int(1)
}
// NEW:
object(stdClass)#1 (2) {
[a]=>
&int(1)
[b]=>
&int(1)
}
允许直接调用__clone现在可以进行类似$obj->__clone()这样的调用。(未完待续)
本文收录于[go4pro.org]


Leave a Reply