PHP 7

PHP 7.0是一个大版本,增加了一些比较显著的新特性,相较于前面版本,速度也有很大的提升。

以下示例不输出结果,请小伙伴们自行敲打,实践出真知。

标量参数类型提示(Scalar type hints)

Type hints并不是什么新生事物,在PHP 5就已经引入,在PHP 7中增加了4个scalar type:

  • bool: true/false
  • float: 表示浮点数类型
  • int: 表示整数类型
  • string: 表示字符串类型
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
<?php
/**
 * Scalar type declarations
 */

//declare(strict_types=1);
function add(int $a, int $b) {
    return $a + $b;
}

var_dump(add(1,2));
var_dump(add("1","2"));	// 若开启严格模式,会抛出类型错误异常

定义返回值类型(Return type declarations)

type hints确保输入类型一致性,返回值类型保证了返回类型的一致性。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
<?php
/**
 * Return type declarations
 */

//declare(strict_types=1);
function add(int $a, int $b): int{
    return (string)($a + $b);
}

var_dump(add(1,2));

匿名类(Anonymous classes)

匿名类是不能有名字的类,它们不能被引用,只能在创建时用New语句来声明它们。 正因为没有名字,所以匿名内部类只能使用一次,它通常用来简化代码编写。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
<?php
/**
 * Anonymous classes
 */

$foo = new class {
    public function foo() {
        return "bar";
    }
};

var_dump($foo,$foo->foo());

闭包函数(Closures)

匿名函数(Anonymous functions),也叫闭包函数(closures),允许 临时创建一个没有指定名称的函数。最经常用作回调函数(callback)参数的值。

以下例子给出了PHP 5与PHP 7的不同写法

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
<?php
/**
 * Closure::call()
 */

class Foo
{
    private $foo = 'bar';
}

$getFooCallback = function() {
    return $this->foo;
};

//PHP5 style
$binding = $getFooCallback->bindTo(new Foo,'Foo');
echo $binding().PHP_EOL;

//PHP7 style
echo $getFooCallback->call(new Foo).PHP_EOL;

生成器委托(Generator Delegation)

官方文档的描述:

PHP7中,通过生成器委托(yield from),可以将其他生成器、可迭代的对象、数组委托给外层生成器。外层的生成器会先顺序 yield 委托出来的值,然后继续 yield 本身中定义的值。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
<?php
/**
 * Generator delegation
 */

function gen()
{
    yield 1;
    yield 2;
    yield from gen2();
}

function gen2()
{
    yield 3;
    yield 4;
}

foreach (gen() as $val)
{
    echo $val, PHP_EOL;
}

生成器是PHP的性能优化利器,以后有机会单独出一篇来讲解。

空合并运算符(Null Coalesce Operator)

用于与isset()函数一起替换三元运算。该空如果它存在,而不是空合并运算符返回第一个操作数; 否则返回第二个操作数。

符号为两个英文问号(??)。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
<?php
/**
 * Null coalesce operator
 */

$array = ['foo'=>'bar'];

//PHP5 style
$message = isset($array['foo']) ? $array['foo'] : 'not set';
echo $message.PHP_EOL;

//PHP7 style
$message = $array['foo'] ?? 'not set';
echo $message.PHP_EOL;

宇宙飞船操作符(Space Ship Operator)

听起来很高科技的样子,“宇宙飞船操作符”使得比较两个值更加容易。相对于返回典型的true或false值,“宇宙飞船操作符”通过比较两个值的结果返回以下数值:

  • 0 当两个值相同时
  • -1 当左值比右值小时
  • 1 当左值比右值大时
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
<?php
/**
 * Space ship operator
 */

$array = [
    "1 <=> 1" => 1 <=> 1,
    "1 <=> 2" =>1 <=> 2,
    "2 <=> 1" => 2 <=> 1
];

var_dump($array);

Throwables

在PHP7之前,异常可以被捕获,但是错误是不能被捕获的。从PHP7开始,任何完整程序或一部分程序中的Fatal错误都可以被捕获。

为了更好的捕获诸多错误(大多数的 Fatal 错误),PHP7 提供了 throwable 接口,异常与错误都继承于这个接口。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
<?php
/**
 * Throwable interface
 */


//Error as Throwable
try {
    sqdf();
} catch (Throwable $t) {
    echo "Throwable: ".$t->getMessage().PHP_EOL;
}

//Exception as Throwable
try {
    throw new Exception("Bla");
} catch (Throwable $t) {
    echo "Throwable: ".$t->getMessage().PHP_EOL;
}

//Error
try {
    sqdf();
} catch (Error $e) {
    echo "Error: ".$e->getMessage().PHP_EOL;
} catch (Exception $e) {
    echo "Exception: ".$e->getMessage().PHP_EOL;
}

//Exception
try {
    throw new Exception("Bla");
} catch (Error $e) {
    echo "Error: ".$e->getMessage().PHP_EOL;
} catch (Exception $e) {
    echo "Exception: ".$e->getMessage().PHP_EOL;
}

//Type error
try {
    function add(int $a, int $b):int {
        return $a + $b;
    }
    echo add(array(), array());
} catch (TypeError $t) {
    echo "Type error: ".$t->getMessage().PHP_EOL;
}

dirname函数支持层数

PHP7 dirname()接受第2个参数(默认为1)来指定向上层级,方便向上更多层。

1
2
3
4
5
6
7
8
9
<?php
/**
 * Dirname levels
 */

echo dirname('/usr/local/bin').PHP_EOL;
echo dirname('/usr/local/bin',1).PHP_EOL;
echo dirname('/usr/local/bin',2).PHP_EOL;
echo dirname('/usr/local/bin',3).PHP_EOL;

整数除法(intdiv)

intdiv() 函数,接收两个参数,返回值为第一个参数除于第二个参数的值并取整。

1
2
3
4
5
6
7
8
9
<?php
/**
 * Integer division
 */

var_dump(
    intdiv(10, 3),
    (10/3)
);

统一变量语法(Uniform Variable Syntax)

PHP 7采取的Uniform方案就是

统一采用从左到右的方式来评估表达式

用一个表格来举例说明:

Express PHP 5 interpretation PHP 7 interpretation
$$foo[‘bar’][‘baz’] ${$foo[‘bar’][‘baz’]} ($$foo)[‘bar’][‘baz’]
$foo->$bar[‘baz’] $foo->{$bar[‘baz’]} ($foo->$bar)[‘baz’]
$foo->$bar[‘baz’] $foo->{$bar[‘baz’]} ($foo->$bar)[‘baz’]
$foo->$bar[‘baz’]() $foo->{$bar[‘baz’]}() ($foo->$bar)[‘baz’]()
Foo::$bar[‘baz’]() Foo::{$bar[‘baz’]}() (Foo::$bar)[‘baz’]()

性能

为什么PHP7的性能可以提高这么多?

  1. JIT
  2. Zval的改变
  3. 内部类型zend_string
  4. PHP数组的变化(HashTable和Zend Array)
  5. 函数调用机制(Function Calling Convention)
  6. 通过宏定义和内联函数(inline),让编译器提前完成部分工作