跳转至

PHP 7.0.x#

说明

本文部分内容根据官网进行删减,仅整理常用特性。

1. 新特性#

1.1. 标量类型声明#

标量 类型声明 有两种模式: 强制 (默认) 和 严格模式。 现在可以使用下列类型参数(无论用强制模式还是严格模式): 字符串(string), 整数 (int), 浮点数 (float), 以及布尔值 (bool)。它们扩充了PHP5中引入的其他类型:类名,接口,数组和 回调类型。

<?php
// Coercive mode
function sumOfInts(int ...$ints)
{
    return array_sum($ints);
}

var_dump(sumOfInts(2, '3', 4.1));

以上例程会输出:

int(9)

要使用严格模式,一个 declare 声明指令必须放在文件的顶部。这意味着严格声明标量是基于文件可配的。 这个指令不仅影响参数的类型声明,也影响到函数的返回值声明(参见 返回值类型声明, 内置的PHP函数以及扩展中加载的PHP函数)

完整的标量类型声明文档和示例参见类型声明章节。

1.2. 返回值类型声明#

PHP 7 增加了对返回类型声明的支持。 类似于参数类型声明,返回类型声明指明了函数返回值的类型。可用的类型与参数声明中可用的类型相同。

<?php

function arraysSum(array ...$arrays): array
{
    return array_map(function(array $array): int {
        return array_sum($array);
    }, $arrays);
}

print_r(arraysSum([1,2,3], [4,5,6], [7,8,9]));

以上例程会输出:

Array
(
    [0] => 6
    [1] => 15
    [2] => 24
)

完整的标量类型声明文档和示例可参见 返回值类型声明.

1.3. null合并运算符#

由于日常使用中存在大量同时使用三元表达式和 isset() 的情况, 我们添加了 null 合并运算符 (??) 这个语法糖。如果变量存在且值不为 NULL, 它就会返回自身的值,否则返回它的第二个操作数。

<?php
// Fetches the value of $_GET['user'] and returns 'nobody'
// if it does not exist.
$username = $_GET['user'] ?? 'nobody';
// This is equivalent to:
$username = isset($_GET['user']) ? $_GET['user'] : 'nobody';

// Coalesces can be chained: this will return the first
// defined value out of $_GET['user'], $_POST['user'], and
// 'nobody'.
$username = $_GET['user'] ?? $_POST['user'] ?? 'nobody';
?>

1.4. 太空船操作符(组合比较符)#

太空船操作符用于比较两个表达式。当 $a 小于、等于或大于 $b 时它分别返回-1、0或1。 比较的原则是沿用 PHP 的常规比较规则进行的。

<?php
// 整数
echo 1 <=> 1; // 0
echo 1 <=> 2; // -1
echo 2 <=> 1; // 1

// 浮点数
echo 1.5 <=> 1.5; // 0
echo 1.5 <=> 2.5; // -1
echo 2.5 <=> 1.5; // 1

// 字符串
echo "a" <=> "a"; // 0
echo "a" <=> "b"; // -1
echo "b" <=> "a"; // 1
?>

1.5. 通过 define() 定义常量数组#

Array 类型的常量现在可以通过 define() 来定义。在 PHP5.6 中仅能通过 const 定义。

<?php
define('ANIMALS', [
    'dog',
    'cat',
    'bird'
]);

echo ANIMALS[1]; // 输出 "cat"
?>

1.6. 匿名类#

现在支持通过 new class 来实例化一个匿名类,这可以用来替代一些“用后即焚”的完整类定义。

<?php
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;
    }
});

var_dump($app->getLogger());
?>

以上例程会输出:

object(class@anonymous)#2 (0) {
}

详细文档可以参考 匿名类.

1.7. Closure::call()#

Closure::call() 现在有着更好的性能,简短干练的暂时绑定一个方法到对象上闭包并调用它。

<?php
class A {private $x = 1;}

// PHP 7 之前版本的代码
$getXCB = function() {return $this->x;};
$getX = $getXCB->bindTo(new A, 'A'); // 中间层闭包
echo $getX();

// PHP 7+ 及更高版本的代码
$getX = function() {return $this->x;};
echo $getX->call(new A);

以上例程会输出:

1
1

1.8. 为 unserialize() 提供过滤#

这个特性旨在提供更安全的方式解包不可靠的数据。它通过白名单的方式来防止潜在的代码注入。

<?php

