Home  >  Article  >  Backend Development  >  Detailed explanation of new features in PHP7.0 (example)

Detailed explanation of new features in PHP7.0 (example)

藏色散人
藏色散人forward
2019-03-20 13:56:424939browse


Detailed explanation of new features in PHP7.0 (example)

This article is mainly to analyze the new features of php7.0 in detail.

1. Performance and underlying layer

PHP7 is twice as fast as PHP5.6

php7 The most significant changes It is a huge improvement in performance and is close to the PHP execution engine HHVM developed by Facebook. In the WordPress benchmark performance test, the speed is 2 to 3 times faster than version 5.6, which greatly reduces memory usage. PHP7 also has some changes in the language, such as adding return type declarations and adding some new reserved keywords. In terms of security, PHP safe mode is removed, magic quotes are added, etc. Not only that, the new version also supports 64-bit and contains the latest version of the Zend engine.

Test it

A very simple example, generate an array of 600,000 elements, and determine whether the key exists by searching for the key.

<?php
$a = [];
for($i=0;$i<600000;$i++){
  $a[$i] = $i;
}
foreach($a as $item) {
 array_key_exists($item, $a);
}

We tested the performance on php5.6.11 and php7.0.4 respectively.

php5.6.11

➜ time php 1.php
  0.67s user 0.06s system 67% cpu 1.078 total
➜ time php 1.php
  0.68s user 0.06s system 98% cpu 0.748 total
➜ time php 1.php
  0.65s user 0.06s system 67% cpu 1.052 total

Averaging the three times, the user usage is roughly 0.65 seconds, the system usage is 0.06 seconds, and the CPU rate is 67%. About 1 second in total.

Look at the situation of php7

➜  time /usr/local/opt/php70/bin/php 1.php
  0.52s user 0.02s system 98% cpu 0.544 total
➜  time /usr/local/opt/php70/bin/php 1.php
  0.49s user 0.02s system 99% cpu 0.513 total
➜  time /usr/local/opt/php70/bin/php 1.php
  0.51s user 0.02s system 98% cpu 0.534 total

In comparison, the user usage time dropped by about 20%, the system usage time dropped by 70%, and the CPU usage rate was as high as 98%. The overall time is reduced to. 0.5 seconds.

Looking at this example, the efficiency is doubled. Not bad indeed.

Look at another example. It also generates an array of 600,000 elements to find whether value exists.

<?php
$a = [];
for($i=0;$i<600000;$i++){
    $a[$i] = $i;
}
foreach($a as $i) {
    array_search($i, $a);
}
?>

First look at php5.6.11

➜  testPHP time php 2.php
0.68s user 0.03s system 66% cpu 1.077 total
➜  testPHP time php 2.php
0.68s user 0.02s system 98% cpu 0.710 total
➜  testPHP time php 2.php
0.68s user 0.02s system 98% cpu 0.713 total
➜  testPHP time php 2.php
0.69s user 0.02s system 98% cpu 0.721 total

Then look at php7.0.4

➜  testPHP time /usr/local/opt/php70/bin/php 2.php
0.12s user 0.02s system 69% cpu 0.201 total
➜  testPHP time /usr/local/opt/php70/bin/php 2.php
0.11s user 0.01s system 97% cpu 0.131 total
➜  testPHP time /usr/local/opt/php70/bin/php 2.php
0.11s user 0.01s system 96% cpu 0.130 total

It is obvious that it is more than 6 times faster. sharp.

2. New features

1. More scalar type declarations

Now there are two modes for scalar in PHP : Enforcement (default) and strict mode. The following type parameters are now available (either in forced or strict mode): string, int, float, and bool. They extend other types introduced in PHP5: class names, interfaces, arrays and callback types. In the old version, function parameter declarations could only be (Array $arr), (CLassName $obj), etc. Basic types such as Int, String, etc. could not be declared.

How to understand? In versions before php7, if we want to limit the type of parameters of a function, there are only two types: array or class.

