0

0

PHP8.1新特性大讲解之readonly properties只读属性

藏色散人

藏色散人

发布时间:2021-11-10 15:14:47

|

3965人浏览过

|

来源于php中文网

原创

本文系翻译,原文地址:https://stitcher.io/blog/php-81-readonly-properties

php 8.1:只读属性

多年来,用 PHP 编写数据传输对象和值对象变得非常容易。以 PHP 5.6 中的 DTO 为例:

class BlogData
{
    /** @var string */
    private $title;
    
    /** @var Status */
    private $status;
    
    /** @var \DateTimeImmutable|null */
    private $publishedAt;
   
   /**
    * @param string $title 
    * @param Status $status 
    * @param \DateTimeImmutable|null $publishedAt 
    */
    public function __construct(
        $title,
        $status,
        $publishedAt = null
    ) {
        $this->title = $title;
        $this->status = $status;
        $this->publishedAt = $publishedAt;
    }
    
    /**
     * @return string 
     */
    public function getTitle()
    {
        return $this->title;    
    }
    
    /**
     * @return Status 
     */
    public function getStatus() 
    {
        return $this->status;    
    }
    
    /**
     * @return \DateTimeImmutable|null 
     */
    public function getPublishedAt() 
    {
        return $this->publishedAt;    
    }
}

并将其与PHP 8.0的等价物进行比较:

class BlogData
{
    public function __construct(
        private string $title,
        private Status $status,
        private ?DateTimeImmutable $publishedAt = null,
    ) {}
    
    public function getTitle(): string
    {
        return $this->title;    
    }
    
    public function getStatus(): Status 
    {
        return $this->status;    
    }
    
    public function getPublishedAt(): ?DateTimeImmutable
    {
        return $this->publishedAt;    
    }
}

这已经很不一样了,尽管我认为仍然存在一个大问题:所有这些吸气剂。就个人而言,自 PHP 8.0 及其提升的属性以来,我不再使用它们。我只是更喜欢使用公共属性而不是添加 getter:

class BlogData
{
    public function __construct(
        public string $title,
        public Status $status,
        public ?DateTimeImmutable $publishedAt = null,
    ) {}
}

面向对象的纯粹主义者不喜欢这种方法:对象的内部状态不应该直接暴露,并且绝对不能从外部改变。

立即学习PHP免费学习笔记(深入)”;

在我们在 Spatie 的项目中,我们有一个内部风格指南规则,即不应从外部更改具有公共属性的 DTO 和 VO;一种似乎效果很好的做法,我们已经做了很长一段时间了,没有遇到任何问题。

然而,是的;我同意如果语言确保公共属性根本不会被覆盖会更好。好吧,PHP 8.1通过引入readonly关键字解决了所有这些问题:

class BlogData
{
    public function __construct(
        public readonly string $title,
        public readonly Status $status,
        public readonly ?DateTimeImmutable $publishedAt = null,
    ) {}
}

这个关键字基本上就像它的名字所暗示的那样:一旦设置了一个属性,它就不能再被覆盖:

$blog = new BlogData(
    title: 'PHP 8.1: readonly properties', 
    status: Status::PUBLISHED, 
    publishedAt: now()
);
$blog->title = 'Another title';
Error: Cannot modify readonly property BlogData::$title

知道当一个对象被构造时,它不会再改变,在编写代码时提供了一定程度的确定性和平静:一系列不可预见的数据更改根本不会再发生。

当然,您仍然希望能够将数据复制到新对象,并可能在此过程中更改某些属性。我们将在本文后面讨论如何使用只读属性来做到这一点。首先,让我们深入了解一下它们。

您想要了解更多有关 PHP 8.1 的信息吗?有通往 PHP 8.1 的道路。在接下来的 10 天内,您将每天收到一封电子邮件,内容涉及 PHP 8.1 的一个新的和现有的特性;之后您将自动退订,因此不会收到垃圾邮件或后续邮件。 现在订阅!

#仅输入属性

只读属性只能与类型化属性结合使用:

class BlogData
{
    public readonly string $title;
    
    public readonly $mixed;
}

但是,您可以将其mixed用作类型提示:

class BlogData
{
    public readonly string $title;
    
    public readonly mixed $mixed;
}

这种限制的原因是通过省略属性类型,null如果在构造函数中没有提供显式值,PHP 将自动设置属性的值。这种行为与 readonly 相结合,会导致不必要的混乱。

#普通属性和提升属性

您已经看到了两者的示例:readonly可以在普通属性和提升属性上添加:

class BlogData
{
    public readonly string $title;
    
    public function __construct(
        public readonly Status $status, 
    ) {}
}

#无默认值

PHP与MySQL程序设计3
PHP与MySQL程序设计3

