PHP 属性教程
上次修改时间:2025 年 5 月 18 日
在本文中,我们介绍了 PHP 属性。
PHP 中的属性是属于类的变量,封装数据并允许对象存储相关信息。每个属性都与特定的可见性级别相关联,决定了它在程序中的可访问性。属性也可以是静态的或非静态的,影响它们是属于类还是实例。
PHP 属性的类型
- 公共属性: 可从程序的任何地方访问。
- 受保护的属性: 仅在类及其子类中可访问。
- 私有属性: 仅限于定义类,确保封装性。
- 静态属性: 属于类本身,而不是实例。
属性对于 PHP 中的面向对象编程至关重要,允许类维护状态和行为。它们可以用各种可见性级别声明,并且 PHP 7.4 引入了类型属性以提高类型安全性。PHP 8.0 增加了构造函数属性提升,减少了在构造函数中初始化属性时的样板代码。
基本属性声明
属性在类中使用以下可见性关键字之一声明:public、protected 或 private。公共属性可以从任何地方访问,受保护的属性只能在类及其后代中访问,而私有属性只能在声明类中访问。
<?php
declare(strict_types=1);
class User {
public $name;
protected $email;
private $password;
public function __construct($name, $email, $password) {
$this->name = $name;
$this->email = $email;
$this->password = $password;
}
public function getEmail() {
return $this->email;
}
}
$user = new User('John Doe', 'john@example.com', 'secret123');
echo "Name: {$user->name}\n"; // Works - public
// echo "Email: {$user->email}\n"; // Error - protected
// echo "Pass: {$user->password}\n"; // Error - private
echo "Email: {$user->getEmail()}\n"; // Works - accessed via method
此示例展示了具有不同可见性级别的属性声明。公共属性可以直接访问,而受保护和私有属性需要方法才能访问它们。构造函数在创建新对象时初始化所有属性。
λ php basic_properties.php Name: John Doe Email: john@example.com
属性类型声明
PHP 7.4 引入了类型属性,允许您指定属性的类型。这有助于尽早捕获与类型相关的错误,并使代码更易于维护。支持的类型包括所有 PHP 类型和自定义类。
<?php
declare(strict_types=1);
class Product {
public int $id;
public string $name;
public float $price;
public bool $inStock;
public ?DateTime $createdAt; // Nullable
public function __construct(int $id, string $name, float $price) {
$this->id = $id;
$this->name = $name;
$this->price = $price;
$this->inStock = true;
$this->createdAt = new DateTime();
}
public function setPrice(float $newPrice): void {
if ($newPrice <= 0) {
throw new InvalidArgumentException("Price must be positive");
}
$this->price = $newPrice;
}
}
$product = new Product(1, 'Laptop', 999.99);
$product->setPrice(899.99);
echo "Product: {$product->name}, Price: {$product->price}\n";
echo "Created at: {$product->createdAt->format('Y-m-d')}\n";
// This would cause a TypeError
// $product->price = "free";
类型属性确保值与声明的类型匹配。该示例显示了各种类型声明,包括可空类型(带有 ? 前缀)。类型检查发生在赋值和访问属性时。
λ php typed_properties.php Product: Laptop, Price: 899.99 Created at: 2025-05-18
静态属性
静态属性属于类,而不是任何对象实例。它们在类的所有实例之间共享,无需创建对象即可访问。使用 static 关键字来声明它们。
<?php
declare(strict_types=1);
class Counter {
public static int $count = 0;
public int $instanceCount = 0;
public function __construct() {
self::$count++;
$this->instanceCount++;
}
public static function getCount(): int {
return self::$count;
}
}
// Access static property without creating an instance
echo "Initial count: " . Counter::$count . "\n";
$c1 = new Counter();
$c2 = new Counter();
$c3 = new Counter();
echo "Static count: " . Counter::getCount() . "\n";
echo "Instance 1 count: {$c1->instanceCount}\n";
echo "Instance 2 count: {$c2->instanceCount}\n";
echo "Instance 3 count: {$c3->instanceCount}\n";
// Late Static Binding
class ParentClass {
protected static string $name = 'Parent';
public static function getName(): string {
return static::$name; // 'static' instead of 'self'
}
}
class ChildClass extends ParentClass {
protected static string $name = 'Child';
}
echo ParentClass::getName() . "\n"; // Outputs 'Parent'
echo ChildClass::getName() . "\n"; // Outputs 'Child'
静态属性在所有实例中保持其值。该示例演示了静态 $count 如何为每个新对象递增,而 $instanceCount 保持每个实例特有。后期静态绑定允许子类覆盖静态属性。
self::$count++;
self:: 关键字用于从类本身内部访问类的静态成员。它允许您引用静态属性和方法,而无需创建类的实例。
$this->instanceCount++;
$this 关键字用于引用类的当前实例。它允许您从类内部访问实例属性和方法。在这种情况下,它会为创建的每个新对象递增实例特定的属性 $instanceCount。
λ php static_properties.php Initial count: 0 Static count: 3 Instance 1 count: 1 Instance 2 count: 1 Instance 3 count: 1 Parent Child
构造函数中的属性提升
PHP 8.0 引入了构造函数属性提升,允许直接在构造函数参数中声明属性。这减少了当属性仅用于存储构造函数参数时的样板代码。
<?php
declare(strict_types=1);
class Customer {
public function __construct(
public string $name,
protected string $email,
private string $phone,
public readonly DateTimeImmutable $createdAt = new DateTimeImmutable()
) {
// No need for $this->name = $name; etc.
}
public function getContactInfo(): string {
return "Email: {$this->email}, Phone: {$this->phone}";
}
}
$customer = new Customer('Alice Smith', 'alice@example.com', '555-1234');
echo "Customer: {$customer->name}\n";
echo "Created: {$customer->createdAt->format('Y-m-d')}\n";
echo $customer->getContactInfo() . "\n";
// readonly properties can't be modified
// $customer->createdAt = new DateTimeImmutable(); // Error
属性提升将参数声明与属性声明相结合。该示例显示了具有不同可见性的提升属性和具有默认值的只读属性。只读属性只能设置一次,之后不能修改。
λ php property_promotion.php Customer: Alice Smith Created: 2025-05-18 Email: alice@example.com, Phone: 555-1234
使用 __get 和 __set 的魔术属性
PHP 允许通过魔术方法 __get 和 __set 动态访问属性。当访问不存在或不可访问的属性时,会调用这些方法,从而实现灵活的属性处理。
<?php
declare(strict_types=1);
class DynamicConfig {
private array $data = [];
private array $allowed = ['timeout', 'debug', 'log_level'];
public function __get(string $name): mixed {
if (in_array($name, $this->allowed)) {
return $this->data[$name] ?? null;
}
throw new OutOfBoundsException("Property $name doesn't exist");
}
public function __set(string $name, mixed $value): void {
if (in_array($name, $this->allowed)) {
$this->data[$name] = $value;
} else {
throw new OutOfBoundsException("Cannot set $name");
}
}
public function __isset(string $name): bool {
return isset($this->data[$name]);
}
public function __unset(string $name): void {
unset($this->data[$name]);
}
}
$config = new DynamicConfig();
$config->timeout = 30;
$config->debug = true;
echo "Timeout: {$config->timeout}\n";
echo "Debug: " . ($config->debug ? 'ON' : 'OFF') . "\n";
var_dump(isset($config->timeout)); // true
var_dump(isset($config->log_level)); // false
// This would throw an exception
// $config->invalid = 'value';
魔术方法提供了对属性访问的控制。该示例实现了一个允许的属性白名单。__get 检索值,__set 存储它们,__isset 检查存在性,__unset 删除属性,所有这些都带有验证。
λ php magic_properties.php Timeout: 30 Debug: ON bool(true) bool(false)
只读属性
PHP 8.1 引入了只读属性,这些属性只能初始化一次,然后保持不变。它们对于创建值对象和数据传输对象(DTO)很有用,在这些对象中,属性在构造后不应更改。
<?php
declare(strict_types=1);
class Transaction {
public readonly string $id;
public readonly float $amount;
public readonly DateTimeImmutable $createdAt;
public function __construct(float $amount) {
$this->id = uniqid('txn_');
$this->amount = $amount;
$this->createdAt = new DateTimeImmutable();
}
// Can't have a setter that modifies readonly properties
// public function setAmount(float $amount): void {
// $this->amount = $amount; // Error
// }
}
// PHP 8.2 allows readonly classes
readonly class Point {
public function __construct(
public float $x,
public float $y
) {}
}
$txn = new Transaction(99.99);
echo "Transaction: {$txn->id}, Amount: {$txn->amount}\n";
echo "Created: {$txn->createdAt->format('Y-m-d H:i:s')}\n";
$point = new Point(3.5, 4.2);
echo "Point: ({$point->x}, {$point->y})\n";
// These would cause errors:
// $txn->amount = 100;
// $point->x = 5;
只读属性提供不变性保证。该示例显示了单独的只读属性和一个只读类(PHP 8.2+)。一旦设置,这些属性就无法修改,从而使对象更可预测且线程安全。
λ php readonly_properties.php Transaction: txn_6647f5a3e3a63, Amount: 99.99 Created: 2025-05-18 00:00:00 Point: (3.5, 4.2)
属性初始化和默认值
属性可以在声明时使用默认值进行初始化。PHP 7.4+ 允许类型属性具有与其类型匹配的默认值。
<?php
declare(strict_types=1);
class Settings {
// Basic initialization
public string $theme = 'light';
public int $itemsPerPage = 10;
// Typed properties with defaults
public bool $notificationsEnabled = true;
public ?string $apiKey = null;
// Complex defaults with constants
public const DEFAULT_LOCALE = 'en_US';
public string $locale = self::DEFAULT_LOCALE;
// Uninitialized typed properties
public DateTime $lastUpdated; // Must be initialized before access
// Static property initialization
public static int $cacheLifetime = 3600;
public function __construct() {
$this->lastUpdated = new DateTime();
}
public function updateLastModified(): void {
$this->lastUpdated = new DateTime();
}
}
$settings = new Settings();
echo "Theme: {$settings->theme}\n";
echo "Items per page: {$settings->itemsPerPage}\n";
echo "Last updated: {$settings->lastUpdated->format('Y-m-d')}\n";
// Modify properties
$settings->theme = 'dark';
$settings->itemsPerPage = 25;
$settings->updateLastModified();
echo "Modified theme: {$settings->theme}\n";
echo "Modified last updated: {$settings->lastUpdated->format('H:i:s')}\n";
此示例演示了各种属性初始化技术。没有默认值的类型属性必须在访问之前进行初始化。常量可以提供默认值。静态属性在加载类时初始化一次。
λ php property_initialization.php Theme: light Items per page: 10 Last updated: 2025-05-21 Modified theme: dark Modified last updated: 08:42:32
PHP 属性是 PHP 中面向对象编程的基础。关于属性要记住的要点
- 属性保存对象状态,并使用可见性关键字声明。
- PHP 7.4+ 支持类型属性 以获得更好的类型安全性。
- 静态属性 属于类而不是实例。
- 构造函数属性提升 减少了样板代码。
- 魔术方法 启用动态属性访问模式。
- 只读属性 提供不变性保证。
- 适当的初始化 对于类型属性至关重要。
在本文中,我们介绍了 PHP 属性的基础知识,包括它们的声明、可见性、静态属性、类型属性和构造函数属性提升。我们还讨论了魔术属性、只读属性和属性初始化技术。
作者
列出 所有 PHP 教程。