ce înseamna cuvântul cheie «static» în PHP și la ce se folosește?

Cuvântul cheie static în PHP are trei sensuri diferite. Să le examinăm, în ordine cronologică, așa cum au apărut ele în acest limbaj.
1 – variabila locală statică

function foo() {
  $a = 0;
  echo $a;
  $a = $a + 1;
}

foo(); // 0
foo(); // 0

În PHP variabilele sunt locale. Acest lucru înseamnă că variabila care este definită într-o funcție (metoda) și a primit o valoare, atunci aceasta va exista numai în timpul executării funcției (metodei).La ieșirea din funcție, variabila locală este distrusă, la repornirea funcției, variabila se re-crează. În codul de mai sus, variabila locală $a – există numai în interiorul  funcției foo(), și de fiecare dată când apelați la această funcție, variabila se re-crează. Incrementarea $a + 1 aici nu are nici un sens, intrucât dupa incrementare, funcția se oprește și are loc ieșirea din ea. De câte ori nu am chema functia foo() , vom vedea afișat cifra 0.

Cu toate acestea, totul se schimbă atunci când am pune înaintea variabliei $a – cuvântul cheie “static”:

function foo() {
  static $a = 0;
  echo $a;
  $a = $a + 1;
}

foo(); // 0
foo(); // 1
foo(); // 2

Cuvântul cheie static, scris, înainte de atribuirea unei variabile locale, produce următoarele efecte:
1 – Asignarea se execută o singură dată, în prima funcție de apel
2 – Valoarea variabilei este marcată astfel reținută după terminarea funcției
3 – La apelurile ulterioare ale funcției, în loc de a atribui o noua variabila, primește valoarea stocată anterior
O astfel de utilizare a cuvântului static se numește variabilă locală statică.

Capcanele variabilelor statice:

Prima capcană – variabila statica poate fi atribuită numai constantelor și expresiilor constante. Urmatorul cod, va da eroare:

static $a = bar();

Capcana 2 – Metodele vor exista într-un singur exemplar.

Aici este un pic mai complicat. Pentru a înțelege esența, voi da exemplu urmatorul cod:

class A {
  public function foo() {
    static $x = 0;
    echo ++$x;
  }
}

$a1 = new A;
$a2 = new A;

$a1->foo(); // 1
$a2->foo(); // 2
$a1->foo(); // 3
$a2->foo(); // 4

Contrar așteptărilor intuitive “diferite obiecte – metode diferite,”. Vedem în acest exemplu, că metodele dinamice în PHP “nu se reproduc”. Chiar dacă avem o sută de obiecte de această clasă, metodă, va exista doar într-un singur exemplar, doar de fiecare dată când va fi apelat, în el va fi redirecționat diferite $this-uri.

Acest comportament poate fi neașteptat pentru un programator nepregătit și poate fi o sursă buna de erori. Trebuie remarcat faptul că moștenirea clasei (și metodei) conduce la re-crearea unei metode noi:

class A {
  public function foo() {
    static $x = 0;
    echo ++$x;
  }
}

class B extends A {
}

$a1 = new A;
$b1 = new B;

$a1->foo(); // 1
$b1->foo(); // 1
$a1->foo(); // 2
$b1->foo(); // 2

2 — proprietățile statice și metodele statice ale claselor

În modelul Programării Orientate pe Obiecte (POO) în PHP este posibil să se definească nu doar proprietățile și metodele obiectelor, ci și obiectul însuși (clasa în ansamblu). Pentru aceasta, de asemenea, este nevoie de cuvântul cheie static:

class A {
  public static $x = 'foo';
  public static function test() {
    return 42;
  }
}

echo A::$x; // 'foo'
echo A::test(); // 42

Pentru a avea acces la aceste proprietăți și metode trebuie să folosim de 2 ori punctele duble  ( :: «Paamayim Nekudotayim»), cum ar fi NUME_CLASS::$numeVariabila și NUME_CLASS::numeMetoda()

Dar e și normal că proprietățile statice și metodele statice au propriile lor caracteristice și unele “capcane” pe care trebuie să le știți.

Prima caracteristica, este banală – metodele statice nu conțin $this De fapt, ea provine din însăși definiția metode statice – întrucât se asociază cu clasa, și nu cu obiectul clasei, în interiorul căreea nu este disponibila pseudovariabla $this, în care se conțin metodele dinamice ale obiectului curent. Acest lucru este destul de logic.

Codul urmator

class A {
  public $id = 42;
  static public function foo() {
    echo $this->id;
  }
}

nu va duce la erroare atât timp până când nu va fi chemată metoda foo()

$a = new A;
$a->foo();

(imediat veți obține «Fatal error: Using $this when not in object context»)

A doua caracteristica – static nu este o axioma

class A {
  static public function foo() {
    echo 42;
  }
}

$a = new A;
$a->foo();

Așa e, da. Metoda statică în cazul în care nu conține variabila $this, poate fi chemată dinamic, ca o metodă dinamica a obiectului. Aceasta nu va da eroare în PHP.

Invers nu va fi chiar corect:

class A {
  public function foo() {
    echo 42;
  }
}

A::foo();

Metodele dinamice care nu conțin variabila $this, pot fi chemate în contextul static, dar veți primi un avertisment «Non-static method A::foo() should not be called statically» de tipul E_STRICT

3 — Legarea statică cu întârziere LSB (Late Static Binding)

Developerii limbajului PHP nu s-au oprit doar la două valori ale cuvântului cheie “static” și în versiunea 5.3 a PHP-ului au adăugat înca o proprietate a acestui cuvânt! Se numește LSB (Late Static Binding) “Legarea statica cu întîrziere”.

Pentru a înțelege LSB,  cel mai simplu e sa avem urmatorul cod:

class Model {
  public static $table = 'table';
  public static function getTable() {
    return self::$table;
  }
}

echo Model::getTable(); // 'table'

Cuvintul cheie “self” totdeauna înseamna numele clasei în care se afla acest self, adică în cazul nostr self::$table va fi echivalent cu Model::$table 

Astfel de legatura se mai numește și “Legetura statica timpurie”. De ce timpurie (devreme) ? Pentru ca legatura dintre self si numele clasei are loc nu în runtime ci la inițierea acestuia, în timpul parsingului și compilării codului.

Puțin vom modifica codul nostru:

class Model {
  public static $table = 'table';
  public static function getTable() {
    return self::$table;
  }
}

class User extends Model {
  public static $table = 'users';
}

echo User::getTable(); // 'table'

Acum intelegi de ce PHP în această situație se comportă nu chiar intuitiv. self a fost asociat cu clasa Model  atunci când clasă User încă nu știa nimic despre ea, și, prin urmare, indică la clasa Model.

Cum facem ]n acest caz?

Pentru a rezolva această dilemă a fost inventat mecanismul “întârziat”, care se rulează la etapa de execuție (runtime). Acesta funcționează foarte simplu – doar înlocuiți cuvântul «self» cu «static» și conexiunea va fi stabilită cu clasa care determină codul, și nu cu cea unde era scris:

class Model {
  public static $table = 'table';
  public static function getTable() {
    return static::$table;
  }
}

class User extends Model {
  public static $table = 'users';
}

echo User::getTable(); // 'users'

Asta și este misteriosul Late Static Binding

Sper sa va fie de folos, și …. spor la treaba 🙂

shareShare on Facebook12Share on Google+0Share on LinkedIn0Tweet about this on TwitterEmail this to someone