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新版本变化

  • 相关阅读:
    测试用例编写思路
    pipenv和virtualenv
    HTTP协议
    性能测试实践
    性能测试
    JS创建类和对象
    servlet的转发与重定向
    早晚得看算法
    安卓开始啦
    写于大三下开学前(即将休学)
  • 原文地址:https://www.cnblogs.com/feiffy/p/9135811.html
Copyright © 2011-2022 走看看