PHP 7 类型提示
2017.07.04 17:54:33

来聊聊 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还有很多好味道,后续有兴致时考虑逐一道来。


(1)
评论(1条)

Jack.W 2017.08.12 18:34

学到一点

1


发表评论请先登录或注册