#### php7新特性
1.运算符(NULL 合并运算符):
在第一操作数存在时可被直接返回,否则返回第二操作数
$a = $_GET['a'] ?? 1;
它相当于:
<php
$a = isset($_GET['a']) ? $_GET['a'] : 1;
2.函数返回值类型声明:
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
)
这个特性可以帮助我们避免一些 PHP 的隐式类型转换带来的问题。
PHP 7 增加了一个 declare 指令: declare(strict_types=1); ,既使用严格模式
例:
declare(strict_types=1);
function foo($a) : int
{
return $a;
}
如果 foo(1.2),就会触发致命错误。
3.标量类型声明:
PHP 7 中的函数的 形参类型 声明可以是标量了,现在可以使用 string、int、float和 bool 了。
实例:
function sumOfInts(int $ints)
{
return array_sum($ints);
}
var_dump(sumOfInts(2,'3',4.1));
输出:int(9)
4.use 批量声明:
php7 中 use 可以在一句话中声明多个类或函数或 const
要写出每个类或函数或 const 的名称。
例:
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};
5.<=>操作符:
<=>操作符将==、<、>三个比较操作符打包在了一起,具体使用规则如下:
操作符两边相等时返回 0,
操作符左边小于右边时返回 -1,
操作符左边大于右边时返回 1,
例:
echo 1 <=> 1; // 0
echo 1 <=> 2; // -1
echo 2 <=> 1; // 1
6.通过 define() 定义常量数组:
define('ANIMALS', [
'dog',
'cat',
'bird'
]);
7.session_start函数中的选项数组;
在PHP7之前,使用session的时候都必须先调用session_start()函数,且这个函数并没有参数需要传递,所有session相关的配置都在php.ini文件中,从PHP7开始,可以在调用这个函数时传递参数选项数组,这些设置信息将覆盖php.ini中的session配置。
session_start([
'cookie_lifetime' => 3600,
'read_and_close' => true
]);
8.unserialize函数引入过滤器:
unserialize()可以反序列化任何类型的对象,没有任何过滤项,不安全,PHP7在unserialize()中引入了过滤器,且默认允许反序列化所有类型的对象。
9.list:
PHP5.4 之前只能通过 array() 来定义数组,5.4之后添加了 [] 的简化写法。
<?php // 5.4 之前
$array = array(1, 2, 3);
$array = array("a" => 1, "b" => 2, "c" => 3);
// 5.4 及之后
$array = [1, 2, 3];
$array = ["a" => 1, "b" => 2, "c" => 3];
那么,如果要把数组的值赋值给不同的变量,可以通过 list 来实现:
<?php list($a, $b, $c) = $array;
是否也可以通过 [] 的简写来实现呢?
<?php [$a, $b, $c] = $array;
以及下一个特性中会提到的 list 指定 key:
<?php ["a" => $a, "b" => $b, "c" => $c] = $array;
PHP7.1 实现了这个特性,但:出现在左侧的 [] 并不是数组的简写,而是 list() 的简写。
现在新的 list() 的实现并不仅仅可以出现在左值中,也能在 foreach 循环中使用:
<?php foreach ($points as ["x" => $x, "y" => $y]) {
var_dump($x, $y);
}
不过因为实现的问题,list() 和 [] 不能相互嵌套使用:
<?php // 不合法
list([$a, $b], [$c, $d]) = [[1, 2], [3, 4]];
// 不合法
[list($a, $b), list($c, $d)] = [[1, 2], [3, 4]];
// 合法
[[$a, $b], [$c, $d]] = [[1, 2], [3, 4]];
另外,在新的 list() 的实现中可以指定key:
<?php $array = ["a" => 1, "b" => 2, "c" => 3];
["a" => $a, "b" => $b, "c" => $c] = $array;
相当于:
<?php $a = $array['a'];
$b = $array['b'];
$c = $array['c'];
和以往的区别在于以往的 list() 的实现相当于 key 只能是 0, 1, 2, 3 的数字形式并且不能调整顺序。执行语句:
<?php list($a, $b) = [1 => '1', 2 => '2'];
会得到 PHP error: Undefined offset: 0... 的错误。
新的实现则可以通过以下方式来调整赋值:
<?php list(1 => $a, 2 => $b) = [1 => '1', 2 => '2'];
不同于数组的是,list 并不支持混合形式的 key,以下写法会触发解析错误:
<?php // Parse error: syntax error, ...
list($unkeyed, "key" => $keyed) = $array;
更复杂的情况,list 也支持复合形式的解析:
<?php $points = [
["x" => 1, "y" => 2],
["x" => 2, "y" => 1]
];
list(list("x" => $x1, "y" => $y1), list("x" => $x2, "y" => $y2)) = $points;
$points = [
"first" => [1, 2],
"second" => [2, 1]
];
list("first" => list($x1, $y1), "second" => list($x2, $y2)) = $points;
以及循环中使用:
<?php $points = [
["x" => 1, "y" => 2],
["x" => 2, "y" => 1]
];
foreach ($points as list("x" => $x, "y" => $y)) {
echo "Point at ($x, $y)", PHP_EOL;
}
10.匿名类
有时我们不想为一个参数专门去声明一个类来适配它,而使用内部类可以直接想使用匿名函数一样方便,直接使用,如果参数类型是接口类型,我们只需要让匿名类实现指定的接口即可
interface IFoo
{
function doSomething();
}
class Bar
{
public function execute(IFoo $foo)
{
$foo->doSomething();
}
}
$bar = new Bar();
$bar->execute(new class () implements IFoo
{
function doSomething()
{
echo 'execute!';
}
});
//输出execute!
11.生成器返回表达式
生成器是一个偏的内容,不太被使用的特性,不过这在PHP5.5版本就已经开始有了。以下是官方对生成器的解释:
生成器提供了一种更容易的方法来实现简单的对象迭代,相比较定义类实现 Iterator 接口的方式,性能开销和复杂性大大降低。
生成器允许你在 foreach 代码块中写代码来迭代一组数据而不需要在内存中创建一个数组, 那会使你的内存达到上限,或者会占据可观的处理时间。相反,你可以写一个生成器函数,就像一个普通的自定义函数一样, 和普通函数只返回一次不同的是, 生成器可以根据需要 yield 多次,以便生成需要迭代的值。
其实平时我们在遍历内容比较大的数据时,很消耗内存,但是使用生成器就不一样,它只有在迭代的时候才会取值,不会把遍历的数据全部放入内存中。
生成器Generator实现了迭代器接口Iterator,可以对其进行遍历操作,在PHP7中生成器添加了getReturn接口,可以获取return返回值,而在PHP7之前,在生成器中声明带值的返回会引发Fatal error: Generators cannot return values using "return" in %s on line %d错误。
function generateSerialNo(int $limit)
{
$i = 0;
for (; $i < $limit; $i++) {
yield $i;
}
return $i;
}
$gen = generateSerialNo(10);
foreach ($gen as $value) {
echo $value, ' ';
}
echo $gen->getReturn();
//输出
//0 1 2 3 4 5 6 7 8 9 10
以上时生成一个0到$limt-1的序列数字,可以看到最后输出10,其实这个10时返回值,当生成器遍历完之后$i的值已经时10了,跳出了循环。
生成器委托
生成器实现了Iterator接口,说明其可以进行遍历操作,在PHP7中,可以用yield from来把生成器委托到其它生成器。
//生成1到5的数字
function generateOneToFive()
{
yield from generateOneToThree();
yield from generateSixFourToFive();
}
//生成1到3的数字
function generateOneToThree()
{
yield 1;
yield 2;
yield 3;
}
//生成4到5的数字
function generateSixFourToFive()
{
yield 4;
yield 5;
}
foreach (generateOneToFive() as $num) {
echo $num . ' ';
}
//输出
//1 2 3 4 5
上边的代码需要生成器生成1-5的数字,主生成器中并没有生成数字的逻辑,而是委托其它生成器完成。
12.更多的Error变为可捕获的Exception
从PHP7开始,程序中的fatal错误都可以被截获,PHP7提供了throwable接口,异常与错误都继承于这个接口。
Error
现在大多数的fatal错误情况会抛出一个error实例,类似于截获异常,error实例可以被try/catch截获。
try
{
...
} catch(Error $e)
{
echo $e->getMessage();
}
13.switch中的default默认值
在PHP7之前,switch语句中允许多个default默认值,从PHP7开始,只能有一个default默认值,否则会产生fatal级别错误。
// php7之前
switch (true) {
case 'value':
# code...
break;
default:
# code...
break;
default:
# code...
break;
}
// php7
switch (true) {
case 'value':
# code...
break;
default:
# code...
break;
}
14.闭包的绑定 Closure::call()
之前声明一个闭包之后需要为为闭包绑定执行上下文,需要复制闭包然后绑定$this,现在使用call()省去复制步骤,更加方便,性能更好。
PHP7之前
class App
{
public function execute()
{
echo 'App execute';
}
}
$closure = function() {
echo $this->execute();
};
$newClosure = Closure::bind($closure, new App());
//或者$newClosure = $closure->bindTo(new App());
$newClosure(); //输出App execute
PHP7
class App
{
public function execute()
{
echo 'App execute Call';
}
}
$closure = function() {
echo $this->execute();
};
$closure->call(new App());
//输出App execute Call
15.整除函数intdiv
这应该很好了解,整除,返回的是整数部分的模。
echo intdiv(100, 3) , '<br>';
echo intdiv(8, 7) , '<br>';
echo intdiv(10.4, 2.5) , '<br>';
//结果
//33 1 5
16.函数preg_replace_callback_array()
这个新函数能够以数组的形式来传递正则和回掉函数处理匹配工作,比使用preg_replace_callback()精简了不少,特别适合批量匹配正则。
17.Expectations 预期
在PHP7中assert不再是一个函数,而是一个语言结构就像echo一样。
预期增强了之前的assert方法,我们可以在开发或者生产环境中使用断言,其提供了可配置选项,我们可以针对不同的环境来使用不同的策略。
PHP7的断言配置:
zend.assertions
1-生成和执行代码(开发坏境)
0-生成代码但跳过运行时环境
-1-不生成代码(生产环境)
assert.exception
1-断言失败时,抛出异常,没有指定异常则默认抛出AssertException
0-生成一个Throwable抛出警告,而不是抛出错误(兼容PHP5的行为)。
ini_set('zend.assertions', 1);
$dest = true;
assert(false, $dest); //抛出AssertException
//----------------------------
ini_set('assert.exception', 0);
ini_set('zend.assertions', 0);
$dest = true;
assert(false, $dest); //无错误和警告