Menu

PHP 类和对象:属性、方法和 $this

PHP 类是用 class Name { } 声明的蓝图,new Name() 用它创建对象。本文讲解属性、方法、$this、public/private/protected、类型化属性和只读属性、__toString,以及为什么赋值一个对象并不会复制它。

本页包含可运行的编辑器。编辑、运行,立即查看输出。

PHP 类用 class Name { ... } 声明,里面包含属性(变量)和方法(函数)。new Name() 用它创建一个对象,-> 用来读取属性或调用方法:$user->name、$user->greet()。

类是蓝图,对象是按蓝图造出来的一个具体东西。同一个类可以创建任意多个对象,每个对象都有自己的属性值。

属性和方法

属性用一个访问控制关键字声明,类型和默认值可写可不写。方法就是类里面的函数。在方法内部,$this 是调用该方法的对象,所以 $this->balance 读取的是这个对象的余额。

每个对象都有自己的 $balance:往 $a 里存钱不会影响 $b。在 new 之后逐个设置属性很繁琐,构造函数可以直接把初始值作为参数接收。

public、private 和 protected

访问控制决定了谁可以访问属性或调用方法:

关键字可以访问的位置
public任何地方
protected类本身以及继承它的类
private只有声明它的类

把属性设为 private,再对外提供方法,类就能保护自己的规则。下面的例子中,余额只能通过 deposit() 和 withdraw() 修改,而这两个方法会拒绝不合法的金额:

在类外部读取私有属性不是警告,而是 Error:

类型化属性和未初始化的值

没有默认值的类型化属性一开始处于“未初始化”状态,这和 null 不一样。在赋值之前读取它会抛出 Error。解决办法是给它一个默认值、在构造函数中赋值,或者用 ?Type 和 = null 把它变成可为 null 的类型。

类型在赋值时检查。在默认的非严格模式下,$p->stock = '7' 会把数字字符串转换成 7,而 $p->stock = 'many' 会抛出 TypeError。

readonly 只读属性

readonly 属性(PHP 8.1)只能在类内部写入一次,之后就再也不能修改。它是构建金额、ID 这类值对象的常用方式。PHP 8.2 新增了 readonly class,让类的所有属性都变成只读。

只读属性必须声明类型,并且不能有默认值。如果需要一个修改过的副本,就创建一个新对象(new Order('B-2002')),而不是去改旧的对象。

用 __toString 输出对象

只有类定义了 __toString(),echo $object 才能正常工作。每当对象被当作文本使用时,比如在 echo 中、字符串拼接中或 "{$object}" 中,PHP 就会使用这个方法返回的字符串。

如果没有 __toString,echo $object 会抛出 Error(“Object of class Money could not be converted to string”)。调试时,print_r() 和 var_dump() 适用于任何对象,还会显示私有属性,参见 var_dump 和 print_r。

赋值对象并不会复制它

这是从数组转过来的人最容易踩的坑。赋值数组会复制整个数组,赋值对象只复制句柄:之后两个变量指向同一个对象。

clone 做的是浅拷贝:如果某个属性保存着另一个对象,两个副本仍然共享这个内部对象。=== 只有在是同一个对象时才为 true,而 == 比较的是同一个类的两个对象的属性值。把对象传给函数和赋值的效果一样,所以函数可以修改它收到的对象。

常见问题

PHP 中怎么用类创建对象?

用 new 加上类名:$user = new User();。如果类有构造函数,就把参数写在括号里,例如 new User('Ada')。之后用箭头运算符调用方法和读取属性:$user->name、$user->greet()。

PHP 中的 $this 是什么意思?

$this 是调用当前方法的那个对象。在 $ada->greet() 内部,$this 就是 $ada,所以 $this->name 读取的是 Ada 的名字。它只存在于非静态方法中。

PHP 中 public、private 和 protected 有什么区别?

public 成员在任何地方都能使用,private 成员只能在声明它的类内部使用,protected 成员可以在该类及其子类中使用。从外部读取私有属性会抛出 Error:Cannot access private property。

PHP 中对象是按引用传递的吗?

变量保存的是指向对象的句柄,而不是对象本身。$b = $a; 复制的是句柄,所以两个变量指向同一个对象,通过 $b 做的修改会在 $a 中体现。要得到一个独立的副本,请使用 $b = clone $a;。

PHP 中的 readonly 属性是什么?

声明为 public readonly string $id; 的属性(PHP 8.1+)只能在类内部赋值一次,之后再也不能修改。第二次写入会抛出 Error:Cannot modify readonly property。

Coddy 编程语言插图

和 Coddy 一起学编程

开始