PHP 7 类型提示
来聊聊 PHP 的好味道之一——PHP 7 类型提示。
PHP 7 之前的类型提示
PHP 5.0 首次提出函数参数(只针对对象类型)的类型提示(Type Hint),之后 PHP 5.1 进一步扩展到可针对数组类型。举例如下:
<?php
class Person
{
public $name;
public $id;
function __construct($name, $id) {
$this->name = $name;
$this->id = $id;
}
}
$person = new Person("Tom", 101);
function printPerson(Person $person) {
echo "Name: ", $person->name, ", ID: ", $person->id, ".";
}
printPerson($person);
$skills = ["PHP 7", "C++", "Java", "Golang", "Python"]; // PHP 5.4 起可以使用数组定义短语法
function printSkills(array $skills) {
foreach ($skills as $skill) {
echo $skill, "\n";
}
}
printSkills($skills);
运行结果如下图所示:
而时光到了 PHP 7,类型提示的增强则更进了一步。
PHP 7 的标量参数类型提示
PHP 7 增加了对标量参数类型的支持:
- int
- float
- string
- bool
举例如下:
// Scalar Type Hints
function printRecord(string $name, int $id, float $salary, bool $sex) {
echo $sex ? "$name, $id, $salary, male." : "$name, $id, $salary, female.";
}
printRecord("Tom", 101, 5650.00, TRUE);
printRecord("Suzy", 101, 5650.00, FALSE);
运行结果如下图所示:
PHP 7 的函数/方法返回值类型提示
PHP 7还支持了函数/方法返回值类型提示。举例如下:
function getRecord(string $name, int $id, float $salary, bool $sex) : string {
return $sex ? "$name, $id, $salary, male." : "$name, $id, $salary, female.";
}
getRecord("Tom", 101, 5650.00, TRUE);
结果如下图所示:
return的返回类型提示,跟 PHPDoc 的 @return 注解是完全不同的两个方面,@return 只是“好言规劝”或向IDE“友好反馈”返回类型应该是什么,而对于实际的返回类型不具约束力。return的返回类型提示则具有对返回类型的运行时强制约束力——具体有待后续进一步阐述,稍安勿躁。
类型提示特性中其他一些问题点
如果函数参数或返回值是对象咋办呢?进一步来说,类型提示涉及父类继承或接口实现时,又是怎样一种表现呢?让我们继续前进的脚步吧。
interface iFoo {}
class Foo implements iFoo {}
class Bar extends Foo {}
function coo(iFoo $foo) : iFoo {
return $foo;
}
coo(new Foo());
coo(new Bar());
function gaa(Foo $foo) : iFoo {
return $foo;
}
gaa(new Foo());
gaa(new Bar());
function zii(Bar $bar) : Foo {
return $bar;
}
zii(new Foo()); // TypeError: Argument 1 passed to zii() must be an instance of Bar, instance of Foo given on line 1
zii(new Bar());
综上,上代码看得最清楚,不太想多花笔墨了。
严格类型约束
还有一个很重要的特性——严格类型约束——declare(strict_types=1);
不妨来看看:
function xii(array $a, string $s) : int {
print_r($a);
echo $s, "\n";
return "101";
}
xii([1, 2, 3, 4, 5, 6, 7, 8], 101);
xii(101, 102); // TypeError: Argument 1 passed to xii() must be of the type array, integer given on line 1
对于标量类型提示,我们的参数也罢、返回值也罢,其类型跟类型提示不一致也不影响程序运行(注:对象及数组类型具备约束力,注意区别)。这可能不是我们想要的。解决办法就是在 PHP 脚本文件的第一条语句的位置放上:declare(strict_types=1);。这是个文件级别的指令,同时不影响其他包含文件——主要是考虑向后兼容及不影响各类扩展、内建代码。
按要求加上 declare(strict_types=1); 指令之后,运行下图代码就会报错:
小结
可见 PHP 的类型提示是个非常棒的功能!在不失弱类型语言方便、灵活特点的前提下,提供了一种运行时保护措施,有助于团队协作,无疑在灵活性与规范化之间取得了巧妙平衡。这是一种浓浓的好味道,那些黑 PHP 的人,大概是不会懂的。让 PHP 走自己的路,春风十里,都不如 PHP!
顺带说说,PHP 的类型提示,可比截至当前 Python 3.6 中的类型提示强太多了,Python 3.6 中的类型提示充其量只是“好言规劝”或向IDE“友好反馈”类型应该是什么。
PHP还有很多好味道,后续有兴致时考虑逐一道来。