文档结构  
原作者:未知 (2016-12-08)    来源:SitePoint [英文]
中山狼    计算机    2016-12-10    0评/1627阅
翻译进度:已翻译   参与翻译: CY2 (6), 中国码农 (2), itsmikej (2), 中山狼 (1), coyee (1)

PHP 社区刚刚发布了最新的 PHP 7.1 版本,该版本在语言方面带来了诸多新特性。本文向你介绍其中最重要的一些新特性介绍,更详细的列表可阅读 PHP RFC

Flying baloon-tied elephpant

ArgumentCountError 异常

早期的 PHP 版本允许函数调用时,传递的参数少于函数定义本身要求的参数个数。当你调用函数时就会抛出一个参数丢失的警告。

// PHP 5.6

function sum($a, $b)
{
    return $a + $b;
}

sum(); 
// Warning: Missing argument 1 for sum()
// Warning: Missing argument 2 for sum()

sum(3);
// Warning: Missing argument 2 for sum()

sum(3, 4);
第 1 段(可获 0.94 积分)

在这种情况下警告没什么用,开发者必须自行检查参数是否正确。在 PHP 7.1 中,这些警告变成了一个 ArgumentCountError 的异常:

// PHP 7.1

function sum($a, $b)
{
    return $a + $b;
}

sum(); 
// Fatal error: Uncaught ArgumentCountError: Too few arguments to function sum(), 0 passed in /vagrant/index.php on line 18 and exactly 2 expected in /vagrant/index.php:13

sum(3); // skipped

sum(3, 4); // skipped 

可空类型 Nullable Types

PHP 7 增加了参数和返回值的类型定义,但是似乎还少了点什么。而 Nullable 类型可以指定类型或者为空,例如:

第 2 段(可获 0.84 积分)
function sum(int $a, int $b): ?int
{
    return $a + $b;
}

上述函数中将返回一个整数或者是空值,如果函数逻辑发生错误,你将不会返回错误类型的空值。函数的参数也可以这么玩:

function sum(?int $a, ?int $b): ?int
{
    if ($a == null || $b == null) {
        return null;
    }

    return $a + $b;
}

一种不在预期的情况是当调用此函数并不传递任意参数时将会抛出异常!

var_dump(sum(null, null)); // NULL
var_dump(sum()); // throw ArgumentCountError exception
第 3 段(可获 0.66 积分)

这意味着你必须显式的指定参数值,因为这些参数没有默认值。

你还需要记住另外一种情况是,当重写或者实现方法时,返回对象类型不能是允许为空的类型,但你可以删掉它。而参数则刚好相反,你不能删除参数中允许为空的类型,但允许添加!

interface Fooable {
    function foo(): ?Fooable;
}
interface StrictFooable extends Fooable {
    function foo(): Fooable; // valid
}

interface Fooable {
    function foo(): Fooable;
}
interface LooseFooable extends Fooable {
    function foo(): ?Fooable; // invalid
}
第 4 段(可获 0.89 积分)

读取数组

我们曾经在读取数组时执行以下操作。

list($a, $b, $c) = [1, 2, 3];
var_dump($a, $b, $c); // int(1) int(2) int(3)

但这样的尝试会失败,因为我们不能指定提取的键和函数试图使用索引键

list($a, $b, $c) = ["a" => 1, "b" => 2, "c" => 3];
var_dump($a, $b, $c); // NULL NULL NULL

RFC提供了对数组读取的更多控制。 上面的代码可以改成这样。

list("a" => $a, "b" => $b, "c" => $c) = ["a" => 1, "b" => 2, "c" => 3];
var_dump($a, $b, $c); // int(1) int(2) int(3)
第 5 段(可获 0.6 积分)

列表函数现在接受用于数组解构的键,并且由于使用了很多,所以引入了一种新的紧凑语法。 以此为例。

["a" => $a, "b" => $b, "c" => $c] = ["a" => 1, "b" => 2, "c" => 3];
var_dump($a, $b, $c); // int(1) int(2) int(3)

很酷,不是吗? 它也适用于多维数组。

[[$a, $b], [$c, $d]] = [[1, 2], [3, 4]];
var_dump($a, $b, $c, $d); // int(1) int(2) int(3) int(4)

