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 教程。