• 技术文章 >后端开发 >php教程

    PHP8.2将有哪些改动(性能改进、新特性)!

    青灯夜游青灯夜游2022-07-04 14:32:34转载310
    目前PHP8.2的发布时间还没有确定,但是预计将在2022年末发布。这篇文章将为你介绍在新版本中的功能、性能改进、弃用的特性等。

    相关推荐:PHP8.2最新进展,即将进行新特性冻结!

    null和false将作为独立的类型

    PHP并不会陷入到完美的类型安全方向中,但是从技术的角度考虑,将null和false作为独立的数据类型是值得的。一般情况下,PHP的很多常见的函数,会通过返回false表示出错了。比如在file_get_content中:

    file_get_contents(/* … */): string|false

    在以前,false可以在联合类型中使用,但是不能独立使用,在PHP8.2中可以单独使用:

    function alwaysFalse(): false
    {
        return false;
    }

    当然,对于这个做法,一些开发者都持谨慎态度。他并不支持true作为独立类型。这些开发者们认为,false只是一个值,类型应该代表类别而不是一个值。当然在类型系统中,有一个概念是单元类型,它是只允许一个值的类型。但是这真的有用吗?

    不过另一个RFC也正在讨论将true作为一种类型添加到PHP中。

    一个独立的null却很有意义,这样可以简单地实现空对象模式:

    class Post
    {
        public function getAuthor(): ?string { /* … */ }
    }
    
    class NullPost extends Post
    {
        public function getAuthor(): null { /* … */ }
    }

    这对NullPost::getAuthor()能够说它只会返回null,不必像以前那样必须将null和string一起联合声明。

    弃用动态属性

    对于语言规范来说,这是更好的设计,但是也会限制很多用法。动态属性在PHP8.2中被弃用,并且会在PHP中抛出错误异常。

    什么是动态属性?就是你没有在类中声明这些属性,但是仍然可以设置和获取:

    class Post
    {
        public string $title;
    }
    
    // …
    
    $post->name = 'Name';  // 在PHP8.2中不能这样使用,因为并没有在类中声明

    不过放心,__set和__get等魔术方法将仍然按预期中工作:

    class Post
    {
        private array $properties = [];
    
        public function __set(string $name, mixed $value): void
        {
            $this->properties[$name] = $value;
        }
    }
    
    // …
    
    $post->name = 'Name';

    标准对象也是如此:stdClass将继续支持动态属性。

    PHP曾经是一种动态程度很强的动态语言,但是现在已经有很多人愿意接受更加严格的编程方式了。尽可能的严格,尽可能的依赖静态分析是一件好事,这能让开发者们写出更好的代码。

    不过可能一部分很看重动态属性的开发人员对这种变化会很不满意,如果你不想在使用PHP8.2时看到这些警告,可以这样做:

    可以使用#[AllowDynamicProperties]

    #[AllowDynamicProperties]
    class Post
    {
        public string $title;
    }
    
    // …
    
    $post->name = 'Name'; // 一切正常

    另一种方法是修改报警级别,但不建议这样做。等你打算升级到PHP9.0时会遇到麻烦。

    error_reporting(E_ALL ^ E_DEPRECATED);

    追踪调用时参数脱敏

    什么叫参数脱敏?在我们开发时,遇到错误,都会使用Trace调试,但是目前的堆栈记录下一些敏感数据,比如环境变量、密码、用户。

    在PHP8.2中允许对参数进行一些编订( Redact ,姑且叫做编订,有一些修饰的意思,但直接称为修饰并不合适),比如将一些参数设置脱敏,这样这些参数的调用值不会在堆栈信息中列出:

    function test(
        $foo,
        #[\SensitiveParameter] $bar,
        $baz
    ) {
        throw new Exception('Error');
    }
    
    test('foo', 'bar', 'baz');

    如果报错的话,会发现,第二个参数bar并没有记录实际的值。这样能起到脱敏的作用,如果传的是密码的话,就不会别记录下来。

    Fatal error: Uncaught Exception: Error in test.php:8
    Stack trace:
    #0 test.php(11): test('foo', Object(SensitiveParameterValue), 'baz')
    #1 {main}
      thrown in test.php on line 8

    弃用了部分对象的调用方式

    一些以前的调用对象方式杯弃用了。这里面一些是需要通过call_user_func($callable)来调用的,而不是能够$callable()直接调用的。

    "self::method"
    "parent::method"
    "static::method"
    ["self", "method"]
    ["parent", "method"]
    ["static", "method"]
    ["Foo", "Bar::method"]
    [new Foo, "Bar::method"]

    为什么要这样做呢?Nikita在RFC讨论中很好的做出了解释:

    这些废弃的调用都是有关上下文的, “self::method”所指的方法取决于从哪个类执行调用或可调用性检查。实际上,当以[new Foo, "parent::method"]的形式使用时,这通常也适用于最后两种情况。

    减少可调用对象的上下文相关性是本RFC的次要目标。在这个RFC之后,唯一剩下的范围依赖是方法可见性:“Foo::bar”可能在一个范围内可见,但在另一个范围内不可见。如果将来可调用对象仅限于公共方法,那么可调用类型将变得明确定义并且可以用作属性类型。但是,对可见性处理的更改不建议作为本RFC的一部分。

    提升对未定义变量的检测机制和级别

    未定义的变量是那些在被读取之前还没有被初始化的变量。访问未定义的变量当前会发出E_WARNING“警告:未定义的变量$varname”,并将变量视为null,但不会中断执行,从而允许代码执行继续有增无减,但可能处于意外状态。

    目前可以通过一些配置,让PHP执行时对未定义变量产生错误级异常,但这需要单独配置。PHP应当默认提供更安全的检验。

    一般什么情况下会出现未定义变量的情况呢?

    用法1

    变量在某个分支中声明,比如在if中设置一个值。

    if  ( $user -> admin )  {
       $restricted  =  false ;
    }
    
    if  ( $restricted )  {
       die ( '你没有进入这里的权限' ) ;
    }

    用法2

    变量拼写错误:

    $name = 'Joe';
    echo 'Welcome, ' . $naame;

    这种用法在1中也可能会发生:

    if ($user->admin) {
       $restricted = false;
    } else {
       $restrictedd = true;
    }
    
    if ($restricted) {
       die('You do not have permission to be here');
    }

    用法3

    在循环中定义,但这个循环可能并没有执行:

    while ($item = $itr->next()) {
    
       $counter++; // 定义变量
    }
    
      // 这里调用了变量,但是很有可能并没有定义这个变量
    echo 'You scanned ' . $counter . ' items';

    解决方法

    在这些分支之前提前定义好一个默认值。

    对于第1种用法:

    $restricted = true;
    if ($user->admin) {
       $restricted = false;
    }
    
    if ($restricted) {
       die('You do not have permission to be here');
    }

    对于第3种用法:

    $counter = 0;
    while ($item = $itr->next()) {
       $counter++;
    }
    
    echo 'You scanned ' . $counter . ' items';

    这样做的好处是消除了整个访问和使用这些未定义变量的后果,以及回退到引擎默认状态的用户态错误。这样我们提供了另一层保护,防止PHP程序发生了这种意外后继续运行。

    这种更改也会让PHP引擎和JIT等方面不会那么复杂。

    这个版本主要是针对PHP9.0的,在PHP8.2的还是警告,在以后会将这种行为提升到错误级别。

    增加只读类

    通过给类添加只读修饰符来声明只读类。

    readonly class Test {
        public string $prop;
    }

    这样做会隐式地将类的所有实例属性标记为只读。此外,它将阻止创建动态属性。

    readonly class Foo
    {
        public int $bar;
    
        public function __construct() {
            $this->bar = 1;
        }
    }
    
    $foo = new Foo();
    $foo->bar = 2;
    // 抛出错误,不能修改只读属性 Foo::$bar
    
    $foo->baz = 1;
    // 抛出错误:不能动态创建属性 Foo::$baz

    可以通过增加#[AllowDynamicProperties]属性,可以不触发错误的情况下创建动态属性。

    #[AllowDynamicProperties]
    readonly class Foo {
    }

    一些限制:

    由于是只读类,必须对属性声明类型:

    readonly class Foo
    {
        public $bar;
    }
    // 以上定义会产生错误。

    不能使用静态属性:

    readonly class Foo
    {
        public static int $bar;
    }
    // 抛出错误: 只读属性不能声明静态类型

    原文地址:https://phpreturn.com/index/a626a74a300dc5.html

    原文平台:PHP武器库

    版权声明:本文由phpreturn.com(PHP武器库官网)原创和首发,所有权利归phpreturn(PHP武器库)所有,本站允许任何形式的转载/引用文章,但必须同时注明出处。

    推荐学习:《PHP视频教程

    以上就是PHP8.2将有哪些改动(性能改进、新特性)!的详细内容,更多请关注php中文网其它相关文章!

    声明:本文转载于:PHP武器库,如有侵犯,请联系admin@php.cn删除
    专题推荐:php
    上一篇:PHP8.2最新进展,即将进行新特性冻结! 下一篇:PHP如何使用xlswriter进行大数据的导入导出?(详解)
    20期PHP线上班

    相关文章推荐

    • 【活动】充值PHP中文网VIP即送云服务器• php可以部署到哪些服务器上• php怎么去除标签和空格• substr在php中是什么意思• php访问权限修饰符有哪几种• 【吐血整理】40+个PHP面试题附答案(实战经验)• php怎么改变数组key的值
    1/1

    PHP中文网