PHP 8.4 新特性 惰性对象

PHP 8.4 新特性 惰性对象

PHP 8.4 引入了惰性对象,这是一项设计旨在推迟对象初始化的特性,直到该对象被访问为止。这种方法降低了资源使用,尤其是对于那些可能只有在执行期间偶尔被使用的重初始化逻辑的对象。

默认对象和惰性对象之间有什么区别?

惰性对象通过动态创建的代理对象来推迟目标对象构造函数的执行。反射是生成该代理的关键,它模拟原始类,允许实际对象在被访问之前保持未初始化状态。


<?php

class  MyClass
{
     public  function  __construct(private  int  $foo)
    {
         echo  '访问方法会触发初始化'.PHP_EOL;
    }
     public  function  getFoo():  int
    {
         return  $this->foo;
    }

}

$object  =  new  MyClass(1);
echo  '对象已创建'.PHP_EOL;
echo  '调用对象 '.  $object->getFoo().  PHP_EOL;

如下输出


访问方法会触发初始化

对象已创建

调用对象,  输出  1

在这个例子中,当对象被创建时,MyClass 的构造函数会立即被调用,从而显示“访问方法会触发初始化”。该类有一个在运行时初始化的私有属性 $foo

使用惰性对象:


<?php

class  MyClass
{

     public  function  __construct(private  int  $foo)
    {
         echo  '访问方法会触发初始化'.PHP_EOL;
    }

     public  function  getFoo():  int
    {
         return  $this->foo;
    }

}
$initializer  =  static  function (MyClass  $ghost):  void {
 $ghost->__construct(123);
};

$reflector  =  new  ReflectionClass(MyClass::class);
$object  =  $reflector->newLazyGhost($initializer);
echo  '惰性对象已创建'.PHP_EOL;
echo  '调用惰性对象 '.  $object->getFoo().  PHP_EOL;

如下输出


惰性对象已创建

访问方法会触发初始化

调用惰性对,输出  123

在这段代码中,newLazyGhost 方法创建了一个惰性对象。初始化函数被定义为仅在调用方法时才初始化对象。ReflectionClass 对象负责创建一个非 MyClass 完整实例的代理对象,在调用 getFoo() 之前。

getFoo() 被调用时,构造函数被启动(显示“访问方法会触发初始化”),对象被初始化为 123,如输出所示。

惰性对象的优点:

性能提升:

延迟实例化减少内存使用,提高性能,尤其是在对象条件性访问时。

透明代理:

开发人员与惰性对象的交互方式与常规对象相同,无需额外的代理处理工作。

优化资源管理:

在依赖注入容器、ORM 系统或 API 集成等场景中非常有用,可将初始化推迟到需要时。

惰性对象的限制

序列化:

惰性对象可能会使序列化和反序列化变得困难,因为它们处于延迟状态。

调试复杂性:

堆栈跟踪可能包括代理层,使调试稍微复杂一些。

结论

PHP 8.4 中的惰性对象是提升现代应用程序性能和资源效率的强大工具。通过推迟初始化直到必要时,它们提供了一种更清晰、更可扩展的管理复杂对象生命周期的方法。

要了解更多有关惰性对象的信息,请访问官方 PHP RFC 页面。

原文转载

本作品采用《CC 协议》,转载必须注明作者和本文链接
《L05 电商实战》
从零开发一个电商项目,功能包括电商后台、商品 & SKU 管理、购物车、订单管理、支付宝支付、微信支付、订单退款流程、优惠券等
《G01 Go 实战入门》
从零开始带你一步步开发一个 Go 博客项目,让你在最短的时间内学会使用 Go 进行编码。项目结构很大程度上参考了 Laravel。
讨论数量: 8

第一种应该就是你说的默认对象吧,就是常规操作,你new的时候一定会调用构造函数,初始化。 但是你打印的内容就别搞成 惰性对象已创建 容易误导。

class MyClass
{
    public function __construct(private int $foo)
    {
        echo '构造函数被调用,初始化对象'.PHP_EOL;
    }
    public function getFoo(): int
    {
        return $this->foo;
    }
}

$object = new MyClass(1);
echo '对象已创建'.PHP_EOL;
echo '调用 getFoo 方法: '. $object->getFoo(). PHP_EOL;

第二种利用反射是 8.4 的新特性,通过代理对象推迟目标对象的构造函数执行。$initializer 是一个闭包(匿名函数),用来定义惰性对象在第一次被访问时应该如何初始化。

2个月前 评论
JaguarJack (楼主) 2个月前

之前在 laravel 中集成过 Ocramius/ProxyManager 实现了类似的功能(Binding virtual proxy example(Lazy Init))。后面 laravel 官方是不是可以给容器支持下了。

2个月前 评论
JaguarJack (楼主) 2个月前

常驻内存 这些都不是问题

2个月前 评论
JaguarJack (楼主) 2个月前
xiusin 2个月前
JaguarJack (楼主) 2个月前

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!