Before php7:

class MyInfo
{
    public $a = 123;
    public function getInfo(array $a, $b)
    {
        var_dump($a, $b);
    }
}
function getClass(MyInfo $a) {
    var_dump($a->a);
}

We want to limit the first parameter of getInfo to an array, so we can add an array before the parameter $a. to declare.

Similarly, we want the parameter of getClass to be a class, so we use the className of this class to declare it for mandatory use.

Before php7, only these two scalars could be used.

Let’s use it:

$info = new MyInfo();
$info->getInfo([1,2,3,4], 4);

We follow the regulations, pass the array as the first parameter, and of course the result will be printed normally:

➜  testPHP php 3.php
array(3) {
  [0] =>
  int(1)
  [1] =>
  int(2)
  [2] =>
  int(3)
}
int(4)

If we don’t install the regulations Come, a well-known error will be reported:

$info = new MyInfo();
$info->getInfo(122, 0);

Error report:

PHP Catchable fatal error:  Argument 1 passed to MyInfo::getInfo() must be of the type array, integer given, called in /Users/yangyi/www/testPHP/3.php on line 25 and defined in /Users/yangyi/www/testPHP/3.php on line 8
PHP Stack trace:
PHP   1. {main}() /Users/yangyi/www/testPHP/3.php:0
PHP   2. MyInfo->getInfo() /Users/yangyi/www/testPHP/3.php:25

The same is true for using the class:

$info = new MyInfo();
getClass($info);

Output result:

➜  testPHP php 3.php
int(123)

Similarly, we pass If you enter other parameters, an error will be reported:

getClass(123);
➜  testPHP php 3.php
PHP Catchable fatal error:  Argument 1 passed to getClass() must be an instance of MyInfo, integer given, called in /Users/yangyi/www/testPHP/3.php on line 27 and defined in /Users/yangyi/www/testPHP/3.php on line 17
PHP Stack trace:
PHP   1. {main}() /Users/yangyi/www/testPHP/3.php:0
PHP   2. getClass() /Users/yangyi/www/testPHP/3.php:27

Let’s go back to the php7 upgrade, which expanded the scalar types and added bool, int, string, and float.

php7 has 2 two modes: mandatory (default) and strict mode.

Forced mode

Forced mode is the default mode. In forced mode, it will help us convert the numeric type string type, int integer type, bool, and forced type. Other types cannot be converted and an error will be reported.

Still the example just now:

class MyInfo
{
    public $a = 123;
    public function get1(bool $b)
    {
        var_dump($b);
    }
    public function get2(int $b)
    {
        var_dump($b);
    }
    public function get3(string $b)
    {
        var_dump($b);
    }
    public function get4(float $b)
    {
        var_dump($b);
    }
    public function get5(array $b)
    {
        var_dump($b);
    }
}

Let’s first pass in all int 1

$info = new MyInfo();
$info->get1(1);
$info->get2(1);
$info->get3(1);
$info->get4(1);

and look at the printed result, it has already been forced to convert for us.

➜  testPHP /usr/local/opt/php70/bin/php 3.php
/Users/yangyi/www/testPHP/3.php:11:
bool(true)
/Users/yangyi/www/testPHP/3.php:19:
int(1)
/Users/yangyi/www/testPHP/3.php:26:
string(1) "1"
/Users/yangyi/www/testPHP/3.php:33:
double(1)

Let’s continue and pass in string 1.23:

