PHP5.5到PHP7的新特性

PHP5.5到PHP7的新特性

作者:悟尘

一、PHP5.5

官方手册:http://php.net/manual/zh/migration55.new-features.php

PHP 5.5.x 中废弃的特性

废弃 ext/mysql

原始的 MySQL 扩展 现在被废弃,当连接到数据库时会产生一个 E_DEPRECATED 错误。可使用 MySQLi 或PDO_MySQL 扩展作为替代。

preg_replace() 中的 /e 修饰符 eval

preg_replace() 函数中用到的 /e 修饰符现在被弃用。可以使用 preg_replace_callback() 函数来替代。

但是如果你非要用,它还可以支持的,最高支持以php5.6.x,不过会报Deprecated,PHP7中就不可以使用了.

PHP 5.5.x 中新特性:

1、生成器[yield]

关键点 : [yield]它最简单的调用形式看起来像一个return申明,不同之处在于普通return会返回值并终止函数的执行,而yield会返回一个值给调用此生成器的代码,并且只是执行生成器函数 循环

$html = '

hello world

';

$html = preg_replace(

'((.*?))e',

'"" . strtoupper("$2") . ""',$html);

$html = '

hello world

';

$html = preg_replace_callback('((.*?))',function ($m) {return "" . strtoupper($m[2]) . "";},$html);


echo '

';

function fun(){

yield 1;

yield 2;

yield 3;

yield 4;

yield 5;

// 我们可以使用echo来进行输出

//echo 'ok';

}

$ret = fun();

foreach($ret as $item){

echo $item.'


';

}

// 传统的循环数据中的数据

$arr = range(1,10);

foreach(range(1,10) as $val){

echo $val.'


';

}

// 运用生成器来生成1到10的记录数

function xrange(){

for($i = 1; $ <= 10; $i++){

yield $i;

}

}

// 循环读取出生成器中的内容