[["b" => $b], ["c" => $c]] = [["a" => 1, "b" => 2], ["c" => 3, "d" => 4]];
var_dump($b, $c); // int(2) int(3)

可迭代类型

第 6 段(可获 0.5 积分)

iterable 伪类型增加到数组原生类型,同时 Traversable 接口可以让生成一个可迭代的值。请看如下示例代码:

// PHP 5.6

function dump(array $items)
{
    var_dump($items);
}

dump([2, 3, 4]);
dump(new Collection());
array(3) {
  [0]=>
  int(2)
  [1]=>
  int(3)
  [2]=>
  int(4)
}

Catchable fatal error: Argument 1 passed to dump() must be of the type array, object given...

但在这种情况下,函数并不接受一个可迭代的值,所以会抛出一个错误。全新的变化让你可以使用 iterable 来描述一个可迭代的值,而不是手工去对其进行检查。

第 7 段(可获 0.76 积分)
// PHP 7.1

function dump(iterable $items)
{
    var_dump($items);
}

dump([2, 3, 4]);
dump(new Collection());
array(3) {
  [0]=>
  int(2)
  [1]=>
  int(3)
  [2]=>
  int(4)
}
object(Collection)#2 (0) {
}

Closure FromCallable 函数

新的 fromCallable 方法提供一个高效和简洁的方式来创建闭包。请看下面的案例:

$callback = Closure::fromCallable([$this, 'fn']);

Void 返回类型

这是我最爱的特性之一, 它完善了 PHP7 中的返回类型特性,之前如果函数没有返回的话,我们只能强制添加上 return null。

第 8 段(可获 0.73 积分)
function dump($object): void
{
    var_dump($object);
}

返回值为 void 的函数会忽略函数体中的 return 语句或者是增加一个空的返回语句 return ;。

类常量的可见性

这是一个小的变化。但却是面向对象编程中重要的一部分 —— 封装增强。为类的常量增加了可见性的修饰符。

class Post
{
    protected const PUBLISHED = 1;
    protected const DRAFT = 2;
    protected const TRASHED = 3;

    // ...
}

捕获多个异常类型

类似 Java 等其他语言都提供了在同一个 catch 块代码中同事捕获多个异常的做法,这样可以避免不必要的代码重复。请看以下例子:

第 9 段(可获 0.9 积分)
// ...

try {
    $user->payMonth($month);
} catch (UserSuspendedException $ex) {
    DB::rollBack();

    return redirect()
            ->back()
            ->withInput()
            ->withErrors([$ex->getMessage()]);
} catch (PaidMonthException $e) {
    DB::rollBack();

    return redirect()
            ->back()
            ->withInput()
            ->withErrors([$ex->getMessage()]);
}

// ...

你可以通过全新的 catch 块语法来移除重复代码:

// ...

try {
    $user->payMonth($month);
} catch (PaidMonthException | UserSuspendedException $ex) {
    DB::rollBack();

    return redirect()
            ->back()
            ->withInput()
            ->withErrors([$ex->getMessage()]);
}

// ...
第 10 段(可获 0.15 积分)

无效的字符串算法

当你开始学习 PHP 时,在做算术计算时你可能会感到惊喜,因为你知道字符串也可以用来做运算。这是因为 PHP 适合 Web 编程,总是把很多值当成字符串来处理。

// PHP 5.6

var_dump("1" + "2");
var_dump("1" + "a string");
var_dump("1" + "2  with a string");
int(3)
int(1)
int(3)
// PHP 7.1

var_dump("1" + "2");
var_dump("1" + "a string");
var_dump("1" + "2  with a string");
int(3)

Warning: A non-numeric value encountered in /vagrant/index.php on line 17
int(1)

Notice: A non well formed numeric value encountered in /vagrant/index.php on line 18
int(3)
第 11 段(可获 0.49 积分)

非数值类型的值相加会抛出一个 Warning, 未格式化的值相加会抛出一个 Notice (2 a string = 2)。

结语

这篇文章没有覆盖所有的新特性, 完整的变动可以在这里找到 RFC list。 如果你有任何关于 PHP7.1 特性或者是 PHP 的相关问题,请再下面留言。

第 12 段(可获 0.83 积分)

文章评论