php7杂谈

虽然php7在2015年未的时候已经正式发布了,但自己目前所经历过的两家公司都是用着5.x版本,不过,php7注定是未来的主流,最近自己也是开始关注这块,所以写下这篇博客来记录一些自己的理解和思考。

升级到php7

php7虽然做了大量的改动过,但同时也做了很多向下兼容的工作,所以升级到php7是没有太大问题的,当然其中也包括一些不兼容的点,具体可以参考这篇文章。我总体看了一遍,有些不兼容的改动基本是很“冷门”的,可能这个关于foreach的修改要特别注意一下:

1
2
3
4
5
// foreach的修改
$arr = [1, 2, 3];
foreach($arr as &$i) {
var_dump(current($i)); // php7输出1 1 1 php7之前输出2 3 false
}

php7的foreach遍历将不再改变数组的内部指针,所以如果以前的代码有在foreach中使用current得到遍历的下一个元素的,在升级之前需要重构掉代码。

php7新特性

关于php7新特性的介绍,可以参考官网的说明文档。总体而言,这次php7的升级重点并不是在语言特性上,所以语法糖并不多,相对而言也没有太多亮点的地方。

标量类型声明和返回类型声明

1
2
3
4
5
6
7
// 新增参数类型支持int、float、string和bool
function (int $i) {
}
// 返回类型支持
function (): array {
return [];
}

php是弱类型语言,弱类型语言向来被人诟病的其中一点是缺少“解析前检查”。函数的传参没有类型约束,意味着传入什么东西都可以被接受,直到了运行期问题才会被抛出,这很让人无能为力。
php7无疑强化了关于类型的输入和输出,语言也渐渐地严谨化和与强类型挂钩,这样带来的好处就是可以让问题暴露在解析前,让开发者能更早地知道代码的错误之处。我个人认为严谨化和强类型是未来语言发展的重要方向,宽松化和容错性高注定是要立下墓碑,所以php7的这个特性还是很切合时代的发展的。

null合并运算符

1
2
3
4
// php7之前的写法
$a = isset($_POST['a']) ? $_POST['a'] : 0;
// php7的写法
$a = $_POST['a'] ?? 0;

这个语法糖应该是php7所有新语法中最实用的。之前的代码确实存在太多isset加三目表达式的写法,新语法要节省多少敲击键盘的次数啊,“人生苦短,敲少代码”把。

组合运算符<=>

1
2
3
echo 1 <=> 1; // 0
echo 1 <=> 2; // -1
echo 2 <=> 1; // 1

这次推出了新的运算符<=>,现在我能想到的一个应用场景就是在数组排序中使用:

1
2
3
4
5
6
7
8
// php7之前的写法
usort($arr, function ($x, $y) {
return $x - $y;
});
// php7的写法
usort($arr, function ($x, $y) {
return $x <=> $y;
});

php7之前的写法基本也能满足,新特性并没有带来很好的体验提升,个人认为这个特性或许没有那么“必须”。

匿名类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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;
}
});

通过new class来实例化一个匿名类,适用于替代一些“用后即焚”的完整类定义。当我看到这个的时候,第一反映是这个特性与单元测试的结合。我们知道单元测试强调快速运行,假如方法中存在调用服务类的地方,需要将服务类接口化并mock一个空实现,传统的实现就要定义一个空实现的类,而有了匿名类,就可以节省这个类,同时还可以支持不同的个性化需求。

通过define定义常量为数组类型

1
2
3
4
5
6
// php7的实现
define('ORDER', ['unpay' => 1, 'pay' => 2]);
echo ORDER['unpay'];
// php7之前的替代实现
define('ORDER_UNPAY', 1);
define('ORDER_PAY', 2);

php7之前的常量定义只能未int、float、string和bool值,现在就多了一个数组,可以将关联的元素集中化,以前的替代实现就需要数组的每个元素都定义为一个常量,现在就会方便一些。

使用use导入一组类

1
2
3
4
5
// php7之前的写法
use common\helper\A;
use common\helper\B as Be;
// php7的写法
use common\helper\{A, B as Be};

这个语法糖简化了导入同一个命名空间下类的写法,但我认为还是比较麻烦,需要指定具体的类,而不是像java那样直接导入命名空间,在代码中用到的类自动识别到命名空间中,不知未来php是否会往这个方向上靠。