世界变化真快,忽然听闻 PHP 都到 7.3 版本了,7.2 还没仔细了解过呢。看到我司面试时会问到php新版本有什么特性,美名其曰考察其学习新技术的能力,我有点汗颜,本身都没有主动去了解过,实在不该该。所以,在这里立下一贴,用于记录新版本的PHP的变化,以及对实际工做的影响。php
PHP7.0 号称是性能提高上革命性的一个版本。面对 Facebook 家的 HHVM 引擎带来的压力,开发团队重写了底层的 Zend Engine,名为 Zend Engine 2。面试
虽然是大版本的更新(直接从PHP5.6跳到了7,中间省略了不存在的6),可是几乎不会遇到兼容性的问题,不会像 Python 那样陷入 2.7 或 3.7 的选择困境。咱们本身在评估测试了实际项目运行状况以后,直接升到了 7.1。数组
下面讲一讲主要的变化:安全
类型声明也叫 type hints,即声明参数的类型。如今能够声明参数为标量类型了,包括:string,int,float,bool。扩充了原来的范围,原来只支持:类名,接口名,''array'' 和 ''callable'' 这五种类型。session
<?php function sum(int $a, int $b) { return $a + $b; } var_dump(sum(1, 2)); // output: int(3)
函数能够添加返回值类型声明了,声明返回值的类型。能够声明的类型范围与参数声明类型相同。闭包
function sum(int $a, int $b): int { return $a . $b; } var_dump(sum(1, 2)); // output: int(12) function sum(int $a, int $b): string { return $a . $b; } var_dump(sum(1, 2)); // output: string(2) "12"
'''??'''操做符简化了'''isset()'''函数的使用,若是第一个操做数存在且不为NULL,则返回之,不然返回第二个操做数。app
<?php // 这种场景,判断是否存在,若是不存在则赋值默认一个值 $username = isset($_GET['user']) ? $_GET['user'] : 'nobody'; // 使用 ?? 得到相同效果,代码却简洁不少 $username = $_GET['user'] ?? 'nobody'; // ?? 能够链式使用,第一个不存在,则判断第二个,第二个不存在再使用默认值 $username = $_GET['user'] ?? $_POST['user'] ?? 'nobody';
'''<=>''' 操做符用于比较两个表达式。能够把这个操做符拆开来理解,'''<=>''' 一次就能判断出 小于<,等于=,大于> 这三种状况。dom
<?php // Integers echo 1 <=> 1; // 0 echo 1 <=> 2; // -1 echo 2 <=> 1; // 1 // Floats echo 1.5 <=> 1.5; // 0 echo 1.5 <=> 2.5; // -1 echo 2.5 <=> 1.5; // 1 // Strings echo "a" <=> "a"; // 0 echo "a" <=> "b"; // -1 echo "b" <=> "a"; // 1 ?>
如今可使用 define() 来定义常量数组了,而以前只能用 const 定义。socket
<?php define('ANIMALS', [ 'dog', 'cat', 'bird', ]); echo ANIMALS[1];
如今支持匿名类了。函数
<?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()); // output: // class class@anonymous#2 (0) { // }
匿名类至少方便了如下场景:(1)测试更方便,为接口建立实时实现,而不用专门去创建一个只用一次的类。
语法以下例所示,能够直接经过16进制的代码来输出 Unicode 字符了。
echo "\u{5201}"; echo "\u{2200}"; // output: 刁 // output: ∀
Closure::call() 是一种更加简洁的方式,来绑定对象到闭包并调用它。
<?php class A { private $x = 1; } $getX = function () { return $this->x; }; // pre PHP7 $getXCB = $getX->bindTo(new A, 'A'); echo $getXCB(); // PHP7 echo $getX->call(new A);
增长了反序列化对象时的安全性。开发者能够经过第二个参数来设置一个容许反序列化的类的白名单。
<?php // 转换全部数据为 __PHP_Incomplete_Class 对象 $data = unserialize($foo, ["allowed_classes" => false]); // 转换全部数据为 __PHP_Incomplete_Class 对象,除了 MyClass 和 MyClass2 $data = unserialize($foo, ["allowed_classes" => ["MyClass", "MyClass2"]]); // 默认行为,至关于忽略了第二个参数,容许全部的类 $data = unserialize($foo, ["allowed_classes" => true]);
增长了新的类 '''IntlChar''',它增长了国际化相关的功能,该类定义了大量的静态方法和静态常量,用于控制 Unicode 字符。
使用该类,前提是安装了 Intl 扩展。
Expectations 是 assert() 的向后兼容的加强。在php.ini中增长了 assert.expectation 指令以控制 assert() 的行为。
能够将多个use声明合并为一个use
<?php // pre PHP7 use some\namespace1\ClassA; use some\namespace1\ClassB; use some\namespace1\ClassC as C; // PHP7+ use some\namespace1\{ClassA, ClassB, ClassC as C};
如今生成器能够用return来返回最后一次的表达式,这个值能够用新的 Generator::getReturn() 方法获取,可是这个方法只能在 yield 值结束以后,使用一次。
<?php $gen = (function () { yield 1; yield 2; return 3; })(); foreach ($gen as $val) { echo $val; } echo $gen->getReturn(); // output: 123
这是一个很方便的功能,客户端使用生成器时能够用它来判断 yield 值是否完成。
如今,只需在最外层生成器中使用 yield from, 就能够把一个生成器自动委托给其余的生成器、, Traversable 对象或者 array。
<?php function gen1() { yield 1; yield 2; yield from gen2(); yield from [5, 6]; } function gen2() { yield 3; yield 4; } foreach (gen1() as $val) { echo $val, PHP_EOL; } /* output: 1 2 3 4 5 6 */
不了解生成器?能够参考:《Modern_PHP》#Generators 或 Generators_(PHP)
var_dump(intdiv(10, 3)); // output: int(3)
如今 session_start()
能够接受一个 options 数组,以重写 php.ini 中的 session 设置。
// 设置 session.cache_limiter 为私有,而且读取完就关闭session session_start([ 'cache_limiter' => 'private', 'read_and_close' => true, ]);
新增两个生成加密整数和字符串的函数:random_bytes()
和 random_int()
。
如今能够在参数类型声明和返回值类型声明的类型前面加一个问号(?),来表示参数能够是NULL或者能够返回NULL值。
<?php function fun1(?int $i) :?string { if ($i ### null) { return null; } else { return $i; } } var_dump(fun1(null)); var_dump(fun1(1)); // output: NULL // output: string(1) "1" // PHP Fatal error: Uncaught ArgumentCountError: Too few arguments to function fun1(), 0 passed
新增函数的 void 返回值。void函数要么没有return语句,要么空return语句,返回NULL是错误的。
短数组语法([])能够做为list()
语法的另外一种形式,用来给数组赋值。
$data = [ [1, 'Tom'], [2, 'Fred'] ]; // list() style list($id1, $name1) = $data[0]; // [] style [$id2, $name2] = $data[1]; // list() style foreach ($data as list($id, $name)) { # code... } // [] style foreach ($data as [$id, $name]) { # code... }
增长了对类常量可见性的支持。
class ConstDemo { const PUBLIC_CONST_A = 1; public const PUBLIC_CONST_B = 2; protected const PROTECTED_CONST = 3; private const PRIVATE_CONST = 4; }
增长了新的伪类:iterable,能够用于参数,或返回值类型,表示接受数组或实现了 Traversable 接口的对象。
function iterator(iterable $iter) { foreach ($iter as $val) { // } }
能够在一个catch中捕获多种异常对象了。
function triError(bool $i) { try { if ($i) { throw new Exception('exception!'); } else { throw new ErrorException('error exception!'); } } catch(Exception | ErrorException $e) { echo $e->getMessage(), PHP_EOL; } } triError(true); triError(false); // output: exception! // output: error exception!
如今能够在 list() 或短数组语法([])中指定键名,这样就能够支持非数字索引的数组赋值了。
$data = [ ["id" => 1, "name" => "Tom"], ["id" => 2, "name" => "Fred"], ]; list("id" => $id1, "name" => $name1) = $data[0]; var_dump($id1); var_dump($name1); // int(1) // string(3) "Tom" ["id" => $id2, "name" => $name2] = $data[1]; var_dump($id2); var_dump($name2); // int(2) // string(4) "Fred"
字符串函数以及字符串下标如今能够为负数。负数表示从字符串末尾开始执行相关操做。
var_dump("abcde"[-1]); var_dump(strpos("abcdeb", "b", -1)); var_dump(strpos("abcdeb", "b", 1)); // string(1) "e" // int(5) // int(1)
增长了一个静态方法 fromCallable()
,用于方便地转换 callable 为 Closure 对象。
class Test { public function exposeFunction() { return Closure::fromCallable([$this, 'privateFunction']); } private function privateFunction($param) { var_dump($param); } } $privFunc = (new Test)->exposeFunction(); $privFunc('some value'); // string(10) "some value"
参数类型和返回值类型声明如今支持 object
类型了,该类型表示接受任何对象。
function test(object $obj): object { return new stdClass(); } test(new stdClass());
加载扩展不须要文件扩展名了(.so或.dll),直接用名字便可,在php.ini或者dl()函数都有效。
当一个抽象类继承另外一个抽象类时,它能够重写父类(抽象类)的方法。
abstract class A { abstract public function test(string $s); } abstract class B extends A { abstract public function test($s): int; }
现代 Sodium 加密库已经成为PHP核心扩展。
Argon2 已经被添加到 password hash API中,经过如下常量使用:
PASSWORD_ARGON2I
PASSWORD_ARGON2_DEFAULT_MEMORY_COST
PASSWORD_ARGON2_DEFAULT_TIME_COST
PASSWORD_ARGON2_DEFAULT_THREADS
新增这些常量,扩展了PDO字符串的使用
PDO::PARAM_STR_NATL
PDO::PARAM_STR_CHAR
*PDO::ATTR_DEFAULT_STR_PARAM
$db->quote('über', PDO::PARAM_STR | PDO::PARAM_STR_NATL);
新增下列方法,能够在链接时、绑定时或解释时查看地址信息:
socket_addrinfo_lookup()
socket_addrinfo_connect()
socket_addrinfo_bind()
socket_addrinfo_explain()
重写方法的参数类型如今被忽略了,so?
interface A { public function Test(array $input); } class B implements A { public function Test($input){} // type omitted for $input }
use Foo\Bar\{ Foo, Bar, Baz, };
支持读写加密的压缩文件了(须要 libzip 1.2.0)
如今 ZipArchive 实现了 Countable 接口。
zip:// 流接受一个 password 上下文选项
PS:我的博客连接 PHP新版本变化***