本书是全面讲述PHP与MySQL的经典之作,书中不但全面介绍了两种技术的核心特性,还讲解了如何高效地结合这两种技术构建健壮的数据驱动的应用程序。本书涵盖了两种技术新版本中出现的最新特性,书中大量实际的示例和深入的分析均来自于作者在这方面多年的专业经验,可用于解决开发者在实际中所面临的各种挑战。 本书内容全面深入,适合各层次PHP和MySQL开发人员阅读,既是优秀的学习教程,也可用作参考手册。

下载

只读属性不能有默认值:

class BlogData
{
    public readonly string $title = 'Readonly properties';
}

也就是说,除非它们是提升的属性:

class BlogData
{
    public function __construct(
        public readonly string $title = 'Readonly properties', 
    ) {}
}

它之所以被允许提升属性,是因为提升属性的默认值不作为类属性的默认值,但只适用于构造函数的参数。在幕后,上面的代码将转换为:

class BlogData
{
    public readonly string $title;
    
    public function __construct(
        string $title = 'Readonly properties', 
    ) {
        $this->title = $title;
    }
}

您可以看到实际属性如何没有被分配默认值。顺便说一下,不允许只读属性的默认值的原因是它们与该形式的常量没有任何不同。

#遗产

继承期间不允许更改 readonly 标志:

class Foo
{
    public readonly int $prop;
}
class Bar extends Foo
{
    public int $prop;
}

这条规则是双向的:readonly在继承过程中不允许添加或删除标志。

#不允许取消设置

一旦设置了只读属性,您就不能更改它,甚至不能取消它:

$foo = new Foo('value');
unset($foo->prop);

#反射

有一个新方法,以及一个标志。ReflectionProperty::isReadOnly()ReflectionProperty::IS_READONLY

#克隆

因此,如果您无法更改只读属性,并且无法取消设置它们,那么您如何创建 DTO 或 VO 的副本并更改其某些数据?您不能使用clone它们,因为您将无法覆盖其值。实际上有一个想法是clone with在未来添加一个允许这种行为的构造,但这并不能解决我们现在的问题。

好吧,如果您依靠一点反射魔法,您可以复制具有更改的只读属性的对象。通过创建一个对象而不调用它的构造函数(这可以使用反射),然后通过手动复制每个属性——有时覆盖它的值——你实际上可以“克隆”一个对象并更改其只读属性。

我做了一个小包来做到这一点,它是这样的:

class BlogData
{
    use Cloneable;
    public function __construct(
        public readonly string $title,
    ) {}
}
$dataA = new BlogData('Title');
$dataB = $dataA->with(title: 'Another title');

我实际上写了一篇专门的博客文章,解释了所有这些背后的机制,你可以在这里阅读。

所以,这就是关于只读属性的全部内容。如果您正在处理处理大量 DTO 和 VO 的项目,并且需要您仔细管理整个代码中的数据流,我认为它们是一个很棒的功能。具有只读属性的不可变对象在这方面有很大帮助。

相关文章

PHP速学教程(入门到精通)
PHP速学教程(入门到精通)

PHP怎么学习?PHP怎么入门?PHP在哪学?PHP怎么学才快?不用担心,这里为大家提供了PHP速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

更多
高德地图升级方法汇总
高德地图升级方法汇总

本专题整合了高德地图升级相关教程,阅读专题下面的文章了解更多详细内容。

65

2026.01.16

全民K歌得高分教程大全
全民K歌得高分教程大全

本专题整合了全民K歌得高分技巧汇总,阅读专题下面的文章了解更多详细内容。

121

2026.01.16

C++ 单元测试与代码质量保障
C++ 单元测试与代码质量保障

本专题系统讲解 C++ 在单元测试与代码质量保障方面的实战方法,包括测试驱动开发理念、Google Test/Google Mock 的使用、测试用例设计、边界条件验证、持续集成中的自动化测试流程,以及常见代码质量问题的发现与修复。通过工程化示例,帮助开发者建立 可测试、可维护、高质量的 C++ 项目体系。

33

2026.01.16

java数据库连接教程大全
java数据库连接教程大全

本专题整合了java数据库连接相关教程,阅读专题下面的文章了解更多详细内容。

39

2026.01.15

Java音频处理教程汇总
Java音频处理教程汇总

本专题整合了java音频处理教程大全,阅读专题下面的文章了解更多详细内容。

19

2026.01.15

windows查看wifi密码教程大全
windows查看wifi密码教程大全

本专题整合了windows查看wifi密码教程大全,阅读专题下面的文章了解更多详细内容。

85

2026.01.15

浏览器缓存清理方法汇总
浏览器缓存清理方法汇总

本专题整合了浏览器缓存清理教程汇总,阅读专题下面的文章了解更多详细内容。

19

2026.01.15

ps图片相关教程汇总
ps图片相关教程汇总

本专题整合了ps图片设置相关教程合集,阅读专题下面的文章了解更多详细内容。

11

2026.01.15

ppt一键生成相关合集
ppt一键生成相关合集

本专题整合了ppt一键生成相关教程汇总,阅读专题下面的的文章了解更多详细内容。

47

2026.01.15

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号