Menu

PHP 构造函数:__construct 和属性提升

PHP 构造函数就是 __construct() 方法,在你写 new ClassName(...) 时自动运行。本文讲解构造函数属性提升、默认参数和命名参数、参数校验、parent::__construct(),以及如何用静态工厂方法模拟多个构造函数。

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

PHP 构造函数是一个名为 __construct() 的方法。当你写 new ClassName(...) 时,PHP 会自动调用它,括号里的参数会成为它的参数,所以对象一创建出来,各项值就已经设置好了。

如果没有构造函数,你得先创建一个空对象,再逐个设置属性,而且没有任何机制能阻止你漏掉一个。有了构造函数,不带参数的 new User() 就会抛出 ArgumentCountError。

构造函数属性提升

声明属性、把它列为参数、再赋值 $this->name = $name,每个名字都要重复写三遍。从 PHP 8.0 开始,在构造函数参数前加上访问控制关键字,就能一次完成这三件事:

提升的参数也可以是 readonly(public readonly string $id),这是编写不可变值对象最简短的方式。提升参数和普通参数可以混用,构造函数体中仍然可以写代码,它们会在提升属性赋值之后运行。

默认值和命名参数

构造函数的参数和普通函数一样可以有默认值。带默认值的参数要放在必填参数后面。使用命名参数(PHP 8.0)时,调用方可以直接跳到想设置的选项,而不必把它前面的每个默认值都重复一遍:

运行它:输出中包含 HTML,所以“页面”标签页会显示渲染好的三个按钮,“输出”标签页则显示 PHP 打印出的标签。注意 (new Button('Save'))->render() 中的括号:从 PHP 8.4 开始可以省略,但 PHP 8.3 必须写。

在构造函数中校验参数

构造函数不能返回 false 或错误码:它返回的任何值都会被忽略。要拒绝不合法的输入,就抛出异常。这样对象根本不会被创建,程序的其他部分就可以放心使用收到的每个 Temperature。

try catch 页面更详细地讲解了如何捕获这些异常。

用静态工厂方法实现多个构造函数

PHP 没有构造函数重载:一个类只有一个 __construct。当对象可以由不同的输入构建时(日期字符串、数组、时间戳),可以添加有名字的静态方法,由它们准备好参数并调用 new static(...)。把构造函数设为 private,就能强制所有人都通过工厂方法创建对象。

现在从类外部调用 new Color(1, 2, 3) 会抛出 Error(“Call to private Color::__construct() from global scope”)。static 页面解释了这里为什么用 new static 而不是 new self。

用 parent::__construct 调用父类构造函数

当子类定义了自己的构造函数时,父类的构造函数不会自动运行。用 parent::__construct(...) 调用它,通常放在第一行,这样父类的属性会在子类添加自己的属性之前设置好:

如果子类根本没有构造函数,PHP 会使用父类的构造函数,new Truck('Volvo') 会把参数直接传给 Vehicle::__construct。更多内容见继承。

忘记调用 parent::__construct

这个错误在出错的那一行不会产生任何报错。子类的构造函数照常运行,父类的类型化属性保持未初始化状态,程序直到后面第一次读取这些属性时才会失败:

在 Post::__construct 的第一行加上 parent::__construct();,再运行一次:它就会输出日期。与之相关的 __destruct() 方法会在对象的最后一个引用消失或脚本结束时运行。日常代码中很少需要它,因为 PHP 会在每个请求结束时自行关闭文件并释放内存。

常见问题

PHP 中的 __construct 是什么?

__construct() 就是构造函数:在 new 创建对象后,PHP 会立即自动调用这个方法。传给 new User('Ada', 36) 的参数会传给 __construct(string $name, int $age),它通常会把这些参数存到属性里。

PHP 中的构造函数属性提升是什么?

从 PHP 8.0 开始,给构造函数参数加上访问控制关键字,就能一步完成属性的声明和赋值:public function __construct(private string $name) {} 等同于声明 private string $name;,再在函数体中写 $this->name = $name;。

PHP 类可以有多个构造函数吗?

不可以。PHP 没有方法重载,所以一个类只有一个 __construct。可以使用带默认值的可选参数,或者添加静态工厂方法,例如 public static function fromArray(array $data): static,由它用正确的参数调用 new static(...)。

PHP 会自动调用父类的构造函数吗?

只有当子类没有自己的构造函数时才会。如果子类定义了 __construct,父类的构造函数就不会运行,除非你自己调用 parent::__construct(...),通常写在第一行。

PHP 构造函数可以返回值吗?

不可以。new 总是返回对象本身,__construct 返回的任何值都会被忽略。要报告问题,就在构造函数中抛出异常,例如 throw new InvalidArgumentException('Age must be positive')。

Coddy 编程语言插图

和 Coddy 一起学编程

开始