foreach(xrange() as $item){echo $item.'


';}

// 数据库操作

$dsn = 'mysql:host=localhost;dbname=a67_web64;charset=utf8';

$user = 'root';

$pwd = 'root';

try{

$pdo = new PDO($dsn, $user, $pwd);

}catch (PDOException $e){

throw new Exception($e->getMessage());

}

$sql = "select * from a67_addon_dianying";

echo '

';

foreach(findAll($sql) as $item){

extract($item);

echo $aid.'----'.$daoyan.'


';

}

2、finally关键字的使用

不管抛出异常是否被抛出,程序代码块都会被执行

注: finally区块中一般执行一些如关闭资源和连接等操作,此代码块不管程序是否有异常都必须要执行。

3、foreach 现在支持 list()

foreach 控制结构现在支持通过 list() 构造将嵌套数组分离到单独的变量

function findAll($sql){

global $pdo;

$stmt = $pdo->prepare($sql);

$stmt->execute();

while ($row = $stmt->fetch(PDO::FETCH_ASSOC)){

yield $row;

}

}

try {

// 抛出异常消息

throw new Exception('打开文件失败');

} catch (Exception $e) {

// 处理异常错误

echo '

';

var_dump($e);

// 模拟可以处理异常的时候出现了别的异常情况的情况

throw new Exception('处理异常失败');

}finally{

// 无论如何都要执行此代码块中的内容

echo '
文件我关闭了';

}

echo '
看我执行了没有了';

// 定义一个数组

$arr = [

[1,2],

[3,4],

[5,6],

];

// 需求,把上面的数组打印出来

// 以前的写法

foreach($arr as $val){

echo $val[0].' -- '.$val[1].'


';

}

// php5.5以后的写法 foreach中支持 list写法 支持索引数组

foreach($arr as list($a,$b)){

echo $a.' -- '.$b.'


';

}

#注: 关联数组暂不支持

4、empty() 支持任意表达式

empty() 现在支持传入一个任意表达式,而不仅是一个变量,对以前的功能的升级

echo '

';

// 定义一个函数

function fun(){

return true;

}

// 空字符串

var_dump(empty('')); # true

// 支持表达式

var_dump(empty(1 + 2)); # false

var_dump(empty(1 + 1 > 3)); # true

// 支持调用函数

var_dump(empty(fun())); # false

5、新的密码加密函数-password_hash()

简单的md5加密很容易通过字典的方式进行破解,随便找个md5解密的网站就能获取原始密码,所以PHP官方推出了一个新的加密的函数,password_hash。

password_hash加密

优点:就是更加的安全可靠,每次运行加密的结果都不一致。

缺点:互操作性差,如和其它语言进行交互验证加密起来就不行了,只能通过password_verify来验证。

string password_hash ( string $password , integer $algo [, array $options ] )

当前支持的算法:

PASSWORD_DEFAULT - 使用 bcrypt 算法 (PHP 5.5.0 默认)。 注意,该常量会随着 PHP 加入更新更高强度的算法而改变。 所以,使用此常量生成结果的长度将在未来有变化。 因此,数据库里储存结果的列可超过60个字符(最好是255个字符)。

PASSWORD_BCRYPT - 使用 CRYPT_BLOWFISH 算法创建哈希。 这会产生兼容使用 " 2y" 的 crypt()。结果将会是 60 个字符的字符串, 或者在失败时返回 FALSE。

①、加密 password_hash

// 明文密码

$pwd = 'admin888';

// 加密密码

echo password_hash($pwd,PASSWORD_DEFAULT);

②、验证 password_verify

password_verify() 验证密码是否和哈希匹配

boolean password_verify ( string $password , string $hash )

$password 明文的密码

$hash 加密的密码

// 明文密码

$pwd = 'admin888';

// 加密密码

$pass = password_hash($pwd,PASSWORD_DEFAULT);

echo '加密后的密码:'.$pass.'


';

// 验证密码是否正确

// 不正确

$plainPwd = '111';

if (password_verify($plainPwd,$pass)) {

echo '密码一致


';

}else{

echo '密码不一致


';

}

// 正确

if (password_verify($pwd,$pass)) {

echo '密码一致


';

}else{

echo '密码不一致


';

}

二、PHP5.6

官方手册:http://php.net/manual/zh/migration56.new-features.php

PHP 5.6.x 中已废弃的特性

$HTTP_RAW_POST_DATA 和 always_populate_raw_post_data

使用 always_populate_raw_post_data 会导致在填充 HTTP_RAW_POST_DATA 时产生 E_DEPRECATED 错误。

请使用 php://input 替代 HTTP_RAW_POST_DATA, 因为它可能在后续的 PHP 版本中被移除。

设置 always_populate_raw_post_data 为 -1 (这样会强制 $HTTP_RAW_POST_DATA 未定义,所以也不会导致E_DEPRECATED 的错误) 来体验新的行为。

1、使用表达式定义常量 const

http://blog.csdn.net/cscrazybing/article/details/46989749

// 1、const不能放在循环或条件语句中,只放在命名空间或头档的顶级中,则可以

// 2、在类中定义常量,只能用const

// 3、define在php7之前不能定义数组而const则可以

// 4、const在php5.6之前是不可定义表达式常量,define则可以

const ONE = 1;

const TWO = ONE * 2;

class C {

const THREE = TWO + 1;

const ONE_THIRD = ONE / self::THREE;

const SENTENCE = 'The value of THREE is '.self::THREE;

public function f($a = ONE + self::THREE) {

return $a;

}

}

echo (new C)->f()."


";

echo C::SENTENCE;

2、使用 ... 运算符定义变长参数函数和参数展开

echo '

';

// 把第三个以一的参数全部在函数中接收

function test($a,$b,...$c){

// 前两个参数给了$a和$b

echo $a.'---'.$b.'
';

// 后面的全部以一维数组的形式给了$c

print_r($c);

}

test(1,2,3,4,5,6,7);

echo '


';

// 使用 ... 运算符进行参数展开

$arr = [1,2,3,4,5];

test(...$arr);

3、导入命令空间中的常量和函数

对use运算符进行了扩展以支持在类中导入外部的函数和常量。对应的结构为 use function 和 use const

// 申明一个A命名空间

namespace A {

const AGE = 20;

function fun(){

echo "


你好!";

}

}

// 申明一个B命名空间

namespace B {

// 调用 命名空间A中的常量和函数 使用use

use const A\AGE;

use function A\fun;

echo '

';

var_dump(AGE);

fun();

}

三、PHP7.0

官网手册:http://php.net/manual/zh/migration70.new-features.php

解析顺序的变化

表达式                    PHP 5 的解析方式              PHP 7 的解析方式

$$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']()

所有 ext/mysql 函数已被删掉了

移除掉的 INI 配置指令

always_populate_raw_post_data 在php.ini文件中已经移除

always_populate_raw_post_data 只能用file_get_content('php://input')

要想在php5.6之前生效,还需要打开工php.ini中的配置文件 asp_tags = Off修改为 asp_tags = On 然后重启apache,此选项在php7之后被移除

asp_tags <%=$name;%>

1、标量类型声明[严格类型]

标量的类型的申明有两种模式:强制(默认)和严格模式。

字符串 string

布尔值 bool

整数 int

浮点 float

类[class]、接口[interface]、回调[callable]

①、强制模式[默认]

function test(array $arr){

echo '

';

var_dump($arr);

}

#test(1); // 报错

test([1,2,3]);

②、严格模式

默认情况下,如果能做到的话,PHP将会强迫错误类型的值转为函数期望的标量类型。 例如,一个函数的一个参数期望是string,但传入的是integer,最终函数得到的将会是一个string类型的值。

可以基于每一个文件开启严格模式。在严格模式中,只有一个与类型声明完全相符的变量才会被接受,否则将会抛出一个TypeError。 唯一的一个例外是可以将integer传给一个期望float的函数。

开启严格模式

使用 declare 语句和strict_types 声明来启用严格模式,声明指令必须放在文件的顶部,意味着严格声明标量是基于文件可配的, 这个指令不仅影响参数的类型声明,也影响到函数的返回值声明。

# 开启严格模式

declare(strict_types=1);

function test2(string $username,int $age){

echo '名称:'.$username;

echo '
';

echo '年龄:'.$age;

}

#test(1,20); # 报错

test2('小明',20);

2、返回值类型声明

返回类型声明指明了函数返回值的类型,类型有class,interface,array,int,callable,bool,float,int,string

# 开启严格模式

declare(strict_types=1);

// 返回值类型申明

function test2(int $age) : bool{

if ($age >20) {

return true;

}else{

return false;

}

}

if (test2(19)) {

echo '年龄有点的小';

}else{

echo '成年了';

}

# 使用它的时候,一定要有memcache扩展

function sum2(int $a, int $b): Memcache {

return new Memcache();

}

开启类型限定,可以极大的提升PHP在编译阶段对程序的执行速度的优化提升。

3、null合并运算符[重要]

简化了之前的三元表达式的写法

// php7.0 之前的写法

$username = $_GET['username'] ? $_GET['username'] : '没有名称';

echo $username;

echo '


';

// php7.0之后

$uname = $_GET['uname'] ?? '没有姓名';

echo $uname;

echo '


';

// 嵌套来运用

$age = $_GET['age'] ?? $_POST['age'] ?? '没有值';

echo $age;

4、太空船操作符(组合比较符)

太空船操作符用于比较两个表达式。当 $a 小于、等于或大于$b时它分别返回-1、0或1

// 比较两个变量的大小,如果a变量大于b变量,返回1

// 如果a变量等于b变量,返回0

// 如果a变量小于b变量,返回-1

function compare($a,$b){

if ($a > $b) {

return 1;

}elseif ($a == $b) {

return 0;

}elseif ($a < $b) {

return -1;

}

}

$a = 1;

$b = 2;

var_dump(compare($a,$b));

echo '
';

$a = 2;

$b = 2;

var_dump(compare($a,$b));

echo '
';

$a = 2;

$b = 1;

var_dump(compare($a,$b));

echo '


';

// php7.0之后来完成这样的需求

$a = 1;

$b = 2;

var_dump($a <=> $b); # -1

echo '
';

$a = 2;

$b = 2;

var_dump($a <=> $b); # 0

echo '
';

$a = 2;

$b = 1;

var_dump($a <=> $b); # 1

echo '


';

注:一定使用的场景多在一些算法场景中,如我们的排序,像【usort】可带回定义回调规则排序中,就可以运用。

$a = array(3, 2, 5, 6, 1);

usort($a,function ($v1,$v2){

return $v1 <=> $v2;

});

echo '

';

print_r($a);

5、通过 define() 定义常量数组

# 定义一个常量的数组

define('ADMINS',[

'admin',

'zhangsan',

'lisi',

[1,2,3]

]);

echo '

';

print_r(ADMINS);

echo ADMINS[1];

6、匿名类

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

// 匿名类

$obj = new class {

public $username = '小明


';

public function __construct(){

echo '这是一个匿名的类


';

}

};

echo $obj->username;

# 日志接口

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) {

return $msg;

}

});

