zoukankan      html  css  js  c++  java
  • PHP新版本变化

    世界变化真快,突然听闻 PHP 都到 7.3 版本了,7.2 还没仔细了解过呢。看到我司面试时会问到php新版本有什么特性,美名其曰考察其学习新技术的能力,我有点汗颜,自己都没有主动去了解过,实在不应该。因此,在这里立下一贴,用于记录新版本的PHP的变化,以及对实际工作的影响。

    PHP 7.0

    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'' 这五种类型。

    <?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,则返回之,否则返回第二个操作数。

    <?php
    // 这种场景,判断是否存在,如果不存在则赋值默认一个值
    $username = isset($_GET['user']) ? $_GET['user'] : 'nobody';
    
    // 使用 ?? 获得相同效果,代码却简洁很多
    $username = $_GET['user'] ?? 'nobody';
    
    // ?? 可以链式使用,第一个不存在,则判断第二个,第二个不存在再使用默认值
    $username = $_GET['user'] ?? $_POST['user'] ?? 'nobody';
    

    <=> 操作符

    '''<=>''' 操作符用于比较两个表达式。可以把这个操作符拆开来理解,'''<=>''' 一次就能判断出 小于<,等于=,大于> 这三种情况。

    <?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() 定义常量数组

    现在可以使用 define() 来定义常量数组了,而之前只能用 const 定义。

    <?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)测试更方便,为接口创建实时实现,而不用专门去建立一个只用一次的类。

    Unicode 转义语法

    语法如下例所示,可以直接通过16进制的代码来输出 Unicode 字符了。

    echo "u{5201}";
    echo "u{2200}";
    // output: 刁
    // output: ∀
    

    Closure::call()

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

    过滤的 unserialize()

    增加了反序列化对象时的安全性。开发者可以通过第二个参数来设置一个允许反序列化的类的白名单。

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

    增加了新的类 '''IntlChar''',它增加了国际化相关的功能,该类定义了大量的静态方法和静态常量,用于控制 Unicode 字符。

    使用该类,前提是安装了 Intl 扩展。

    Expectations

    Expectations 是 assert() 的向后兼容的增强。在php.ini中增加了 assert.expectation 指令以控制 assert() 的行为。

    use 声明分组

    可以将多个use声明合并为一个use

    <?php
    // pre PHP7
    use some
    amespace1ClassA;
    use some
    amespace1ClassB;
    use some
    amespace1ClassC as C;
    
    // PHP7+
    use some
    amespace1{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》#GeneratorsGenerators_(PHP)

    使用 intdiv() 进行整数除法

    var_dump(intdiv(10, 3));
    // output: int(3)
    

    session 选项

    现在 session_start() 可以接受一个 options 数组,以重写 php.ini 中的 session 设置。

    // 设置 session.cache_limiter 为私有,并且读取完就关闭session
    session_start([
        'cache_limiter' => 'private',
        'read_and_close' => true,
    ]);
    

    CSPRNG 函数

    新增两个生成加密整数和字符串的函数:random_bytes()random_int()

    PHP 7.1

    新增

    Nullable 类型

    现在可以在参数类型声明和返回值类型声明的类型前面加一个问号(?),来表示参数可以是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 返回值。void函数要么没有return语句,要么空return语句,返回NULL是错误的。

    Symmetric array destructuring

    短数组语法([])可以作为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 伪类

    增加了新的伪类:iterable,可以用于参数,或返回值类型,表示接受数组或实现了 Traversable 接口的对象。

    function iterator(iterable $iter)
    {
        foreach ($iter as $val) {
            //
        }
    }
    

    多重 catch 捕获

    可以在一个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() 可以指定键名

    现在可以在 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)
    

    Closure::fromCallable()

    增加了一个静态方法 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"
    

    PHP 7.2

    新增

    object 类型

    参数类型和返回值类型声明现在支持 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 成为核心扩展

    现代 Sodium 加密库已经成为PHP核心扩展。

    使用 Argon2 进行密码哈希

    Argon2 已经被添加到 password hash API中,通过以下常量使用:
    *PASSWORD_ARGON2I
    *PASSWORD_ARGON2_DEFAULT_MEMORY_COST
    *PASSWORD_ARGON2_DEFAULT_TIME_COST
    *PASSWORD_ARGON2_DEFAULT_THREADS

    扩展PDO字符串类型

    新增这些常量,扩展了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扩展新增地址信息获取

    新增下列方法,可以在连接时、绑定时或解释时查看地址信息:
    *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 FooBar{
        Foo,
        Bar,
        Baz,
    };
    

    ZIP扩展增强

    支持读写加密的压缩文件了(需要 libzip 1.2.0)

    现在 ZipArchive 实现了 Countable 接口。

    zip:// 流接受一个 password 上下文选项

    PHP 7.3

    References

    PS - 个人博客原文:PHP新版本变化

  • 相关阅读:
    Java实现 蓝桥杯VIP 基础练习 回形取数
    Java实现 蓝桥杯VIP 基础练习 回形取数
    Java实现 蓝桥杯VIP 基础练习 回形取数
    Java实现 蓝桥杯VIP 基础练习 回形取数
    Java实现 蓝桥杯VIP 基础练习 报时助手
    Java实现 蓝桥杯VIP 基础练习 报时助手
    Java实现 蓝桥杯VIP 基础练习 报时助手
    Java实现 蓝桥杯VIP 基础练习 报时助手
    Java实现 蓝桥杯VIP 基础练习 报时助手
    block的是发送信号的线程,又不是处理槽函数的线程
  • 原文地址:https://www.cnblogs.com/feiffy/p/9135811.html
Copyright © 2011-2022 走看看