$info = new MyInfo();
$info->get1(&#39;1.23&#39;);
$info->get2(&#39;1.23&#39;);
$info->get3(&#39;1.23&#39;);
$info->get4(&#39;1.23&#39;);

Take a look and print the result. It has also been forced to convert for us.

➜  testPHP /usr/local/opt/php70/bin/php 3.php
/Users/yangyi/www/testPHP/3.php:11:
bool(true)
/Users/yangyi/www/testPHP/3.php:19:
int(1)
/Users/yangyi/www/testPHP/3.php:26:
string(4) "1.23"
/Users/yangyi/www/testPHP/3.php:33:
double(1.23)

But if the parameter is an array, we cannot force the conversion, and an error will be reported:

$info->get5(&#39;1.23&#39;);
 testPHP /usr/local/opt/php70/bin/php 3.php
PHP Fatal error:  Uncaught TypeError: Argument 1 passed to MyInfo::get5() must be of the type array, string given, called in /Users/yangyi/www/testPHP/3.php on line 54 and defined in /Users/yangyi/www/testPHP/3.php:37

Will we report an error when we run these codes in PHP5.6.11? Give it a try:

$info = new MyInfo();
$info->get1(&#39;1.23&#39;);
$info->get2(&#39;1.23&#39;);
$info->get3(&#39;1.23&#39;);
$info->get4(&#39;1.23&#39;);
➜  testPHP php 3.php
PHP Catchable fatal error:  Argument 1 passed to MyInfo::get1() must be an instance of bool, string given, called in /Users/yangyi/www/testPHP/3.php on line 48 and defined in /Users/yangyi/www/testPHP/3.php on line 8

Okay. An error was reported directly. Although the error message also said that the type was wrong, other declarations of these types were not supported.

strict mode

As mentioned before, in forced mode, it will help us force conversion, so what about strict mode?

First of all, how to turn on strict mode?

<?php
declare(strict_types=1);

Just add it. In this way, you will enter strict mode. The parameters must comply with the regulations, otherwise an error will be reported:

Let’s add this sentence and run it again:

<?php
declare(strict_types=1);
...
...
$info = new MyInfo();
$info->get1(&#39;1.23&#39;);
$info->get2(&#39;1.23&#39;);
$info->get3(&#39;1.23&#39;);
$info->get4(&#39;1.23&#39;);

Run it and look at the results. Sure enough, an error is reported directly.

PHP Fatal error:  Uncaught TypeError: Argument 1 passed to MyInfo::get1() must be of the type boolean, string given, called in /Users/yangyi/www/testPHP/3.php on line 49 and defined in /Users/yangyi/www/testPHP/3.php:9

2. Return value type declaration

We know that PHP functions do not have return value types. Whatever type is returned is the type. The return value type has been added in php7, and we can define the return value type of a function.

Same as the scalar type declaration in PHP7 upgrade, the return type can be the following: bool, int, string, float, array, class.

For example, if we want the return value of a function to be an array, we can write it like this:

: array {} // colon + return type

function returnInfo ($a) : array {
    return $a;
}
var_dump(returnInfo([1,2,3]));

Don’t you think it’s strange and incredible! ! !

View the print results:

➜  testPHP /usr/local/opt/php70/bin/php 3.php
/Users/yangyi/www/testPHP/3.php:64:
array(3) {
  [0] =>
  int(1)
  [1] =>
  int(2)
  [2] =>
  int(3)
}

Similarly, we want to return an integer type:

function returnInfo ($a) : int {
    return $a;
}
var_dump(returnInfo(&#39;1.233&#39;));

查看结果,他已经帮我们强制转换成整型了。

➜  testPHP /usr/local/opt/php70/bin/php 3.php
/Users/yangyi/www/testPHP/3.php:64:
int(1)

同样,我们可以返回一个class类型的:

public function getLogger(): Logger {
    return $this->logger;
}

默认,也是强制模式,会帮我们转换,如果,我们想使用严格模式,同样是一样的,在文件头部加上:

<?php
declare(strict_types=1);

就可以了,这样,我们规定返回值是什么类型,就必须得是这样,不然就报致命报错。

3. null合并运算符 (??)

由于日常使用中存在大量同时使用三元表达式和 isset()的情况, php7增加了一个新的语法糖 : null合并运算符 (??)

如果变量存在且值不为NULL, 它就会返回自身的值,否则返回它的第二个操作数。

//php version = 7 
$username = $user ?? &#39;nobody&#39;;
//php  version < 7 得这样使用:
$username = isset($_GET[&#39;user&#39;]) ? $_GET[&#39;user&#39;] : &#39;nobody&#39;;

确实方便了很多。

我记得php5.3的更新中,加入了 三元运算符简写形式:

$a ?: $b

千万别和??搞混淆了!!!

$a ?: $b的意思是 $a为true时,直接返回$a, 否则返回$b

$a ?? $b的意思是 $a isset($a)为true, 且不为NULL, 就返回$a, 否则返回$b。

看例子:

$user = 0;
$username = $user ?? &#39;nobody&#39;;
echo $username;  //输出 0,因为 0 存在 且 不为NULL。
$username = $user ?: &#39;nobody&#39;;
echo $username; //输出 &#39;nobody&#39;,因为 0 为 false

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

php7 中,新加入了一个比较符号:96b4fef55684b9312718d5de63fb7121 ,因为长相像太空船,所以,也叫太空船操作符。

它有啥用呢?

96b4fef55684b9312718d5de63fb7121用于比较两个表达式。当$a小于、等于或大于$b时它分别返回-1、0或1。

看例子:

<?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
?>

其实,蛮多地方可以派上用场的。

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

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

在php5.3中,增加了可以使用const来申明常量,替代define()函数,但是只能申明一些简单的变量。

//旧式风格:
define("XOOO", "Value");
//新式风格:
const XXOO = "Value";
//const 形式仅适用于常量,不适用于运行时才能求值的表达式:
// 正确
const XXOO = 1234;
// 错误
const XXOO = 2 * 617;

在php5.6中,又对const进行来升级,可以支持上面的运算了。

const A = 2;
const B = A + 1;

但是,一只都是在优化const,可是确把define()给搞忘记了,php 5.6申明一个数组常量,只能用const。所以,在 php7 中把 define()申明一个数组也给加上去了。

//php 7
define (&#39;AWS&#39; , [12,33,44,55]);
// php < 7
const QWE = [12,33,44,55];
echo AWS[1]; //12
echo QWE[2]; //33

至此,到php7版本,define()的功能和const就一摸一样了,所以,你随便用哪一个都可以,但是因为在class类中,什么常量是const。所以,我们就统一用const申明常量好了。

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());
?>

我们先输出的打印的结果,显示为匿名类:

class class@anonymous#2 (0) {
}

我们来分解下,还原被偷懒的少写的代码:

class logClass implements Logger {
    public function log(string $msg) {
        echo $msg;
    }
}
$app = new Application;
$log2 = new logClass;
$app->setLogger($log2);

输出结果为:

class logClass#2 (0) {
}

虽然代码简洁了很多,但是还是有点不适应,多用用就好了。

还记得php中的匿名函数嘛?在php5.3中新增的匿名函数,结合新的,顺便复习下:

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
)

7. Unicode codepoint 转译语法

ps : 由于用的少,我就直接抄官网的说明了。

这接受一个以16进制形式的 Unicode codepoint,并打印出一个双引号或heredoc包围的 UTF-8 编码格式的字符串。 可以接受任何有效的 codepoint,并且开头的 0 是可以省略的。

echo "\u{0000aa}";
echo "\u{aa}"; //省略了开头的0
echo "\u{9999}";

看下输出:

ª ª 香

我们在php5.6环境下执行下呢?会怎样:

\u{aa} \u{0000aa} \u{9999}

好吧,直接原样输出了。

8. Closure::call() 闭包

ps : 由于用的少,我就直接抄官网的说明了。

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

<?php
class A {private $x = 1;}
// php 7之前:
$getXCB = function() {return $this->x;};
$getX = $getXCB->bindTo(new A, &#39;A&#39;); // intermediate closure
echo $getX();
// PHP 7:
$getX = function() {return $this->x;};
echo $getX->call(new A);

会输出:

1
1

9. 为unserialize()提供过滤

unserialize 这个函数应该不陌生,它是php中用解开用serialize序列化的变量。

看个栗子:

<?php
$a = [1,2,3,4,5,6];
$b = serialize($a);
$c = unserialize($b);
var_dump($a, $b, $c);

打印结果为:

array(6) {
  [0] =>
  int(1)
  [1] =>
  int(2)
  [2] =>
  int(3)
  [3] =>
  int(4)
  [4] =>
  int(5)
  [5] =>
  int(6)
}
string(54) "a:6:{i:0;i:1;i:1;i:2;i:2;i:3;i:3;i:4;i:4;i:5;i:5;i:6;}"
array(6) {
  [0] =>
  int(1)
  [1] =>
  int(2)
  [2] =>
  int(3)
  [3] =>
  int(4)
  [4] =>
  int(5)
  [5] =>
  int(6)
}

现在php7中unserialize会变得更佳好用,它多了一个参数,用来反序列化包涵class的过滤不需要的类,变的更加安全。

unserialize($one, ["allowed_classes" => true]);
    unserialize($one, ["allowed_classes" => false]);
    unserialize($one, ["allowed_classes" => [class1,class2,class3]]);

举个例子,先序列化一个类。

class MyInfo {
        public function getMyName()
        {
                return &#39;phper&#39;;
        }
}
$phper = new MyInfo();
$one = serialize($phper);
//参数allowed_classes 设置为 true,表示允许解析class
$two = unserialize($one, ["allowed_classes" => true]);
//参数allowed_classes 设置为 false,表示不允许解析class
$three = unserialize($one, ["allowed_classes" => false]);
//不加参数。正常解析。
$four = unserialize($one);
//只允许解析 类 MyInfo1。
$five = unserialize($one, ["allowed_classes" => ["MyInfo1"]]);
//分别输出下 getMyName方法;
var_dump($one);
var_dump($two->getMyName());
var_dump($three->getMyName());
var_dump($four->getMyName());
var_dump($five->getMyName());

发现3和5直接报致命错误了:

PHP Fatal error:  main(): The script tried to execute a method or access a property of an incomplete object. Please ensure that the class definition "MyInfo" of the object you are trying to operate on was loaded _before_ unserialize() gets called or provide a __autoload() function to load the class definition  in /Users/yangyi/www/php7/5.php on line 22

大致意思就是,没权限解析。

所以,我们改一下:

$three = unserialize($one, ["allowed_classes" => true]);
$five = unserialize($one, ["allowed_classes" => ["MyInfo"]]);

再输出,就正常了。

/Users/yangyi/www/php7/5.php:22:
string(17) "O:6:"MyInfo":0:{}"
/Users/yangyi/www/php7/5.php:23:
string(5) "phper"
/Users/yangyi/www/php7/5.php:24:
string(5) "phper"
/Users/yangyi/www/php7/5.php:25:
string(5) "phper"
/Users/yangyi/www/php7/5.php:26:
string(5) "phper"

发现我目前为止并没用到,并没有什么乱用,好吧,继续下一个。

10. IntlChar

ps : 由于用的少,我就直接抄官网的说明了。

新增加的 IntlChar(http://php.net/manual/zh/class.intlchar.php) 类旨在暴露出更多的 ICU 功能。这个类自身定义了许多静态方法用于操作多字符集的 unicode 字符。

<?php
printf(&#39;%x&#39;, IntlChar::CODEPOINT_MAX);
echo IntlChar::charName(&#39;@&#39;);
var_dump(IntlChar::ispunct(&#39;!&#39;));

以上例程会输出:

10ffff
COMMERCIAL AT
bool(true)

若要使用此类,请先安装Intl扩展

相关推荐:《PHP7新特性手册

The above is the detailed content of Detailed explanation of new features in PHP7.0 (example). For more information, please follow other related articles on the PHP Chinese website!

Statement:
This article is reproduced at:zybuluo.com. If there is any infringement, please contact admin@php.cn delete