var_dump($app->getLogger());

echo '


';

var_dump($app->getLogger()->log('111'));

7、Unicode 转译语法

每个汉字都有对应的unicode编码

PHP是世界上最好的语言

\u50\u48\u50\u662f\u4e16\u754c\u4e0a\u6700\u597d\u7684\u8bed\u8a00

像这样的编码在php7.0之后可以直接转化为汉字,人可识别的,php7.0之前的PHP的转化可以参考此地址来使用:http://blog.csdn.net/friendan/article/details/52900529

/**

* PHP是世界上最好的语言

* \u50\u48\u50\u662f\u4e16\u754c\u4e0a\u6700\u597d\u7684\u8bed\u8a00

*/

$unicodeStr =

"\u{50}\u{48}\u{50}\u{662f}\u{4e16}\u{754c}\u{4e0a}\u{6700}\u{597d}\u{7684}\u{8bed}\u{8a00}";

echo $unicodeStr;

注:定义的字符必须用双引号且还必须要用{}括起来不带\u的部份,应用的场景如emoji图标:

https://unicode-table.com/cn/sets/hearts-symbols/

8、Closure::call()

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

# 匿名函数

$fun2 = function(){

$this->say();

};

class Test {

private function say(){

echo 'Hi.
';

}

}

$fun2->call(new Test);

