PHP 5 permite programatorilor să definească constructori pentru clase. Clasele care au definit un constructor vor apela această metodă la fiecare obiect nou creat, pentru ca acesta (obiectul) să fie utilizabil pentru inițializare înante de a fi folosit.
Notă: Constructorul-părinte nu este apelat implicit dacă clasa-fiică definește un constructor. Pentru a apela un constructor-părinte, este necesar de a apela parent::__construct() din cadrul constructorului-fiu. Dacă clasa-fiică nu definește un constructor, atunci acesta poate fi moștenit de la clasa-părinte la fel ca o metodă normală a clasei (dacă aceasta nu a fost declarată ca privată).
Example #1 utilizarea noilor constructori unificați
<?php
class BaseClass {
function __construct() {
print "In BaseClass constructor\n";
}
}
class SubClass extends BaseClass {
function __construct() {
parent::__construct();
print "In SubClass constructor\n";
}
}
class OtherSubClass extends BaseClass {
// inherits BaseClass's constructor
}
// In BaseClass constructor
$obj = new BaseClass();
// In BaseClass constructor
// In SubClass constructor
$obj = new SubClass();
// In BaseClass constructor
$obj = new OtherSubClass();
?>
Spre deosebire de alte metode, PHP nu va genera un mesaj de eroare de nivel
E_STRICT
atunci când __construct()
este suprascrisă cu alți parametri decât cei ai metodei
__construct() din clasa-părinte.
Constructorii sunt metode apelate la inițializarea obiectelor. Aceștia pot fi definiți cu un număr arbitrar de argumente, care pot fi opționali sau nu, pot ave tip, și pot avea valoare implicită. Argumentele pentru constructori se pun între paranteze după numele clasei.
Example #2 Constructori în clasele cu spații de nume
<?php
class Point {
protected int $x;
protected int $y;
public function __construct(int $x, int $y = 0) {
$this->x = $x;
$this->y = $y;
}
}
// Apel cu ambii parametrii
$p1 = new Point(4, 5);
// Apel cu argumentul necesar. $y va prelua valoare implictă 0.
$p2 = new Point(4);
// Cu argumente numite (începând cu PHP 8.0):
$p3 = new Point(y: 5, x: 4);
?>
Dacă o clasă nu are constructor, sau constructorul nu are nici un argument necesar, parantezele pot fi omise.
Înainte de PHP 8.0.0, clasele din namespaceul global interpretau o metodă cu același nume
ca și clasa ca un constructor de stil vechi. Acea syntaxă este învechită și nerecomandată,
iar utilizarea ei va genera or eroare de tip E_DEPRECATED
dar metoda constructor va fi apelată.
Dacă atât __construct() cât și o motodă cu acelasi nume cu al clasei sunt
definite, numai __construct() va fi apelat.
În clasele din namespace-uri, sau orice altă clasă începând cu PHP 8.0.0, o metodă cu același nume cu al clasei nu are însemnătate specială.
Folosiți întotdeauna __construct() în cod nou.
Începând cu PHP 8.0.0, parametrii constructorului pot fi promovati să corespundă cu o proprietate a objectului. Este foarte des întâlnit ca parametrii constructorului să fie asignat unei proprietăți în constructor și apoi să nu se mai lucreze cu acea proprietate. Promovarea prin constructor oferă o scurtătură a acestul caz. Exemplul de mai sus poate fi rescris în forma următoare.
Example #3 Folosirea promovării prin constructor
<?php
class Point {
public function __construct(protected int $x, protected int $y = 0) {
}
}
Atunci când argumentele constructorului include modificatori de vizibilitate, PHP îl va interpreta atât ca o proprietate a obiectului cât și drept argument al constructorului, va asigna valoarea argumentului la proprietatea respectivă. Corpul constructorului poate fi gol sau poate contine alte declarații. Declarațiile vor fi executate după ce valorile au fost asignate la proprietățile corespunzătoare.
Nu este necesar să fie promovate toate argumentele. Este posibil să se amestece argumente/proprietăți promovate și nepromovate, în orice ordine. Argumentele promovate nu au nici un impact asupra codului care apelează constructorul.
Notă:
Proprietățile obiectelor nu pot fi de tipul callable pentru că ar introduce ambiguități. Argumentele promovate, de asemenea, nu pot fi de tipul callable. Orice alte declarații de tip sunt permise.
Notă:
Atributele plasate ca argumente la un constructor promovat vor fi replicate și ca proprietăți dar și ca argumente.
PHP suportă un singur constructor într-o clasă. În unele cazuri, însă, este nevoie să permitem crearea unui obiect în diferite feluri cu intrări diferite. Metoda recomandată este folosind metode statice care împacheterază constructorul.
Example #4 Folosirea metodelor de creare statice
<?php
class Product {
private ?int $id;
private ?string $name;
private function __construct(?int $id = null, ?string $name = null) {
$this->id = $id;
$this->name = $name;
}
public static function fromBasicData(int $id, string $name): static {
$new = new static($id, $name);
return $new;
}
public static function fromJson(string $json): static {
$data = json_decode($json);
return new static($data['id'], $data['name']);
}
public static function fromXml(string $xml): static {
// Put your own logic here.
$data = convert_xml_to_array($xml);
$new = new static();
$new->id = $data['id'];
$new->name = $data['name'];
return $new;
}
}
$p1 = Product::fromBasicData(5, 'Widget');
$p2 = Product::fromJson($some_json_string);
$p3 = Product::fromXml($some_xml_string);
Constructorul poate fi făcut private sau protected pentru a preveni apelarea din exterior. Dacă se alege această cale, numai o metodă statică va putea instanția classa. Pentru că sunt definite în aceeași clasă au access la metodele private, chiar dacă obiectele instanțiate sunt diferite. Un constructor private este opțional și poate fi o alegere bună în funcție de cerințe...
Cele trei metode statice publice demonstrează feluri diferite de instanțiere a obiectelor.
fromBasicData()
permite exact parametrii necesari, și apoi crează
obiectul apelând constructorul și returnând rezultatul.fromJson()
acceptă un text în format JSON și îl pre-procesează pentru într-un
format necesar constructorului. Apoi returnează obiectul nou.fromXml()
acceptă un text XML, în pro-procesează, apoi crează un obiect
gol. Constructorul este apelat, dar pentru că toți parapetrii sunt opționali nu sunt
pasați. Apoi asignează valori corecte proprietăților obiectului înainte de a întoarce rezultatul.
În toate cele trei cazuri, cuvântul cheie static
este tradus în numele clasei în care este scris acest cod.
În acest caz, Product
.
PHP 5 introduce un concept de distrugere a unui obiect similar cu cel regăsit în alte limbaje de programare orientate pe obiecte (C++). Metoda de distrugere va fi apelată imediat ce nu mai sunt careva referințe către un anumit obiect sau în orice ordine în timpul secvenței de deconectare.
Example #5 Exemplu destructor
<?php
class MyDestructableClass
{
function __construct() {
print "In constructor\n";
}
function __destruct() {
print "Destroying " . __CLASS__ . "\n";
}
}
$obj = new MyDestructableClass();
La fel ca la constructori, destructorii-părinti nu vor fi apelați implicit. Pentru a apela destructorul-părinte trebuie să apelați explicit parent::__destruct() în destructorul descendent. De asemenea, ca și în cazul constructorilor, o clasă-fiică poate să moștenească destructorul părintelui dacă ea nu-și implementează destructorul propriu.
Destructorul este apelat chiar dacă scriptul este terminat cu apelul la funcția exit(). Apelând exit() într-un destructor va preveni apelarea tuturor rutinelor de terminare din scriptul respectiv.
Notă:
Destructorii apelați la momentul terminării execuției scriptului au antetele HTTP trimise deja. Directorul de lucru în timpul fazei de deconectare a scriptului poate să difere în cazul anumitor SAPI-uri (de ex. Apache).
Notă:
Încercarea de a arunca o excepție dintr-un destructor (apelat la momentul terminării execuției scriptului) va cauza o eroare fatală.