// 将所有的对象都转换为 __PHP_Incomplete_Class 对象
$data = unserialize($foo, ["allowed_classes" => false]);

// 将除 MyClass 和 MyClass2 之外的所有对象都转换为 __PHP_Incomplete_Class 对象
$data = unserialize($foo, ["allowed_classes" => ["MyClass", "MyClass2"]);

// 默认情况下所有的类都是可接受的,等同于省略第二个参数
$data = unserialize($foo, ["allowed_classes" => true]);

1.9. Group use declarations#

从同一 namespace 导入的类、函数和常量现在可以通过单个 use 语句 一次性导入了。

<?php

// PHP 7 之前的代码
use some\namespace\ClassA;
use some\namespace\ClassB;
use some\namespace\ClassC as C;

use function some\namespace\fn_a;
use function some\namespace\fn_b;
use function some\namespace\fn_c;

use const some\namespace\ConstA;
use const some\namespace\ConstB;
use const some\namespace\ConstC;

// PHP 7+ 及更高版本的代码
use some\namespace\{ClassA, ClassB, ClassC as C};
use function some\namespace\{fn_a, fn_b, fn_c};
use const some\namespace\{ConstA, ConstB, ConstC};
?>

1.10. 整数除法函数 intdiv()#

新加的函数 intdiv() 用来进行 整数的除法运算。

<?php

var_dump(intdiv(10, 3));
?>

以上例程会输出:

int(3)

1.11. 会话选项#

session_start() 可以接受一个 array 作为参数, 用来覆盖 php.ini 文件中设置的 会话配置选项

在调用 session_start() 的时候, 传入的选项参数中也支持 session.lazy_write 行为, 默认情况下这个配置项是打开的。它的作用是控制 PHP 只有在会话中的数据发生变化的时候才 写入会话存储文件,如果会话中的数据没有发生改变,那么 PHP 会在读取完会话数据之后, 立即关闭会话存储文件,不做任何修改,可以通过设置 read_and_close 来实现。

例如,下列代码设置 session.cache_limiterprivate,并且在读取完毕会话数据之后马上关闭会话存储文件。

<?php
session_start([
    'cache_limiter' => 'private',
    'read_and_close' => true,
]);
?>

1.12. preg_replace_callback_array()#

在 PHP 7 之前,当使用 preg_replace_callback() 函数的时候, 由于针对每个正则表达式都要执行回调函数,可能导致过多的分支代码。 而使用新加的 preg_replace_callback_array() 函数, 可以使得代码更加简洁。

现在,可以使用一个关联数组来对每个正则表达式注册回调函数, 正则表达式本身作为关联数组的键, 而对应的回调函数就是关联数组的值。

1.13. CSPRNG Functions#

新加入两个跨平台的函数: random_bytes()random_int() 用来产生高安全级别的随机字符串和随机整数。

1.14. 可以使用 list() 函数来展开实现了 ArrayAccess 接口的对象#

在之前版本中,list() 函数不能保证 正确的展开实现了 ArrayAccess 接口的对象, 现在这个问题已经被修复。

1.15. 其他特性#

允许在克隆表达式上访问对象成员,例如: (clone $foo)->bar()

2. 弃用的功能#

2.1. PHP4 风格的构造函数#

PHP4 风格的构造函数(方法名和类名一样)将被弃用,并在将来移除。 如果在类中仅使用了 PHP4 风格的构造函数,PHP7 会产生 E_DEPRECATED 警告。 如果还定义了 __construct() 方法则不受影响。

<?php
class foo {
    function foo() {
        echo 'I am the constructor';
    }
}
?>

以上例程会输出:

Deprecated: Methods with the same name as their class will not be constructors in a future version of PHP; foo has a deprecated constructor in example.php on line 3

2.2. 静态调用非静态的方法#

废弃了 静态(Static) 调用未声明成 static 的方法,未来可能会彻底移除该功能。

<?php
class foo {
    function bar() {
        echo 'I am not static!';
    }
}

foo::bar();
?>

以上例程会输出:

Deprecated: Non-static method foo::bar() should not be called statically in - on line 8
I am not static!

2.3. password_hash() 盐值选项#

废弃了 password_hash() 函数中的盐值选项,阻止开发者生成自己的盐值(通常更不安全)。 开发者不传该值时,该函数自己会生成密码学安全的盐值。因此再无必要传入自己自定义的盐值。


原文