9、预期 assert

预期是向后兼用并增强之前的 assert() 的方法。 它使得在生产环境中启用断言为零成本,并且提供当断言失败时抛出特定异常的能力。它允许第一个参数是一个表达式,在调试测试中用。

// assert(true|false)

// 如果为true 得到了预期的结果,后面的结果不能执行

// 如果为false 没有得到预期的结果,执行后面

//assert(true,'1111');

assert(1+1>3 , new Exception('预期失败,异常抛出,条件不成立。'));

10、批量导入命名空间

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

namespace A {

class C1{}

class C2{}

function fun1(){echo 'fun1';}

function fun2(){echo 'fun2';}

const AGE1 = 20;

const AGE2 = 21;

}

// PHP 7 之前的代码

namespace B {

use A\C1;

use A\C2;

use function A\fun1;

use function A\fun2;

use const A\AGE1;

use const A\AGE2;

}

// PHP 7+ 及更高版本的代码

namespace C {

use A\{C1,C2};

use function A\{fun1,fun2};

use const A\{AGE1,AGE2};

var_dump(new C1());

echo '


';

var_dump(new C2());

echo '


';

fun1();

echo '


';

fun2();

echo '


';

echo AGE1;

echo '


';

echo AGE2;

echo '


';

}

11、生成器[yield]可以返回表达式

此特性基于 PHP 5.5 版本中引入的生成器特性构建的。 可以通过调用 Generator::getReturn() 方法来获取生成器的返回值, 但是这个方法只能在生成器完成产生工作以后调用一次。

function test(){

yield '1
';

yield '2
';

yield '3
';

return '我是返回值:4


';

}

$gen = test();

#echo $gen->getReturn(); # 报错,必须是生成循环完毕后才能执行它

foreach ($gen as $val) {

echo $val;

}

echo $gen->getReturn();

## 类JS的写法

$gen2 = (function() {

yield '张三';

yield '李四';

return '返回值';

})();

foreach ($gen2 as $val) {

echo $val, '
';

}

echo $gen2->getReturn(), '


';

四、PHP7.x

官网手册:http://php.net/manual/zh/migration71.new-features.php

1、可为空(Nullable)类型

类型现在允许为空,当启用这个特性时,传入的参数或者函数返回的结果要么是给定的类型,要么是 null 。可以通过在类型前面加上一个问号【?】来使之成为可为空的。

function test(?string $username,int $age){

echo "姓名:{$username} -- 年龄:{$age}


";

}

test('小明',20);

test(null,22);

2、 Void函数

对于 void 函数来说,null 不是一个合法的返回值

# 可以不写return 或 return;就可以,返回null会报错

function test() : void {

return; //表示返回void

echo 111;

//return null; # 报错,因为return null不能替换return;

}

test();

3、array赋值变量取出

短数组语法([])现在可以用于将数组的值赋给一些变量(包括在foreach中)。 这种方式使从数组中提取值变得更为容易。

$arr = [1,2];

[$a,$b] = $arr;

echo $a.' -- '.$b;

echo '


';

// 互换两个变量的值

$aa = 1;

$bb = 2;

[$aa,$bb] = [$bb,$aa];

echo $aa.' -- '.$bb;

echo '


';

// 定义数组

$data = [

['id' => 1,'name' => 'tom'],

['id' => 2,'name' => 'jack']

];

// 取出数组中的元素给指定的变量

['id' => $id,'name' => $name] = ['id' => 1,'name' => 'tom'];

echo $id.' --- '.$name.'
';

echo '


';

// 循环中取出数组中的元素给指定的变量

foreach($data as ['id' => $id,'name' => $name]){

echo $id.' --- '.$name.'
';

}

4、多异常捕获

一个catch语句块现在可以通过管道字符(|)来实现多个异常的捕获。 这对于需要同时处理来自不同类的不同异常时很有用。

class Exception1 extends Exception {

}

class Exception2 extends Exception {

}

class Exception3 extends Exception {

}

try {

throw new Exception('这里有异常了');

} catch (Exception1|Exception2|Exception3 $e) {

var_dump($e);

}

5、list()支持关联数组

现在list()支持在它内部去指定键名。这意味着它可以将任意类型的数组 都赋值给一些变量(与短数组语法类似)

$arr = ['username' => '张三', 'age' => 20];

list('username' => $username, 'age' => $age) = $arr;

echo $username . '----' . $age . '


';

$data = [

['id' => 1, 'name' => 'Tom'],

['id' => 2, 'name' => 'jack'],

];

echo '


';

// php7.1写法

foreach($data as list('id' => $id, 'name' => $name)){

echo $id . '----' . $name . '
';

}

你可能感兴趣的:(PHP5.5到PHP7的新特性)