• 首页
  • vue
  • TypeScript
  • JavaScript
  • scss
  • css3
  • html5
  • php
  • MySQL
  • redis
  • jQuery
  • 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';
    


    定义常量数组

    <?php
    define('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()获取类名将是系统自动生成的类名。相同的匿名类返回的名称当然也是相同的。
    • 当匿名类被嵌套进普通类后,不能访问这个外部类中使用privateprotected修饰的方法或者属性。如果要访问外部类使用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
    ?>