PHP 7 新特性
PHP 7+版本极大地改进了性能,在一些 WordPress 基准测试当中,性能可以达到 PHP 5.6 的 3 倍。
参数可变数量
<?php function test(...$args) { print_r($args); } test(1,2,3,4,5); ?>
短数组语法
短数组语法[]
(方括号),现在可以用于将数组的值赋给一些变量(包括在 foreach中)。这种方式使从数组中提取值变得更为容易。
$data = [ ['id' => 1, 'name' => 'Tom'], ['id' => 2, 'name' => 'Fred'], ]; while (['id' => $id, 'name' => $name] = $data) { // logic here with $id and $name }
list()支持键名
现在list()
支持在它内部去指定键名。这意味着它可以将任意类型的数组都赋值给一些变量(与短数组语法类似)。
$data = [ ['id' => 1, 'name' => 'Tom'], ['id' => 2, 'name' => 'Fred'], ]; while (list('id' => $id, 'name' => $name) = $data) { // logic here with $id and $name }
foreach 支持 list()
对于“数组的数组”进行迭代,之前需要使用两个foreach
,现在只需要使用foreach
+ list
,但是这个数组的数组中的每个数组的个数需要一样。
$array = [ [1, 2], [3, 4],]; foreach ($array as list($a, $b)) { echo "A: $a; B: $b\n"; }
foreach 遍历数组不再修改内部指针。
$arr=[1,2,3,4,5,6]; foreach ($arr as $key => $value) { if($value ==2) break; } echo current($arr); //php7下 1,php5下 3
foreach 通过引用遍历时,有更好的迭代特性
当使用引用遍历数组时,现在 foreach 在迭代中能更好的跟踪变化。例如,在迭代中添加一个迭代值到数组中,参考下面的代码:
$array = [0]; foreach ($array as &$val) { var_dump($val); $array[1] = 1; } // PHP5 输出: int(0) // PHP7 输出: int(0) int(1)
为 unserialize()提供过滤
这个特性旨在提供更安全的方式解包不可靠的数据。它通过白名单的方式来防止潜在的代码注入。
// 将所有对象分为 __PHP_Incomplete_Class 对象 $data = unserialize($foo, ["allowed_classes" => false]); // 将所有对象分为 __PHP_Incomplete_Class 对象 除了 ClassName1 和 ClassName2 $data = unserialize($foo, ["allowed_classes" => ["ClassName1", "ClassName2"]); //默认行为,和 unserialize($foo) 相同 $data = unserialize($foo, ["allowed_classes" => true]);
异常处理增加 finally 关键字
异常处理语句由原来的 try-catch 新增了一个 finally语句块,适合用于写哪些不管是否异常最终都会执行的代码。
try { $pdo = new PDO('mysql:host=localhost;dbname=test;', 'root', '123456'); $msg = "开始正常执行"; } catch (Error $e) { $msg = "错误:" . $e->getMessage(); } catch (Exception $e) { $msg = "异常:" . $e->getMessage(); } finally { file_put_contents('error.log', $msg, FILE_APPEND); }
数组和字符串直接表达式
echo "hello world"[4];
新的密码加密函数
该算法弊端在于会增加了数据库字段的容量,因为加密后的 hash 太长。
$str = 'i am password'; //用户加密 $hash = password_hash($str, PASSWORD_BCRYPT); //用于验证加密是否正确 password_verify($str, $hash);
严格模式
在 PHP7 中为了提高执行效率,在函数方法中增加了标量类型(布尔、浮点、整型、字符)的申明特性(declare(strict_type=1);
),节省了对数据类型的检测。
- 强制模式:默认是强制模式,不需要指定。
- 严格模式:严格的模式,必须明确声明。
PHP 的数据类型可分为三种:标量数据类型、复合数据类型和特殊数据类型。
标量类型 4 种:
- boolean(布尔型)
- integer(整形)
- float/double(浮点型)
- tring(字符串类型)
复合类型 2 种:
- array(数组)
- object(对象)
特殊类型 2 种:
- resource(资源)
- null
<?php // 严格模式 declare(strict_types=1); function sum(int ...$ints) { return array_sum($ints); } print(sum(2, '3', 4.1)); ?>
- 严格模式的校验行为:严格的类型校验调用拓展或者 PHP 内置函数,会改变 zend_parse_parameters 的行为。特别注意,失败的时候,它会产生 E_RECOVERABLE_ERROR 而不是 E_WARNING。
- 严格类型校验规则是非常直接的:只有当类型和指定类型声明匹配,它才会接受,否则拒绝。
返回类型声明
在使用 PHP7 的时候,您会发现在 PHP7 中包含了一个新的功能,即返回类型声明。返回类型声明指定一个函数应该返回的值的类型,可用的类型与参数声明中可用的类型相同。可以声明以下类型的返回类型:
- int
- float
- bool
- string
- interfaces
- array
- callable
- void
<?php declare(strict_types=1); function returnIntValue(int $value): int { return $value; } print(returnIntValue(5)); // 5 ?>
void 类型
返回的类型还有void
,定义返回类型为void
的函数不能有返回值,即使返回NULL
也不行。
<?php function swap(&$left, &$right) : void { if ($left === $right) { return; } $tmp = $left; $left = $right; $right = $tmp; } $a = 1; $b = 2; var_dump(swap($a, $b), $a, $b); /* 以上实例输出结果: null int(2) int(1) */ ?>
太空船操作符
空船操作符,又被称为组合比较运算符,或者结合比较符,它使用符号<=>
表示,该操作符可以用于实现对两个变量的比较(不限制于数值类型的数据)。
太空船操作符的表达式为:
$z = $x <=> $y;
- 如果$x>$y,则$z的值为1。
- 如果$x==$y,则$z的值为0。
- 如果$x<$y,则$z的值为-1。
<?php // 整型比较 print( 1 <=> 1); 0 print( 1 <=> 2); -1 print( 2 <=> 1); 1 // 浮点型比较 print( 1.5 <=> 1.5); 0 print( 1.5 <=> 2.5); -1 print( 2.5 <=> 1.5); 1 // 字符串比较 print( "a" <=> "a"); 0 print( "a" <=> "b"); -1 print( "b" <=> "a"); 1 ?>
幂运算
PHP7 中添加了新的幂运算:**
。如果是多个值进行幂运算,实则运算顺序是从右往左进行的,比如:a**b**c
。
<?php $pow = pow(2,10); $replace = 2 ** 10; var_dump($replace == $pow);
空合并运算符
在 PHP7 中,引入了一个新的功能,即空合并运算符(??
)。由于在 PHP7 项目中存在大量同时使用三元表达式和isset()
的情况。如果变量是存在的并且不为null
,则空合并运算符将返回它的第一个操作数;否则将返回其第二个操作数。
// 在旧版的PHP中: isset($_GET[‘id']) ? $_GET[id] : err; // 而新版的写法为: $_GET['id'] ?? 'err';
// 之前版本写法: $info = isset($_GET['email']) ? $_GET['email'] : 'noemail'; // PHP7 版本的写法: $info = $_GET['email'] ?? noemail; // 还可以写成这种形式: $info = $_GET['email'] ?? $_POST['email'] ?? 'noemail';
在类外也可使用 const 来定义常量
在之前,只能在 class 类中,可以使用const
关键字来定义常量。在 class 类外,使用define()
函数进行定义。现在在 PHP7+中,可以使用const
关键字,在类外,定义常量。
//PHP 中定义常量通常是用这种方式 define("CONSTANT", "Hello world."); //并且新增了一种常量定义方式 const CONSTANT = 'Hello World';
定义常量数组
<?phpdefine ('ANIMALS', ['dog', 'cat', 'bird']); echo ANIMALS[1]; // outputs "cat" ?>
<?php const STATUS = [ 'ERROR' => 0, 'SUCCESS' => 1 ]; STATUS['ERROR'];
新增函数 boolval
PHP 已经实现了strval()
、intval()
和floatval()
的函数。为了达到一致性将添加floatval()
函数。它完全可以作为一个布尔值计算,也可以作为一个回调函数。
新增函数 hash_pbkdf2
PBKDF2 全称“Password-Based Key Derivation Function 2”,正如它的名字一样,是一种从密码派生出加密密钥的算法。这就需要加密算法,也可以用于对密码哈希。
array_column
//从数据库获取一列,但返回是数组。 $userNames = []; foreach ($users as $user) { $userNames[] = $user['name']; } //现在如下 $userNames = array_column($users, 'name');
intdiv
intdiv
:对除法结果取整。
intdiv(int $num1, int $num2): int
返回 num1 除以 num2 商数的整数部分。
- $num1:被除数。
- $num2:除数。
- 返回值:$num1除以$num2的商,对该商取整。
- 如果$num2是 0,将抛出 DivisionByZeroError 异常。
- 如果$num1是 PHP_INT_MIN 并且$num2是
-1
,将抛出 ArithmeticError 异常。
var_dump(intdiv(3, 2)); var_dump(intdiv(-3, 2)); var_dump(intdiv(3, -2)); var_dump(intdiv(-3, -2)); var_dump(intdiv(PHP_INT_MAX, PHP_INT_MAX)); var_dump(intdiv(PHP_INT_MIN, PHP_INT_MIN));
var_dump(intdiv(PHP_INT_MIN, -1)); var_dump(intdiv(1, 0));
session_start()中可动态设置项覆盖配置项
session_start
原来的作用用来开启 session。
date_default_timezone_set("PRC"); session_start([ 'save_path' => 'F:\Session', 'name' => 'FELIXSESSID', 'cookie_lifetime' => 3600 ]);
命名空间成员的批量导入
use App\Course\{ Common\Lesson, Base\Teacher }; new Lesson(); new Teacher();
生成器( Generator )
生成器是专门了处理大数组(大数据)和协程通信而出现。
<?php function xrange($start, $end, $step=1) { for ($i=$start; $i<$end; $i+=$step){yield $i; } } foreach (xrange(0, 1000) as $item) { echo $item; }
生成器支持返回值
<?php function builder() { yield '第1次调用生成器'; yield '第2次调用生成器'; yield '第3次调用生成器'; yield '第4次调用生成器'; return 'success'; } $builder = builder(); foreach ($builder as $item) { echo $item . '<br />'; } // 如果 7 以下,一定会报错 if ($builder->getReturn() == 'success') { echo "程序执行完毕"; }
生成器的委托
生成器的委托操作,主要是把一个复杂的生成器分离成若干简单的生成器。
function builder() { yield '奥特之父发出指定'; if (mt_rand(0, 1) == 0) { yield from tl(); } else { yield from dj(); } } function tl() { yield "泰罗你去打小怪兽"; } function dj() { yield "迪迦你去打小怪兽"; } $builder = builder(); foreach ($builder as $item) { echo "{$item}<br/>"; }
IntlChar 类
新增加的 IntlChar 类旨在暴露出更多的 ICU 功能。这个类自身定义了许多静态方法用于操作多字符集的 unicode 字符。Intl是 Pecl 扩展,使用前需要编译进 PHP 中。
echo IntlChar::ord('A'); //获取 A 的 ascii 码 65
匿名类
在 PHP 中,匿名类是指没有名字的类,匿名类不能被引用,可以利用new class
来创建一个匿名类。一个匿名类就只能创建一次对象。在执行的过程中,类不占用空间,用完即可销毁。匿名类可以在一个类的内部方法中声明,也可以直接赋值给变量,可以在方法中使用return
返回,也可以当做参数传递给方法内部。其实,匿名类就像一个没有事先定义的类,而在定义的时候直接就进行了实例化。
- 匿名类和普通类一样,可以继承其他类,可以实现接口,当然也包括各种访问控制的能力。也就是说,匿名类在使用方面和普通类并没有什么不同。但如果用
get_class()
获取类名将是系统自动生成的类名。相同的匿名类返回的名称当然也是相同的。 - 当匿名类被嵌套进普通类后,不能访问这个外部类中使用
private
、protected
修饰的方法或者属性。如果要访问外部类使用protected
修饰的属性或方法,可以使用匿名类来继承此外部类。如果要使用外部类使用private
修饰的属性,则必须通过构造器传进来。
interface Cache{ public function read (); }class Ca { private $cache; public function setcache(Cache $cache){ $this->cache=$cache; } } $fcache =new Ca; $fcache->setcache(new Class implements Cache { public function read(){ } });
Closure::call()
在 php7 之前,当动态的给一个对象添加方法时,可以通过Closure来复制一个闭包对象,并绑定到一个$this对象和类作用域。在 php7 可通过Closure::call()
来暂时绑定一个闭包对象到$this对象并调用它。
Closure::call()
:方法被添加作为临时绑定的对象范围,以封闭并简便调用它的方法。它的性能相比 PHP5.6 bindTo
要快得多。
<?php // PHP7 之前 class A { private $x = 1; } // Define a closure Pre PHP 7 code $getValue = function() { return $this->x; }; // Bind a clousure $value = $getValue->bindTo (new A, 'A'); print($value()); // 1 ?>
<?php // PHP7+ class A { private $x = 1; } // PHP 7+ code, Define $value = function() { return $this->x; }; print($value->call(new A)); // 1 ?>