PHP Properties Tutorial
last modified May 18, 2025
In this article we cover PHP properties.
Properties in PHP are variables that belong to a class, encapsulating data and allowing objects to store relevant information. Each property is associated with a specific visibility level, determining how accessible it is within the program. Properties can also be static or non-static, influencing whether they belong to a class or an instance.
Types of PHP Properties:
- Public Properties: Accessible from anywhere in the program.
- Protected Properties: Only accessible within the class and its child classes.
- Private Properties: Restricted to the defining class, ensuring encapsulation.
- Static Properties: Belong to the class itself rather than an instance.
Properties are essential for object-oriented programming in PHP, allowing classes to maintain state and behavior. They can be declared with various visibility levels, and PHP 7.4 introduced typed properties for better type safety. PHP 8.0 added constructor property promotion, reducing boilerplate code when initializing properties in constructors.
Basic property declaration
Properties are declared within a class using one of the visibility keywords: public, protected, or private. Public properties can be accessed from anywhere, protected only within the class and its descendants, and private only within the declaring class.
<?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
This example shows property declaration with different visibility levels. Public properties can be accessed directly, while protected and private properties need methods to access them. The constructor initializes all properties when creating a new object.
λ php basic_properties.php Name: John Doe Email: john@example.com
Property type declarations
PHP 7.4 introduced typed properties, allowing you to specify the type of a property. This helps catch type-related errors early and makes code more maintainable. Supported types include all PHP types and custom classes.
<?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";
Typed properties ensure values match the declared type. The example shows various type declarations including nullable types (with ? prefix). Type checks happen both during assignment and when accessing properties.
λ php typed_properties.php Product: Laptop, Price: 899.99 Created at: 2025-05-18
Static properties
Static properties belong to the class rather than any object instance. They
are shared across all instances of the class and can be accessed without
creating an object. Use the static
keyword to declare them.
<?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'
Static properties maintain their value across all instances. The example
demonstrates how static $count
increments for each new object while
$instanceCount
remains specific to each instance. Late static
binding allows child classes to override static properties.
self::$count++;
The self::
keyword is used to access static members of the class
from within the class itself. It allows you to refer to static properties and
methods without needing to create an instance of the class.
$this->instanceCount++;
The $this
keyword is used to refer to the current instance of
the class. It allows you to access instance properties and methods from
within the class. In this case, it increments the instance-specific
property $instanceCount
for each new object created.
λ php static_properties.php Initial count: 0 Static count: 3 Instance 1 count: 1 Instance 2 count: 1 Instance 3 count: 1 Parent Child
Property promotion in constructors
PHP 8.0 introduced constructor property promotion, allowing properties to be declared directly in the constructor parameters. This reduces boilerplate code when properties are only used to store constructor parameters.
<?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
Property promotion combines parameter declaration with property declaration. The example shows promoted properties with different visibilities and a readonly property with a default value. Readonly properties can only be set once and cannot be modified afterward.
λ php property_promotion.php Customer: Alice Smith Created: 2025-05-18 Email: alice@example.com, Phone: 555-1234
Magic properties with __get and __set
PHP allows dynamic property access through magic methods __get
and
__set
. These methods are called when accessing non-existent or
inaccessible properties, enabling flexible property handling.
<?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';
Magic methods provide control over property access. The example implements a
whitelist of allowed properties. __get
retrieves values,
__set
stores them, __isset
checks existence, and
__unset
removes properties, all with validation.
λ php magic_properties.php Timeout: 30 Debug: ON bool(true) bool(false)
Readonly properties
PHP 8.1 introduced readonly properties that can only be initialized once and then remain immutable. They're useful for creating value objects and DTOs where properties shouldn't change after construction.
<?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;
Readonly properties provide immutability guarantees. The example shows individual readonly properties and a readonly class (PHP 8.2+). Once set, these properties cannot be modified, making objects more predictable and thread-safe.
λ php readonly_properties.php Transaction: txn_6647f5a3e3a63, Amount: 99.99 Created: 2025-05-18 00:00:00 Point: (3.5, 4.2)
Property initialization and default values
Properties can be initialized with default values when declared. PHP 7.4+ allows typed properties to have default values that match their type.
<?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";
This example demonstrates various property initialization techniques. Typed properties without defaults must be initialized before access. Constants can provide default values. Static properties are initialized once when the class is loaded.
λ 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 properties are fundamental to object-oriented programming in PHP. Key points to remember about properties:
- Properties hold object state and are declared with visibility keywords.
- PHP 7.4+ supports typed properties for better type safety.
- Static properties belong to the class rather than instances.
- Constructor property promotion reduces boilerplate code.
- Magic methods enable dynamic property access patterns.
- Readonly properties provide immutability guarantees.
- Proper initialization is crucial for typed properties.
In this article we covered the basics of PHP properties, including their declaration, visibility, static properties, typed properties, and constructor property promotion. We also discussed magic properties, readonly properties, and property initialization techniques.
Author
List all PHP tutorials.