# Property Hooks, Asymmetric Visibility, Attributes and Magic Methods — PHP

Source: https://www.skillbyai.com/en/php/o-modern

> Use PHP 8.4 property features, attributes and magic methods sensibly.

## The newest object features

**PHP 8.4** added **property hooks**: `get` and `set` logic attached directly to a property, so you can validate or compute values without writing separate getter and setter methods, while callers still use plain property syntax (`$product->price = 499;`). It also added **asymmetric visibility**, such as `public private(set) string $status`, meaning anyone can read the property but only the class can change it, which replaces many getter-only patterns. **Attributes** (PHP 8.0), written `#[Route('/orders', methods: ['GET'])]`, attach structured metadata to classes, methods, properties and parameters; frameworks read them via reflection for routing, validation, ORM mapping and dependency injection, replacing docblock annotations. **Magic methods** such as `__get`, `__set`, `__call`, `__toString`, `__invoke` and `__serialize` customise behaviour, but overusing `__get`/`__call` hides APIs from IDEs and static analysis; prefer explicit methods and the newer typed features. Also note PHP 8.4's ability to chain on `new` without extra parentheses: `new Order()->addItem(...)`.

## Property hooks and asymmetric visibility (PHP 8.4)

Validation in a set hook; status readable everywhere but writable only inside the class.

```php
<?php
declare(strict_types=1);

final class Product
{
    public private(set) string $status = 'draft';      // public read, private write

    public int $pricePaise {
        set (int $value) {
            if ($value < 0) {
                throw new InvalidArgumentException('Price cannot be negative');
            }
            $this->pricePaise = $value;
        }
    }

    public string $displayPrice {
        get => number_format($this->pricePaise / 100, 2) . ' INR';   // computed, no storage
    }

    public function __construct(public readonly string $sku, int $pricePaise)
    {
        $this->pricePaise = $pricePaise;                 // runs the set hook
    }

    public function publish(): void
    {
        $this->status = 'published';
    }
}

$p = new Product('PEN-BLUE', 4950);
echo $p->displayPrice, PHP_EOL;     // 49.50 INR
// $p->status = 'published';        // Error: cannot modify private(set) property
$p->publish();
```

## Check your PHP version before using new syntax

Property hooks and asymmetric visibility require PHP 8.4. Libraries that must support older versions should keep explicit getter and setter methods; applications on 8.4+ can adopt the new syntax gradually.

**Quiz:** What does `public private(set) string $status` mean in PHP 8.4?

- [ ] The property is private for reading and writing
- [ ] The property is constant
- [x] Anyone can read the property, but only the class itself can modify it
- [ ] It is a syntax error

*Answer:* Anyone can read the property, but only the class itself can modify it. Asymmetric visibility separates read access from write access.
