当前位置: 首页 > news >正文

【PHP属性详解:从基础到只读的完全指南】

《PHP属性详解:从基础到只读的完全指南》

属性基础:类的“部件”

属性是类的变量,代表对象的状态或特征。

class Robot {public $name; // 一个简单的属性
}
类型化属性 (PHP 7.4+):给部件“定类型”

避免属性乱装东西。从 PHP 7.4 起,可以明确属性的类型。

class Robot {public string $name;     // 必须是字符串public int $age;         // 必须是整数public ?float $height;   // 可以是浮点数或 nullpublic array $tools;     // 必须是数组// 注意:callable 不能作为属性类型
}

好处:代码更健壮,IDE 更智能。

只读属性 readonly (PHP 8.1+):锁定部件

让属性一旦初始化就不可更改。这是实现“不可变对象”的关键。

class Robot {public readonly string $serialNumber; // 序列号,出厂后不能改!public function __construct(string $serial) {$this->serialNumber = $serial; // ✅ 构造函数内初始化(唯一机会)}
}$robot = new Robot("SN123");
// $robot->serialNumber = "SN456"; // ❌ Fatal error! 不能修改
echo $robot->serialNumber; // ✅ 可以读取

⚠️ 核心规则

  1. 必须初始化readonly 属性必须在构造函数(或 __clone)中赋值一次。
  2. 禁止默认值public readonly string $name = "default";语法错误!只读属性不能有默认值。
  3. 仅限类型化属性:必须先声明类型。
  4. 不支持静态static readonly不支持
readonly 的精髓:引用 vs 内容

readonly 保护的是“引用”(指向哪里),不是“内容”(里面有什么)。

class Robot {public readonly array $inventory; // 只读数组public readonly object $sensor;   // 只读对象
}$robot = new Robot();
$robot->inventory = ['screwdriver']; // ✅ 初始化
$robot->sensor = new stdClass();     // ✅ 初始化// ❌ 错误!试图改变“引用”
// $robot->inventory = ['wrench']; // 不行!不能换整个数组!
// $robot->sensor = new stdClass(); // 不行!不能换整个对象!// ✅ 正确!修改“内容”(内部可变性)
$robot->inventory[] = 'wrench';      // 给 inventory 数组添加新工具 ✅
$robot->sensor->temperature = 25;    // 给 sensor 对象添加属性 ✅

总结readonly 保证“背包”和“传感器”不被替换,但允许往背包里装东西或给传感器升级。

类级别的 readonly (PHP 8.2+):一键锁定

直接标记整个类为 readonly

readonly class Robot {public function __construct(public string $name,public int $age) {}
}$robot = new Robot("小助手", 5);
// $robot->name = "大助手"; // ❌ 错误!所有属性只读
// $robot->newProp = "test"; // ❌ 错误!禁止动态属性!
  • 效果:所有声明的属性自动 readonly,并禁止创建动态属性
  • 继承:子类也必须是 readonly 类。
readonly 的“写权限”大变革 (PHP 8.4+)

PHP 8.3 及之前readonly 属性的“写权限”是隐式 private

  • 只有声明该属性的类本身可以在其构造函数中初始化它。
  • 子类无法直接初始化继承的 readonly 属性,必须依赖父类构造函数。
// PHP 8.3
class ParentRobot {public readonly string $name;
}
class ChildRobot extends ParentRobot {public function __construct(string $name) {// parent::__construct($name); // ❌ 必须调用父类// $this->name = $name; // ❌ 子类不能写!}
}

PHP 8.4+readonly 属性的“写权限”变为隐式 protected(set)

