__get / __set / __toString / __call / __invoke în PHP

Clase și obiecte PHP 5+ (__invoke: PHP 5.3+)

Metode cu nume speciale, care încep cu două linii jos, rulate automat de PHP în anumite situații.

Sintaxă
public function __toString(): string { ... }

Ce face __get / __set / __toString / __call / __invoke

Metodele magice nu se apelează direct: PHP le rulează singur. __toString() rulează când obiectul este folosit ca text (de exemplu cu echo). __invoke() rulează când obiectul este apelat ca o funcție: $obiect().

__get($nume) și __set($nume, $valoare) rulează când citești sau scrii o proprietate care nu există sau nu este accesibilă. __isset și __unset acoperă isset() și unset(). __call($nume, $argumente) rulează când apelezi o metodă inexistentă, iar __callStatic face același lucru pentru metode statice.

Alte metode magice: __construct, __destruct (la distrugerea obiectului), __clone, __serialize / __unserialize, __debugInfo (ce afișează var_dump).

Exemple

Exemplul 1: __toString și __invoke

<?php
class Bani
{
    public function __construct(private float $suma)
    {
    }

    public function __toString(): string
    {
        return number_format($this->suma, 2, ",", ".") . " lei";
    }
}

class Tva
{
    public function __invoke(float $pret): float
    {
        return $pret * 1.21;
    }
}

echo new Bani(1299.5) . "\n";

$tva = new Tva();
echo $tva(100) . "\n";
print_r(array_map($tva, [10, 20]));

Rezultat

1.299,50 lei
121
Array
(
    [0] => 12.1
    [1] => 24.2
)

Exemplul 2: __get și __set pentru setări

<?php
class Setari
{
    private array $date = ["tema" => "light"];

    public function __get(string $nume): mixed
    {
        return $this->date[$nume] ?? "(nesetat)";
    }

    public function __set(string $nume, mixed $valoare): void
    {
        echo "Salvez $nume = $valoare\n";
        $this->date[$nume] = $valoare;
    }

    public function __isset(string $nume): bool
    {
        return isset($this->date[$nume]);
    }
}

$s = new Setari();
$s->limba = "ro";
echo $s->tema . ", " . $s->limba . ", " . $s->font . "\n";
var_dump(isset($s->font));

Rezultat

Salvez limba = ro
light, ro, (nesetat)
bool(false)

Exemplul 3: __call pentru metode generate

<?php
class Utilizator
{
    private array $date = ["nume" => "Ana", "oras" => "Iași"];

    public function __call(string $metoda, array $argumente): mixed
    {
        if (str_starts_with($metoda, "get")) {
            $camp = strtolower(substr($metoda, 3));
            return $this->date[$camp] ?? null;
        }
        throw new BadMethodCallException("Metoda $metoda nu există");
    }
}

$u = new Utilizator();
echo $u->getNume() . " din " . $u->getOras() . "\n";

try {
    $u->sterge();
} catch (BadMethodCallException $e) {
    echo $e->getMessage();
}

Rezultat

Ana din Iași
Metoda sterge nu există

Greșeli frecvente

  • Folosești __get și __set pentru tot. Editorul nu mai poate sugera proprietățile, iar greșelile de scriere în nume trec neobservate. Folosește-le doar când chiar ai date dinamice.
  • __toString nu returnează text. Din PHP 8, metoda trebuie să returneze string; altfel primești TypeError.

Comenzi înrudite

  • class / new / $this: Definește o clasă: un șablon pentru obiecte care au date (proprietăți) și funcții proprii (metode).
  • __construct: Constructorul este metoda rulată automat la new. Pregătește obiectul cu datele de pornire.
  • clone: Creează o copie a unui obiect. Fără clone, atribuirea unui obiect copiază doar referința către același obiect.
  • method_exists: Verifică dacă o clasă sau un obiect are o metodă cu un anumit nume.