  • “读权限” (get) 由 public/protected/private 决定。
  • “写权限” (set) 默认为 protected子类也可以直接初始化
// PHP 8.4+
class ParentRobot {public readonly string $name;// 父类甚至可以没有构造函数!
}
class ChildRobot extends ParentRobot {public function __construct(string $name) {$this->name = $name; // ✅ 太棒了!子类可以直接初始化!}
}
  • 显式控制 (PHP 8.4+) :可以用 public(set), protected(set), private(set) 精确控制写权限。
克隆时的 readonly (PHP 8.3+)

克隆对象时,readonly 属性也需要在新对象中初始化。使用 __clone() 方法。

class Robot {public readonly ?string $status;public function __clone() {$this->status = "Cloned"; // ✅ 在克隆时重新初始化}
}$robot1 = new Robot();
$robot1->status = "Active";
$robot2 = clone $robot1;
var_dump($robot2->status); // string(6) "Cloned"
final 常量 (PHP 8.1.0+):锁定常量

在 PHP 8.1 之前,只有方法可以被标记为 final,常量不行。从 PHP 8.1.0 起,常量也可以被标记为 final

  • 目的:防止子类重新定义(覆盖)某个核心常量,确保其值在继承链中保持不变。
  • 效果:一旦常量被标记为 final,任何尝试在子类中重新定义它的行为都会导致致命错误

例子:

class MathConstants {// 普通常量,子类可以覆盖public const PI = 3.14159;// final 常量,子类禁止覆盖!public final const E = 2.71828;
}// 错误示例:尝试覆盖 final 常量
// class WrongPhysicsConstants extends MathConstants {
//     public const E = 2.7; // Fatal error: Cannot override final constant MathConstants::E
// }// 正确示例:只覆盖非 final 常量
class PhysicsConstants extends MathConstants {public const PI = 3.14; // ✅ 合法!覆盖非 final 的 PI// E 常量会直接继承,值为 2.71828
}// 测试
echo PhysicsConstants::PI; // 输出: 3.14
echo PhysicsConstants::E;  // 输出: 2.71828

关键点总结: 如果某个常量的值是“基石”或“标准”,不希望被子类修改,就用 final 标记它。

http://www.dtcms.com/a/308779.html

相关文章:

  • 企业智脑1.3.1技术升级全面解读:AI笔记引擎如何重塑企业知识管理范式
  • 计算机系统基础与操作系统笔记
  • Spring Boot Admin 监控模块笔记-实现全链路追踪
  • 另外几种语言挑战100万行字符串文本排序
  • Web开发-PHP应用原生语法全局变量数据接受身份验证变量覆盖任意上传(代码审计案例)
  • 风力发电场景下设备状态监测与智能润滑预测性维护策略
  • 【Python气象可视化】用Cartopy+Matplotlib绘制青藏高原涡移动轨迹图(附完整代码+颜色渐变时间轴)
  • 数据库学习--------数据库日志类型及其与事务特性的关系
  • 题目:BUUCTF之rip(pwn)
  • [算法]Leetcode3487
  • 【高等数学】第七章 微分方程——第五节 可降阶的高阶微分方程
  • 第三章·数据链路层
  • 前端路由深度解析:Hash 模式 vs. History 模式
  • 数字化应急预案:构筑现代安全防线
  • 实时语音流分段识别技术解析:基于WebRTC VAD的智能分割策略
  • MySQL 中的事务隔离级别有哪些?分别解决什么问题?
  • 图结构知识构造方法详解 ——面向垂直领域的高效知识库构建方案
  • CentOS 7 编译 Redis 6.x 完整教程(解决 GCC 版本不支持 C11)
  • lesson29:Python元类与抽象类深度解析:从接口定义到元编程实践
  • mysql 日志机制
  • Java 接口(上)
  • 哈希相关的模拟实现
  • 04百融云策略引擎项目laravel实战步完整安装composer及tcpdf依赖库和验证-优雅草卓伊凡
  • 常用的ROS(Robot Operating System,机器人操作系统)包,用于机器人软件开发的工具和库
  • isasssim robotiq夹爪踩坑
  • 同个主机拉取不同权限仓库的方法
  • 疯狂星期四文案网第25天运营日记
  • Product Hunt 每日热榜 | 2025-07-31
  • 零信任网络概念及在网络安全中的应用
  • 2025年渗透测试面试题总结-2025年HW(护网面试) 80(题目+回答)