0% au considerat acest document util (0 voturi)
5 vizualizări182 pagini

Introducere: Definitie

PHP (Hypertext Preprocessor) este un limbaj de scripting open source destinat dezvoltării web, care poate fi integrat în HTML și executat pe server. Scripturile PHP pot funcționa atât pe server, cât și în linia de comandă, având capacitatea de a gestiona formulare HTML și de a interacționa cu variabilele superglobale precum $_POST și $_SERVER. Documentul detaliază sintaxa PHP, tipurile de date, gestionarea erorilor și exemple de utilizare a funcțiilor și structurilor de control.

Încărcat de

razvantaga97
Drepturi de autor
© All Rights Reserved
Respectăm cu strictețe drepturile privind conținutul. Dacă suspectați că acesta este conținutul dumneavoastră, reclamați-l aici.
Formate disponibile
Descărcați ca ODT, PDF, TXT sau citiți online pe Scribd
0% au considerat acest document util (0 voturi)
5 vizualizări182 pagini

Introducere: Definitie

PHP (Hypertext Preprocessor) este un limbaj de scripting open source destinat dezvoltării web, care poate fi integrat în HTML și executat pe server. Scripturile PHP pot funcționa atât pe server, cât și în linia de comandă, având capacitatea de a gestiona formulare HTML și de a interacționa cu variabilele superglobale precum $_POST și $_SERVER. Documentul detaliază sintaxa PHP, tipurile de date, gestionarea erorilor și exemple de utilizare a funcțiilor și structurilor de control.

Încărcat de

razvantaga97
Drepturi de autor
© All Rights Reserved
Respectăm cu strictețe drepturile privind conținutul. Dacă suspectați că acesta este conținutul dumneavoastră, reclamați-l aici.
Formate disponibile
Descărcați ca ODT, PDF, TXT sau citiți online pe Scribd

PHP

1. Introducere
Definitie PHP (Hypertext Preprocessor) = este un limbaj open source de scripting cu scop general
care este deosebit de potrivit pentru dezvoltarea web și poate fi încorporat în HTML.
Codul PHP este inclus în instrucțiuni speciale de început și sfârșit de procesare <?php și ?>
care permit intrarea și ieșirea din „modul PHP”. Codul este executat pe server, generând HTML
care este apoi trimis către client. Clientul primește rezultatele executării acelui script, dar nu știe
care este codul de bază.
Există două domenii principale în care sunt utilizate scripturile PHP:
• Scripturi server-side. Acesta este cel mai utilizat și principalul domeniu țintă pentru PHP.
Trei lucruri sunt necesare pentru a face acest lucru să funcționeze: analizorul PHP (modulul
CGI sau server), un server web și un browser web. Toate acestea pot rula pe o mașină locală
pentru a experimenta doar cu programarea PHP.
• Scripturi în linia de comandă. Un script PHP poate fi rulat fără niciun server sau browser,
fiind necesar doar analizorul PHP pentru a-l utiliza în acest mod. Acest tip de utilizare este
ideal pentru scripturile executate în mod regulat folosind cron (pe Unix sau macOS) sau
Task Scheduler (pe Windows). Aceste scripturi pot fi utilizate și pentru sarcini simple de
prelucrare a textului.

Exemplu <?php echo "Hello World!"; ?>


Accesand serverul localhost vom regasi output-ul “Hello World!”.

Exemplu <?php phpinfo(); ?>


Aceasta functie ofera informatii despre sistem si setarile de configuratie.

Exemplu <?php echo $_SERVER['HTTP_USER_AGENT']; ?>


$_SERVER este o variabilă PHP special rezervată care conține toate informațiile despre
serverul web. Este totodata si o variabila globala. Acesta cod va returna output-ul “Mozilla/5.0
(Linux) Firefox/112.0”.

Exemplu <?php if (str_contains($_SERVER['HTTP_USER_AGENT'],'Firefox')) {


echo 'You are using Firefox.';
} ?>
Aici vă prezentăm câteva concepte noi. Primul este o declarație if, care este la fel cu sintaxa
logica if din limbajul C. Al doilea concep este functia str_contains care determina daca un sir dat
conține un alt sir și returneaza true în caz de succes.

Important Una dintre cele mai puternice caracteristici ale PHP este modul în care gestionează
formularele HTML. Conceptul de bază care este important de înțeles este că orice element de
formular va fi automat disponibil pentru scripturile PHP.

Exemplu
<form action="[Link]" method="post">
<label for="name">Your name:</label>
<input name="name" id="name" type="text">

<label for="age">Your age:</label>


<input name="age" id="age" type="number">
<button type="submit">Submit</button>
</form>
In PHP vom afisa datele acestui form in felul urmator:
Hi <?php echo htmlspecialchars($_POST['name']); ?>.
You are <?php echo (int) $_POST['age']; ?> years old.
Iar output-ul acestui cod va fi: Hi Joe. You are 22 years old.

Important În afară de părțile htmlspecialchars() și (int), ar trebui să fie evident ce face acest lucru.
htmlspecialchars() se asigură că orice caractere speciale în html sunt codificate corect, astfel încât
oamenii să nu poată injecta etichete HTML sau Javascript în pagina ta. Pentru câmpul de vârstă,
deoarece știm că este un număr, îl putem converti într-un int care va scăpa automat de orice
caractere rătăcite. Variabilele $_POST['nume'] și $_POST['vârstă'] sunt setate automat pentru dvs.
de PHP. Mai devreme am folosit $_SERVER superglobal; mai sus tocmai am introdus superglobalul
$_POST care conține toate datele POST. Observați cum metoda formularului nostru este POST.
Dacă am folosi metoda GET, atunci informațiile noastre din formular ar locui în locul superglobal
$_GET. De asemenea, puteți utiliza superglobalul $_REQUEST, dacă nu vă pasă de sursa datelor
solicitate. Conține informațiile îmbinate ale datelor GET, POST și COOKIE.

2. PHP tags (etichetele)


Important Când PHP analizează un fișier, caută etichete de deschidere și de închidere, care sunt <?
php și ?> care îi spun PHP să înceapă și să oprească interpretarea codului dintre ele. PHP include o
etichetă scurtă de echo <?= care este o scurtă mână la echoul <?php mai verbos.

Exemplu
<?php echo 'if you want to serve PHP code in XHTML or XML documents, use these tags'; ?>
You can use the short echo tag to <?= 'print this string' ?>. It's equivalent to <?php echo 'print
this string' ?>.

Important Etichetele scurte (exemplul trei) sunt disponibile implicit, dar pot fi dezactivate fie prin
directiva fișierului de configurare short_open_tag [Link], fie sunt dezactivate implicit dacă PHP
este construit cu configurația –disable-short-tags.
Important Dacă un fișier conține doar cod PHP, este de preferat să omiteți eticheta de închidere
PHP la sfârșitul fișierului. Acest lucru previne adăugarea accidentală de spații albe sau de noi linii
după eticheta de închidere PHP, ceea ce poate provoca efecte nedorite, deoarece PHP va începe
bufferingul de ieșire atunci când programatorul nu intenționează să trimită vreo ieșire în acel
moment al scriptului.

Exemplu
<?php
echo "Hello world";

// ... more code

echo "Last statement";

// the script ends here with no PHP closing tag


3. Evadarea din HTML
Important Tot ceea ce este în afara unei perechi de etichete de deschidere și de închidere este
ignorat de parserul PHP, care permite fișierelor PHP să aibă conținut mixt. Acest lucru permite ca
PHP să fie încorporat în documente HTML, de exemplu pentru a crea șabloane.

Exemplu
<?php if ($expression == true): ?>
This will show if the expression is true.
<?php else: ?>
Otherwise this will show.
<?php endif; ?>

Important În acest exemplu, PHP va sări peste blocurile în care condiția nu este îndeplinită, chiar
dacă acestea sunt în afara etichetelor PHP open/close; PHP le omite în funcție de condiție, deoarece
interpretul PHP va sări peste blocurile conținute într-o condiție care nu este îndeplinită.

4. Separarea instructiunilor
Important PHP necesită ca instrucțiunile să fie terminate cu un punct și virgulă la sfârșitul fiecărei
instrucțiuni.

Exemplu
<?php echo "Some text"; ?>
No newline
<?= "But newline now" ?>

Acest exemplu va returna: „Some textNo newline” si ”But newline now”.

5. Comentarii
Important Comentariile în php se pot adauga folosit caracterele „//”, „/**/” și „#”. Caracterul „/**/”
aplica comentarii pe mai multe linii de cod, în schimb cele doua doar pe câte o linie.

Exemplu
<?php
echo 'This is a test'; // This is a one-line c++ style comment
/* This is a multi line comment
yet another line of comment */
echo 'This is yet another test';
echo 'One Final Test'; # This is a one-line shell-style comment
?>

6. Tipurile de date
Important Fiecare expresie din PHP are urmatoarele tipuri de date: null, bool, int, float, string,
array, object, callable, resource.

Important Pentru a verifica valoarea și tipul unei expresii, utilizați funcția var_dump(). Pentru a
prelua tipul unei expresii, utilizați funcția get_debug_type(). Cu toate acestea, pentru a verifica dacă
o expresie este de un anumit tip, utilizați în schimb funcțiile is_type.
Important O valoare este considerata scalara daca este de tipul int, float, string sau bool; iar prin
intermediul interfaces, classes sau a enumerations putem defini tipuri customizabile de date. De
exemplu putem defini o clasa Elephant, apoi pot fi instantiate obiecte de tip Elephant, iar o funcție
poate solicita un parametru de tip Elephant.

7. Tipul de date NULL


Important Tipul de date NULL are o singura valoare, null. Variabilele nedefinite sau cele cu unset()
au valoarea null.
Exemplu
<?php
$var = NULL;
$a = array();
$a == null <== return true
$a === null < == return false
is_null($a) <== return false
?>
Important NULL ar trebui să indice absența unei valori, mai degrabă decât să fie considerat ca o
valoare în sine. Acesta este motivul pentru care o variabilă care conține un NULL este considerată a
fi nesetată: nu are o valoare. Setarea unei variabile la NULL înseamnă să-i uite valoarea fără a oferi
o valoare de înlocuire de reținut.

8. Tipul de date BOOL


Important Tipul bool are doar două valori și este folosit pentru a exprima o valoare de adevăr. Poate
fi fie adevărat, fie fals. Pentru a specifica un literal bool, utilizați constantele true sau false. Ambele
sunt insensibile la majuscule. Pentru a converti explicit o valoare în bool, utilizați cast-ul (bool). La
conversia în bool, următoarele valori sunt considerate false: falsul boolean în sine, int 0, float 0.0,
empty string,null, obiecte interne care își supraincarca comportamentul de difuzare la bool (ex.
SimpleXML).

9. Tipul de date INT


Important Un int este un număr al mulțimii ℤ = {..., -2, -1, 0, 1, 2, ...}. Int poate fi specificat în
notație zecimală (bază 10), hexazecimală (bază 16), octală (bază 8) sau binară (bază 2). Operatorul
de negație poate fi folosit pentru a desemna un int negativ.

10. Tipul de date FLOAT


Important Numerele în virgulă mobilă (cunoscute și sub numele de „float”, „duble” sau „numere
reale”) pot fi specificate utilizând oricare dintre următoarele sintaxe:

<?php
$a = 1.234;
$b = 1.2e3;
$c = 7E-10;
$d = 1_234.567; // as of PHP 7.4.0
?>
Important Daca un tip de date este numeric se poate converti la float, iar daca nu este numeric mai
întâi se converteste la int și apoi se converteste la float. Pentru a compara doua valori de tip float a
și b se utilizeaza o limita superioara a erorii relative datorate rotunjirii, valoare cunoscuta sub
denumirea de epsilon. Ex:
<?php
$a = 1.23456789;
$b = 1.23456780;
$epsilon = 0.00001;

if(abs($a-$b) < $epsilon) {


echo "true";
}
?>

Important Unele operații numerice pot avea ca rezultat o valoare reprezentată de constanta NaN.
Acest rezultat reprezintă o valoare nedefinită sau nereprezentabilă în calculele cu virgulă mobilă.
De regula se mai verifica prin utilizarea functiei is_nan().

11. Tipul de date STRING


Important Un șir este o serie de caractere, unde un caracter este același cu un octet. Aceasta
înseamnă că PHP acceptă doar un set de 256 de caractere și, prin urmare, nu oferă suport nativ
Unicode. Un literal poate fi reprezentat prin urmatoarele moduri: citat simplu, ghilimele duble,
sintaxa heredoc, sintaxa nowdoc. Cel mai simplu mod de a specifica un șir este să-l încadrezi între
ghilimele simple (caracterul ').

<?php
echo 'this is a simple string';
echo 'You can also have embedded newlines in
strings this way as it is
okay to do';

// Outputs: Arnold once said: "I'll be back"


echo 'Arnold once said: "I\'ll be back"';

// Outputs: You deleted C:\*.*?


echo 'You deleted C:\\*.*?';

// Outputs: You deleted C:\*.*?


echo 'You deleted C:\*.*?';

// Outputs: This will not expand: \n a newline


echo 'This will not expand: \n a newline';

// Outputs: Variables do not $expand $either


echo 'Variables do not $expand $either';
?>

Important Dacă șirul este cuprins între ghilimele ("), PHP va interpreta următoarele secvențe de
escape pentru caractere speciale:
\n linefeed (LF or 0x0A (10) in ASCII)
\r carriage return (CR or 0x0D (13) in ASCII)
\t horizontal tab (HT or 0x09 (9) in ASCII)
\v vertical tab (VT or 0x0B (11) in ASCII)
\e escape (ESC or 0x1B (27) in ASCII)
\f form feed (FF or 0x0C (12) in ASCII)
\\ backslash
\$ dollar sign
\" double-quote
Octal: the sequence of characters matching the regular expression [0-7]{1,3}
\[0-7]{1,3} is a character in octal notation (e.g. "\101" === "A"), which silently
overflows to fit in a byte (e.g. "\400" === "\000")
Hexadecimal: the sequence of characters matching the regular expression [0-
\x[0-9A-Fa-
9A-Fa-f]{1,2} is a character in hexadecimal notation (e.g. "\x41" ===
f]{1,2}
"A")
Unicode: the sequence of characters matching the regular expression [0-9A-
\u{[0-9A- Fa-f]+ is a Unicode codepoint, which will be output to the string as that
Fa-f]+} codepoint's UTF-8 representation. The braces are required in the sequence. E.g.
"\u{41}" === "A"

Important Un al treilea mod de a delimita șirurile de caractere este sintaxa heredoc: <<<. După
acest operator, este furnizat un identificator, apoi o nouă linie. Urmează șirul în sine și apoi din nou
același identificator pentru a închide ghilimele.

<?php Acest code va afisa:


// no indentation a
echo <<<END b
a c
b
c
\n
END;
<?php
{ Acest cod nu v-a funcționa și va returna
echo <<<END o eroare de tipul: invalid body indentation
a
END;
}
<?php
$values = [<<<END Output:
a array(2) {
b [0] => string(11) „a
b
c”
c [1] => string(5) „d e f”
END, 'd e f']; }
var_dump($values);

12. Tipul de date NUMERIC STRING


Important Un șir PHP este considerat numeric dacă poate fi interpretat ca un int sau un float.

<?php
$foo = 1 + "10.5"; // $foo is float (11.5)
$foo = 1 + "-1.3e3"; // $foo is float (-1299)
$foo = 1 + "bob-1.3e3"; // TypeError as of PHP 8.0.0, $foo is integer (1) previously
$foo = 1 + "bob3"; // TypeError as of PHP 8.0.0, $foo is integer (1) previously
$foo = 1 + "10 Small Pigs"; // $foo is integer (11) and an E_WARNING is raised in PHP 8.0.0,
E_NOTICE previously
$foo = 4 + "10.2 Little Piggies"; // $foo is float (14.2) and an E_WARNING is raised in PHP 8.0.0,
E_NOTICE previously
$foo = "10.0 pigs " + 1; // $foo is float (11) and an E_WARNING is raised in PHP 8.0.0,
E_NOTICE previously
$foo = "10.0 pigs " + 1.0; // $foo is float (11) and an E_WARNING is raised in PHP 8.0.0,
E_NOTICE previously
?>

Important Atunci când un șir trebuie evaluat ca număr (de exemplu, operații aritmetice, declarație
de tip int etc.), se parcurg următorii pași pentru a determina rezultatul:
• Dacă șirul este numeric, se rezolvă la un int dacă șirul este un șir numeric întreg și se
încadrează în limitele limitelor de tip int (așa cum sunt definite de PHP_INT_MAX), în caz
contrar, se rezolvă la un șir flotant.
• Dacă contextul permite șiruri numerice de început și șirul este unul, rezolvați la un int dacă
partea de început a șirului este un șir numeric întreg și se încadrează în limitele limitelor de
tip int (așa cum sunt definite de PHP_INT_MAX), în caz contrar rezolvați la un plutire. În
plus, este ridicată o eroare de nivel E_WARNING
• Șirul nu este numeric, aruncați un TypeError.

13. Array
Important O matrice (array) în PHP este de fapt o hartă ordonată. O hartă este un tip care asociază
valori cu chei. Acest tip este optimizat pentru mai multe utilizări diferite; poate fi tratat ca o matrice,
listă (vector), tabel hash (o implementare a unei hărți), dicționar, colecție, stivă, coadă și, probabil,
multe altele. Deoarece valorile matricei pot fi alte matrice, sunt posibile și arbori și matrice
multidimensionale.
array(
key => value,
key2 => value2,
key3 => value3,
...)
Important Virgula după ultimul element de matrice este opțională și poate fi omisă.
<?php
$array = array(
"foo" => "bar",
"bar" => "foo",
);

// Using the short array syntax


$array = [
"foo" => "bar",
"bar" => "foo",
];
?>
Important Cheia poate fi fie un int, fie un șir. Valoarea poate fi de orice tip. În plus, vor avea loc
următoarele turnări cheie:
• Șirurile care conțin interiuri zecimale valide, cu excepția cazului în care numărul este
precedat de un semn +, vor fi turnate la tipul int. de ex. cheia „8” va fi de fapt stocată sub 8.
Pe de altă parte, „08” nu va fi turnat, deoarece nu este un întreg zecimal valid.
• Flotatoarele sunt, de asemenea, turnate în int, ceea ce înseamnă că partea fracționată va fi
trunchiată. de ex. cheia 8.7 va fi de fapt stocată sub 8.
• Boolurile sunt de asemenea transformate în inți, adică cheia adevărată va fi de fapt stocată
sub 1 și cheia falsă sub 0. Null va fi turnat în șirul gol, adică cheia null va fi de fapt stocată
sub „”.
• Matricele și obiectele nu pot fi folosite ca chei. Acest lucru va avea ca rezultat un
avertisment: tip offset ilegal.

14. Obiecte
Important Pentru a crea un obiect nou, utilizați instrucțiunea nouă pentru a instanția o clasă:
<?php
class foo {
function do_foo() {
echo "Doing foo.";
}
}

$bar = new foo;


$bar->do_foo();
?>
Important Dacă un obiect este convertit într-un obiect, acesta nu este modificat. Dacă o valoare de
orice alt tip este convertită într-un obiect, este creată o nouă instanță a clasei încorporate stdClass.
Dacă valoarea a fost nulă, noua instanță va fi goală. O matrice se convertește într-un obiect cu
proprietăți numite prin chei și valori corespunzătoare.

15. Enumeratii
Important Enumerările sunt un strat restrictiv deasupra claselor și constantelor de clasă, menite să
ofere o modalitate de a defini un set închis de valori posibile pentru un tip.
<?php
enum Suit
{
case Hearts;
case Diamonds;
case Clubs;
case Spades;
}

function do_stuff(Suit $s)


{
// ...
}do_stuff(Suit::Spades);
?>

16. Resurse
Important O resursă este o variabilă specială, care conține o referință la o resursă externă. Resursele
sunt create și utilizate de funcții speciale. Consultați anexa pentru o listă a tuturor acestor funcții și a
tipurilor de resurse corespunzătoare.

17. Reapeluri (callbacsk/callables)


Important Reapelurile pot fi notate prin declarația de tip apelabil. Unele funcții precum
call_user_func() sau usort() acceptă funcții de apel invers definite de utilizator ca parametru.
Funcțiile de apel invers nu pot fi doar funcții simple, ci și metode obiect, inclusiv metode de clasă
statică. O funcție PHP este trecută de numele ei ca șir. Poate fi utilizată orice funcție încorporată sau
definită de utilizator, cu excepția constructelor de limbaj precum: array(), echo, empty(), eval(),
exit(), isset(), list(), print sau unset() . O metodă a unui obiect instanțiat este transmisă ca o matrice
care conține un obiect la indexul 0 și numele metodei la indexul 1. Accesarea metodelor protejate și
private din cadrul unei clase este permisă. Metodele de clasă statică pot fi, de asemenea, transmise
fără instanțierea unui obiect din acea clasă, fie trecând numele clasei în loc de un obiect la indexul
0, fie trecând „ClassName::methodName”.

<?php

// An example callback function


function my_callback_function() {
echo 'hello world!';
}

// An example callback method


class MyClass {
static function myCallbackMethod() {
echo 'Hello World!';
}
}

// Type 1: Simple callback


call_user_func('my_callback_function');

// Type 2: Static class method call


call_user_func(array('MyClass', 'myCallbackMethod'));

// Type 3: Object method call


$obj = new MyClass();
call_user_func(array($obj, 'myCallbackMethod'));

// Type 4: Static class method call


call_user_func('MyClass::myCallbackMethod');

18. Mixt
Important Tipul mixt acceptă fiecare valoare. Este echivalent cu tipul de unire obiect|resursa|
matrice|string|float|int|bool|null. Disponibil începând cu PHP 8.0.0. Mixt este, în limbajul teoriei
tipurilor, tipul de vârf. Înseamnă că orice alt tip este un subtip al acestuia.

19. Void
Important void este o declarație de tip de returnare care indică faptul că funcția nu returnează o
valoare, dar funcția se poate termina. Prin urmare, nu poate face parte dintr-o declarație de tip
uniune. Disponibil începând cu PHP 7.1.0.

20. Never
Important Never nu este un tip de returnare care indică faptul că funcția nu se termină. Aceasta
înseamnă că fie apelează exit(), aruncă o excepție, fie este o buclă infinită. Prin urmare, nu poate
face parte dintr-o declarație de tip uniune. Never nu este, în limbajul teoriei tipurilor, tipul de jos.
Înseamnă că este subtipul oricărui alt tip și poate înlocui orice alt tip de returnare în timpul
moștenirii.

21. Tipuri de clase relative


Important self = Valoarea trebuie să fie o instanță din aceeași clasă cu cea în care este utilizată
declarația de tip.
Parent = Valoarea trebuie să fie o instanță a unui părinte al clasei în care este utilizată
declarația de tip.
Static = static este un tip de returnare care necesită ca valoarea returnată să fie o instanță din
aceeași clasă cu cea în care este apelată metoda.

22. Iterable
Important Iterable este un alias de tip timp de compilare încorporat pentru array|Traversable. Un tip
iterabil poate fi utilizat pentru fiecare și cu randament din interiorul unui generator.
<?php function gen(): iterable { yield 1; yield 2; yield 3; } ?>

23. Variabile
Important Variabilele în PHP sunt reprezentate de un semn dolar urmat de numele variabilei.
Numele variabilei face distincție între majuscule și minuscule. Un nume de variabilă valid începe
cu o literă (A-Z, a-z sau octeții de la 128 la 255) sau liniuță de subliniere, urmată de orice număr de
litere, cifre sau liniuțe de subliniere. Ca expresie regulată, ar fi exprimată astfel: ^[a-zA-Z_\x80-\
xff][a-zA-Z0-9_\x80-\xff]*$
<?php
$var = 'Bob';
$Var = 'Joe';
echo "$var, $Var"; // outputs "Bob, Joe"

$4site = 'not yet'; // invalid; starts with a number


$_4site = 'not yet'; // valid; starts with an underscore
$täyte = 'mansikka'; // valid; 'ä' is (Extended) ASCII 228.
?>

<?php
$foo = 'Bob'; // Assign the value 'Bob' to $foo
$bar = &$foo; // Reference $foo via $bar.
$bar = "My name is $bar"; // Alter $bar...
echo $bar;
echo $foo; // $foo is altered too.
?>

<?php
$foo = 25;
$bar = &$foo; // This is a valid assignment.
$bar = &(24 * 7); // Invalid; references an unnamed expression.

function test()
{
return 25;
}

$bar = &test(); // Invalid because test() doesn't return a variable by reference.


?>

Important Sfera de aplicare a unei variabile este contextul în care este definită. Orice variabilă
definită în afara unei funcții este limitată la domeniul global. Când un fișier este inclus, codul pe
care îl conține moștenește domeniul variabil al liniei pe care are loc includerea.

<?php
$a = 1;
include '[Link]'; // Variable $a will be available within [Link]
?>

<?php
$a = 1; // global scope

function test()
{
echo $a; // Variable $a is undefined as it refers to a local version of $a}
?>
Important Exemplul de mai sus va genera o variabilă nedefinită E_WARNING (sau un E_NOTICE
înainte de PHP 8.0.0). Acest lucru se datorează faptului că instrucțiunea echo se referă la o versiune
locală a variabilei $a și nu i s-a atribuit o valoare în acest domeniu.
Important Cuvântul cheie global este folosit pentru a lega o variabilă dintr-un domeniu global într-
un domeniu local. Cuvântul cheie poate fi folosit cu o listă de variabile sau cu o singură variabilă.
Va fi creată o variabilă locală care face referire la variabila globală cu același nume. Dacă variabila
globală nu există, variabila va fi creată în domeniul global și va fi atribuită nul.
<?php
$a = 1;
$b = 2;

function Sum()
{
global $a, $b;

$b = $a + $b;
}

Sum();
echo $b;
?>

<?php
$a = 1;
$b = 2;

function Sum()
{
$GLOBALS['b'] = $GLOBALS['a'] + $GLOBALS['b'];
}

Sum();
echo $b;
?>

Important Tabloul $GLOBALS este un tablou asociativ cu numele variabilei globale fiind cheia și
conținutul acelei variabile fiind valoarea elementului de matrice.
Important O altă caracteristică importantă a domeniului variabilei este variabila statică. O variabilă
statică există doar într-un domeniu de aplicare local, dar nu își pierde valoarea atunci când execuția
programului părăsește acest domeniu.
<?php
function test()
{
$a = 0; // or static $a = 0;
echo $a;
$a++;
}
?>

Important Uneori este convenabil să poți avea nume de variabile variabile. Adică, un nume de
variabilă care poate fi setat și utilizat dinamic. O variabilă normală este setată cu o instrucțiune
precum:
<?php
$a = 'hello';
?>
Important O variabilă variabilă ia valoarea unei variabile și o tratează ca pe numele unei variabile.
În exemplul de mai sus, salut, poate fi folosit ca nume al unei variabile folosind două semne de
dolar. adică
<?php
$$a = 'world';
?>

Important În acest moment au fost definite și stocate două variabile în arborele simbol PHP: $a cu
conținutul „hello” și $hello cu conținutul „world”. Prin urmare, această afirmație:
<?php
echo "$a {$$a}"; // este echivalent cu echo "$a $hello";
?>

Important va return output „hello wordl”

Important Când un formular este trimis la un script PHP, informațiile din formularul respectiv sunt
puse automat la dispoziția scriptului. Există câteva modalități de a accesa aceste informații, de
exemplu:

<form action="[Link]" method="post">


Name: <input type="text" name="username" /><br />
Email: <input type="text" name="email" /><br />
<input type="submit" name="submit" value="Submit me!" />
</form>

<?php
echo $_POST['username'];
echo $_REQUEST['username'];
?>

Important Utilizarea unui formular GET este similară, cu excepția faptului că variabila predefinită
GET corespunzătoare poate fi utilizată în schimb. GET se aplică și pentru QUERY_STRING
(informațiile de după „?” dintr-o adresă URL).
Important Când trimiteți un formular, este posibil să utilizați o imagine în locul butonului standard
de trimitere cu o etichetă precum: <input type="image" src="[Link]" name="sub" /> Când
utilizatorul face clic undeva pe imagine, formularul însoțitor va fi transmis serverului cu două
variabile suplimentare, sub_x și sub_y. Acestea conțin coordonatele clicului utilizatorului în
imagine.
Important PHP acceptă în mod transparent cookie-urile HTTP așa cum sunt definite de » RFC
6265. Cookie-urile sunt un mecanism de stocare a datelor în browserul de la distanță și, astfel, de
urmărire sau de identificare a utilizatorilor reveniți. Este posibil să setați cookie-uri folosind funcția
setcookie(). Cookie-urile fac parte din antetul HTTP, astfel încât funcția SetCookie trebuie apelată
înainte ca orice rezultat să fie trimis către browser. Aceasta este aceeași restricție ca și pentru funcția
header(). Datele cookie sunt apoi disponibile în matricele de date cookie corespunzătoare, cum ar fi
$_COOKIE, precum și în $_REQUEST.
<?php
setcookie("MyCookie[foo]", 'Testing 1', time()+3600);
setcookie("MyCookie[bar]", 'Testing 2', time()+3600);
?>
Important Acest lucru va crea două cookie-uri separate, deși MyCookie va fi acum o singură
matrice în script. Dacă un singur cookie ar trebui setat cu mai multe valori, luați în considerare mai
întâi utilizarea serialize() sau explode() pe valoare.
Important Deoarece PHP determină tipurile de variabile și le convertește (în general) după cum
este necesar, nu este întotdeauna evident ce tip este o anumită variabilă la un moment dat. PHP
include mai multe funcții care află ce tip este o variabilă, cum ar fi: gettype(), is_array(), is_float(),
is_int(), is_object() și is_string().

<?php
if (isset($_COOKIE['count'])) {
$count = $_COOKIE['count'] + 1;
} else {
$count = 1;
}
setcookie('count', $count, time()+3600);
setcookie("Cart[$count]", $item, time()+3600);
?>

24. Constante
Important O constantă este un identificator (nume) pentru o valoare simplă. După cum sugerează și
numele, această valoare nu se poate schimba în timpul executării scriptului (cu excepția
constantelor magice, care nu sunt de fapt constante). Constantele sunt sensibile la majuscule. Prin
convenție, identificatorii constantelor sunt întotdeauna majuscule.
Important Numele unei constante urmează aceleași reguli ca orice etichetă în PHP. Un nume de
constantă valid începe cu o literă sau un semn de subliniere, urmat de orice număr de litere, cifre
sau semne de subliniere. Ca expresie regulată, ar fi exprimată astfel: ^[a-zA-Z_\x80-\xff][a-zA-Z0-
9_\x80-\xff]*$.
Important Constantele pot fi definite cu ajutorul cuvântului-cheie const sau prin utilizarea funcției
define(). În timp ce define() permite definirea unei constante într-o expresie arbitrară, cuvântul-
cheie const are restricții, așa cum se subliniază în paragraful următor. Odată ce o constantă este
definită, aceasta nu poate fi niciodată modificată sau nedefinită.

<?php
// Valid constant names
define("FOO", "something");
define("FOO2", "something else");
define("FOO_BAR", "something more");

// Invalid constant names


define("2FOO", "something");

// This is valid, but should be avoided:


// PHP may one day provide a magical constant
// that will break your script
define("__FOO__", "something");
?>

Important Acestea sunt diferențele dintre constante și variabile:


• Constantele nu au semnul dolarului ($) înaintea lor;
• Constantele pot fi definite și accesate oriunde, fără a se ține cont de regulile de delimitare a
variabilelor;
• Constantele nu pot fi redefinite sau nedefinite odată ce au fost stabilite;
• Constantele pot fi evaluate numai la valori scalare sau matrici.
<?php
define("CONSTANT", "Hello world.");
echo CONSTANT; // outputs "Hello world."
echo Constant; // Emits an Error: Undefined constant "Constant"
// Prior to PHP 8.0.0, outputs "Constant" and issues a warning.
?>

Important PHP oferă un număr mare de constante predefinite pentru orice script pe care îl rulează.
Cu toate acestea, multe dintre aceste constante sunt create de diverse extensii și vor fi prezente
numai atunci când aceste extensii sunt disponibile, fie prin încărcare dinamică, fie pentru că au fost
compilate.

Important Există câteva constante magice care se schimbă în funcție de locul în care sunt utilizate.
De exemplu, valoarea __LINE__ depinde de linia pe care este utilizată într-un script. Toate aceste
constante „magice” sunt rezolvate la momentul compilării, spre deosebire de constantele obișnuite,
care sunt rezolvate la momentul rulării. Aceste constante speciale sunt insensibile la majuscule și
sunt după cum urmează:

Name Description
__LINE__ Numărul liniei curente din fișier.
Calea completă și numele fișierului, cu rezolvarea legăturilor simbolice.
__FILE__ Dacă este utilizat în interiorul unei incluziuni, este returnat numele fișierului
inclus.
Directorul fișierului. Dacă este utilizat în interiorul unei incluziuni, este
__DIR__ returnat directorul fișierului inclus. Acest lucru este echivalent cu
dirname(__FILE__). Acest nume de director nu are o bară oblică finală, cu
excepția cazului în care este directorul rădăcină.
__FUNCTION__ Numele funcției, sau {closure} pentru funcții anonime.
Numele clasei. Numele clasei include spațiul de nume în care a fost
__CLASS__ declarată (de exemplu, Foo\Bar). Atunci când este utilizat în interiorul unei
metode de trăsătură, __CLASS__ este numele clasei în care este utilizată
trăsătura.

__TRAIT__ Numele trăsăturii. Numele trăsăturii include spațiul de nume în care a fost
declarată (de exemplu, Foo\Bar).
__METHOD__ Numele metodei clasei.
__PROPERTY__ Valabil numai în interiorul unui cârlig de proprietate. Este egal cu numele
proprietății.
__NAMESPACE__ Numele spațiului de nume curent.
ClassName::cla
ss Numele complet calificat al clasei.

25. Expresii
Important Expresiile sunt cele mai importante elemente de bază ale PHP. În PHP, aproape orice
scrieți este o expresie. Cel mai simplu, dar și cel mai precis mod de a defini o expresie este „orice
lucru care are o valoare”.
Important Cele mai de bază forme de expresii sunt constantele și variabilele. Când scrieți $a = 5,
atribuiți 5 în $a. 5, evident, are valoarea 5 sau, cu alte cuvinte, 5 este o expresie cu valoarea 5 (în
acest caz, 5 este o constantă întreagă).

<?php
function foo ()
{
return 5;
}
?>

Important Presupunând că sunteți familiarizat cu conceptul de funcții (dacă nu sunteți, aruncați o


privire la capitolul despre funcții), ați presupune că scrierea $c = foo() este în esență la fel ca
scrierea $c = 5, și aveți dreptate. Funcțiile sunt expresii cu valoarea de retur. Deoarece foo()
returnează 5, valoarea expresiei „foo()” este 5. De obicei, funcțiile nu returnează doar o valoare
statică, ci calculează ceva.

Important Desigur, valorile în PHP nu trebuie să fie neapărat numere întregi și foarte des nu sunt.
PHP acceptă patru tipuri de valori scalare: valori int, valori în virgulă mobilă (float), valori string și
valori bool (valorile scalare sunt valori pe care nu le puteți „rupe” în bucăți mai mici, spre deosebire
de array-uri, de exemplu). PHP acceptă, de asemenea, două tipuri compuse (nescalare): array-uri și
obiecte. Fiecare dintre aceste tipuri de valori poate fi atribuită în variabile sau returnată din funcții.

Important Mai există o expresie care poate părea ciudată dacă nu ați văzut-o în alte limbi,
operatorul condițional ternar:
<?php $first ? $second : $third ?>
Important Dacă valoarea primei subexpresii este adevărată (diferită de zero), atunci a doua
subexpresie este evaluată și acesta este rezultatul expresiei condiționale. În caz contrar, a treia
subexpresie este evaluată, iar aceasta este valoarea.

<?php
function double($i)
{
return $i*2;
}
$b = $a = 5; /* assign the value five into the variable $a and $b */
$c = $a++; /* post-increment, assign original value of $a
(5) to $c */
$e = $d = ++$b; /* pre-increment, assign the incremented value of
$b (6) to $d and $e */

/* at this point, both $d and $e are equal to 6 */

$f = double($d++); /* assign twice the value of $d before


the increment, 2*6 = 12 to $f */
$g = double(++$e); /* assign twice the value of $e after
the increment, 2*7 = 14 to $g */
$h = $g += 10; /* first, $g is incremented by 10 and ends with the
value of 24. the value of the assignment (24) is
then assigned into $h, and $h ends with the value
of 24 as well. */
?>
26. Operatori
Important Un operator este ceva care ia una sau mai multe valori (sau expresii, în jargonul
programării) și produce o altă valoare (astfel încât construcția în sine devine o expresie).
Important Operatorii pot fi grupați în funcție de numărul de valori pe care le iau. Operatorii unari
iau o singură valoare, de exemplu ! (operatorul logic not) sau ++ (operatorul de incrementare).
Operatorii binari iau două valori, cum ar fi operatorii aritmetici familiari + (plus) și - (minus), iar
majoritatea operatorilor PHP fac parte din această categorie. În cele din urmă, există un singur
operator ternar, ? :, care ia trei valori; acesta este denumit de obicei pur și simplu „operatorul ternar”
(deși poate ar putea fi numit mai corect operatorul condițional).
Important Precedența unui operator specifică cât de „strâns” leagă două expresii între ele. De
exemplu, în expresia 1 + 5 * 3, răspunsul este 16 și nu 18 deoarece operatorul de înmulțire („*”) are
o precedență mai mare decât operatorul de adunare („+”). Parantezele pot fi utilizate pentru a forța
precedența, dacă este necesar. De exemplu: (1 + 5) * 3 se evaluează la 18.
Important Tabelul următor enumeră operatorii în ordinea precedenței, cu cei cu precedența cea mai
mare în partea de sus. Operatorii de pe aceeași linie au precedență egală, caz în care asociativitatea
decide gruparea.

Associativity Operators Additional Information


(n/a) clone new clone and new
right ** arithmetic
+ - ++ -- ~ (int) (float) arithmetic (unary + and -),
(n/a) (string) (array) (object) increment/decrement, bitwise, type casting
(bool) @ and error control
left instanceof type
(n/a) ! logical
left */% arithmetic
arithmetic (binary + and -), array and
left +-.
string (. prior to PHP 8.0.0)
left << >> bitwise
left . string (as of PHP 8.0.0)
non-associative < <= > >= comparison
non-associative == != === !== <> <=> comparison
left & bitwise and references
left ^ bitwise
left | bitwise
left && logical
left || logical
right ?? null coalescing
ternary (left-associative prior to PHP
non-associative ? :
8.0.0)
= += -= *= **= /= .= %= &= |= ^=
right assignment
<<= >>= ??=
(n/a) yield from yield from
(n/a) yield yield
(n/a) print print
left and logical
Associativity Operators Additional Information
left xor logical
left or logical

Example Name Result


+$a Identity Conversion of $a to int or float as appropriate.
-$a Negation Opposite of $a.
$a + $b Addition Sum of $a and $b.
$a - $b Subtraction Difference of $a and $b.
$a * $b Multiplication Product of $a and $b.
$a / $b Division Quotient of $a and $b.
$a % $b Modulo Remainder of $a divided by $b.
$a ** $b Exponentiation Result of raising $a to the $b'th power.

Important Operatorul de diviziune / returnează o valoare float, cu excepția cazului în care cei doi
operanzi sunt int (sau șiruri numerice care sunt transformate în int), iar numărătorul este un multiplu
al divizorului, caz în care va fi returnată o valoare întreagă. Pentru diviziunea numerelor întregi,
consultați intdiv().

Important Operanzii modulo sunt convertiți în int înainte de prelucrare. Pentru modulo în virgulă
mobilă, consultați fmod().

xample Name Effect


++$a Pre-increment Increments $a by one, then returns $a.
$a++ Post-increment Returns $a, then increments $a by one.
--$a Pre-decrement Decrements $a by one, then returns $a.
$a-- Post-decrement Returns $a, then decrements $a by one.

Example Equivalent Operation


$a += $b $a = $a + $b Addition
$a -= $b $a = $a - $b Subtraction
$a *= $b $a = $a * $b Multiplication
$a /= $b $a = $a / $b Division
$a %= $b $a = $a % $b Modulus
$a **= $b $a = $a ** $b Exponentiation

Example Equivalent Operation


$a &= $b $a = $a & $b Bitwise And
$a |= $b $a = $a | $b Bitwise Or
$a ^= $b $a = $a ^ $b Bitwise Xor
$a <<= $b $a = $a << $b Left Shift
$a >>= $b $a = $a >> $b Right Shift
Example Equivalent Operation
$a .= $b $a = $a . $b String Concatenation
$a ??= $b $a = $a ?? $b Null Coalesce

Important Operatorii bitwise permit evaluarea și manipularea anumitor biți dintr-un număr întreg.

Example Name Result


$a & $b And Bits that are set in both $a and $b are set.
$a | $b Or (inclusive or) Bits that are set in either $a or $b are set.
$a ^ $b Xor (exclusive Bits that are set in $a or $b but not both are set.
or)
~ $a Not Bits that are set in $a are not set, and vice versa.
$a << $b Shift left Shift the bits of $a $b steps to the left (each step means "multiply
by two")
$a >> $b Shift right Shift the bits of $a $b steps to the right (each step means "divide by
two")

Important Deplasarea biților în PHP este aritmetică. Biturile deplasate de la ambele capete sunt
eliminate. La deplasarea spre stânga, zerourile sunt deplasate în dreapta, în timp ce bitul de semn
este deplasat în stânga, ceea ce înseamnă că semnul unui operand nu este păstrat. În cazul deplasării
spre dreapta, copiile bitului de semn sunt deplasate spre stânga, ceea ce înseamnă că semnul unui
operand este păstrat.
Important Dacă ambii operanzi pentru operatorii &, | și ^ sunt șiruri de caractere, operația va fi
efectuată asupra valorilor ASCII ale caracterelor care alcătuiesc șirurile de caractere, iar rezultatul
va fi un șir de caractere. În toate celelalte cazuri, ambii operanzi vor fi convertiți în numere întregi,
iar rezultatul va fi un număr întreg.
Important Dacă operandul pentru operatorul ~ este un șir de caractere, operația va fi efectuată
asupra valorilor ASCII ale caracterelor care alcătuiesc șirul, iar rezultatul va fi un șir de caractere; în
caz contrar, operandul și rezultatul vor fi tratate ca numere întregi.
Important Atât operanzii, cât și rezultatul pentru operatorii << și >> sunt întotdeauna tratați ca
numere întregi.
Important Operatorii de comparare, după cum sugerează și numele lor, vă permit să comparați două
valori. De asemenea, este posibil să fiți interesat să vizualizați tabelele de comparare a tipurilor,
deoarece acestea prezintă exemple de diverse comparații legate de tipuri.

Example Name Result


$a == $b Equal true if $a is equal to $b after type juggling.
$a === $b Identical true if $a is equal to $b, and they are of the same type.
$a != $b Not equal true if $a is not equal to $b after type juggling.
$a <> $b Not equal true if $a is not equal to $b after type juggling.
$a !== $b Not identical true if $a is not equal to $b, or they are not of the same type.
$a < $b Less than true if $a is strictly less than $b.
$a > $b Greater than true if $a is strictly greater than $b.
Less than or equal
$a <= $b true if $a is less than or equal to $b.
to
Greater than or
$a >= $b true if $a is greater than or equal to $b.
equal to
$a <=> $b Spaceship An int less than, equal to, or greater than zero when $a is less than,
Example Name Result
equal to, or greater than $b, respectively.

Important Dacă ambii operanzi sunt șiruri numerice sau unul dintre operanzi este un număr, iar
celălalt este un șir numeric, atunci comparația se face numeric. Aceste reguli se aplică și la
instrucțiunea switch. Conversia de tip nu are loc atunci când comparația este === sau !==, deoarece
aceasta implică compararea tipului, precum și a valorii.

Type of Type of
Result
Operand 1 Operand 2
null or string string Convert null to "", numerical or lexical comparison
bool or null anything Convert both sides to bool, false < true
Built-in classes can define its own comparison, different classes
object object
are incomparable, same class see Object Comparison
string, string,
resource, int or resource, int or Translate strings and resources to numbers, usual math
float float
Array with fewer members is smaller, if key from operand 1 is not
array array found in operand 2 then arrays are incomparable, otherwise -
compare value by value (see following example)
object anything object is always greater
array anything array is always greater

Important Expresia (expr1) ? (expr2) : (expr3) se evaluează la expr2 dacă expr1 se evaluează la
adevărat și la expr3 dacă expr1 se evaluează la fals. Este posibil să se omită partea din mijloc a
operatorului ternar. Expresia expr1 ?: expr3 se evaluează la rezultatul expr1 dacă expr1 se evaluează
la true, și la expr3 în caz contrar. expr1 este evaluată o singură dată în acest caz.
Important Expresia (expr1) ?? (expr2) este evaluată la expr2 dacă expr1 este nul, și la expr1 în caz
contrar. În special, acest operator nu emite o notificare sau un avertisment dacă valoarea din partea
stângă nu există, la fel ca isset(). Acest lucru este util în special în cazul cheilor de array.
Important PHP acceptă un singur operator de control al erorilor: semnul at (@).Atunci când este
atașat unei expresii în PHP, orice diagnostic de eroare care ar putea fi generat de expresia respectivă
va fi suprimat.
Important Dacă o funcție personalizată de gestionare a erorilor este setată cu set_error_handler(),
aceasta va fi apelată în continuare chiar dacă diagnosticul a fost suprimat. Orice mesaj de eroare
generat de expresie este disponibil în elementul „message” al array-ului returnat de error_get_last().
Rezultatul acestei funcții se va schimba la fiecare eroare, deci trebuie verificat din timp.

Important PHP acceptă un singur operator de execuție: ghilimelele (``). Rețineți că acestea nu sunt
ghilimele simple! PHP va încerca să execute conținutul ghilimelelor ca o comandă shell; rezultatul
va fi returnat (adică, nu va fi pur și simplu transferat la ieșire; poate fi atribuit unei variabile).
Utilizarea operatorului backtick este identică cu shell_exec().
<?php
$output = `ls -al`;
echo "<pre>$output</pre>";
?>
Example Name Result
$a and $b And true if both $a and $b are true.
$a or $b Or true if either $a or $b is true.
$a xor $b Xor true if either $a or $b is true, but not both.
! $a Not true if $a is not true.
$a && $b And true if both $a and $b are true.
$a || $b Or true if either $a or $b is true.

Important Există doi operatori de șir de caractere. Primul este operatorul de concatenare ('.'), care
returnează concatenarea argumentelor sale din dreapta și din stânga. Al doilea este operatorul de
atribuire de concatenare ('.='), care anexează argumentul din partea dreaptă la argumentul din partea
stângă. Vă rugăm să citiți Operatori de atribuire pentru mai multe informații.
<?php
$a = "Hello ";
$b = $a . "World!"; // now $b contains "Hello World!"

$a = "Hello ";
$a .= "World!"; // now $a contains "Hello World!"
?>

Important Daca $a și $b sunt array:

Example Name Result


$a + $b Union Union of $a and $b.
$a == $b Equality true if $a and $b have the same key/value pairs.
true if $a and $b have the same key/value pairs in the same order and of
$a === $b Identity
the same types.
$a != $b Inequality true if $a is not equal to $b.
$a <> $b Inequality true if $a is not equal to $b.
$a !== $b Non-identity true if $a is not identical to $b.

<?php
$a = array("a" => "apple", "b" => "banana");
$b = array("a" => "pear", "b" => "strawberry", "c" => "cherry");

$c = $a + $b; // Union of $a and $b


echo "Union of \$a and \$b: \n";
var_dump($c);

$c = $b + $a; // Union of $b and $a


echo "Union of \$b and \$a: \n";
var_dump($c);

$a += $b; // Union of $a += $b is $a and $b


echo "Union of \$a += \$b: \n";
var_dump($a);
?>
Important instanceof este utilizat pentru a determina dacă o variabilă PHP este un obiect instanțiat
al unei anumite clase. instanceof poate fi, de asemenea, utilizată pentru a determina dacă o variabilă
este un obiect instanțiat al unei clase care moștenește de la o clasă părinte. În cele din urmă,
instanceof poate fi utilizat și pentru a determina dacă o variabilă este un obiect instanțiat al unei
clase care implementează o interfață. Deși instanceof este utilizat de obicei cu un nume de clasă
literal, poate fi utilizat și cu un alt obiect sau cu o variabilă de tip string.

27. Structuri de control


Important Orice script PHP este construit dintr-o serie de instrucțiuni. O instrucțiune poate fi o
atribuire, un apel de funcție, o buclă, o instrucțiune condițională sau chiar o instrucțiune care nu
face nimic (o instrucțiune goală). Declarațiile se termină de obicei cu punct și virgulă. În plus,
instrucțiunile pot fi grupate într-un grup de instrucțiuni prin încapsularea unui grup de instrucțiuni
cu paranteze. Un statement-grup este, de asemenea, un statement de sine stătător. Diferitele tipuri de
instrucțiuni sunt descrise în acest capitol.

Important Construcția if este una dintre cele mai importante caracteristici ale multor limbaje,
inclusiv PHP. Aceasta permite executarea condiționată a fragmentelor de cod. PHP dispune de o
structură if similară cu cea din C:

if (expr)
declarație

Important După cum s-a descris în secțiunea despre expresii, expresia este evaluată la valoarea sa
booleană. Dacă expresia este evaluată la true, PHP va executa declarația, iar dacă este evaluată la
false - o va ignora. Mai multe informații despre ce valori evaluează la fals pot fi găsite în secțiunea
„Conversia în boolean”.

Important Instrucțiunea else este executată numai dacă expresia if a fost evaluată la false, iar dacă
există expresii elseif - numai dacă și acestea au fost evaluate la false (a se vedea elseif).

Important elseif, după cum sugerează și numele său, este o combinație de if și else. La fel ca else,
extinde o instrucțiune if pentru a executa o instrucțiune diferită în cazul în care expresia if originală
este evaluată la fals. Cu toate acestea, spre deosebire de else, va executa acea expresie alternativă
numai dacă expresia condițională elseif este evaluată la true.
Important Pot exista mai multe elseif în cadrul aceleiași instrucțiuni if. Prima expresie elseif (dacă
există) care este evaluată la true ar fi executată. În PHP, este posibil să se scrie else if (în două
cuvinte) și comportamentul ar fi identic cu cel al elseif (într-un singur cuvânt). Semnificația
sintactică este ușor diferită (același comportament ca în C), dar concluzia este că ambele ar duce la
exact același comportament.
Important Instrucțiunea elseif este executată numai dacă expresia if anterioară și orice expresie
elseif anterioară au evaluat la false, iar expresia elseif curentă a evaluat la true.

<?php
if ($a > $b) {
echo "a is bigger than b";
} elseif ($a == $b) {
echo "a is equal to b";
} else {
echo "a is smaller than b";
}
?>
Important PHP oferă o sintaxă alternativă pentru unele dintre structurile sale de control; și anume,
if, while, for, foreach și switch. În fiecare caz, forma de bază a sintaxei alternative este schimbarea
parantezei de deschidere cu două puncte (:) și a parantezei de închidere cu endif;, endwhile;,
endfor;, endforeach;, sau endswitch;, respectiv.

<?php if ($a == 5): ?>


A is equal to 5
<?php endif; ?>

Important Buclele while sunt cel mai simplu tip de bucle în PHP. Ele se comportă la fel ca cele din
C. Forma de bază a unei instrucțiuni while este:

while (expr)
instrucțiune

Important Semnificația unei instrucțiuni while este simplă. Aceasta îi spune PHP să execute
declarația (declarațiile) imbricate în mod repetat, atât timp cât expresia while este evaluată la true.
Valoarea expresiei este verificată de fiecare dată la începutul buclei, astfel încât, chiar dacă această
valoare se modifică în timpul executării instrucțiunii (instrucțiunilor) imbricate, execuția nu se va
opri până la sfârșitul iterației (fiecare dată când PHP execută instrucțiunile din buclă este o iterație).
Dacă expresia while este evaluată la false încă de la început, instrucțiunea (instrucțiunile) imbricate
nu vor fi executate nici măcar o dată.

<?php
$i = 1;
while ($i <= 10):
echo $i;
$i++;
endwhile;
?>

Important buclele do-while sunt foarte asemănătoare buclelor while, cu excepția faptului că
expresia adevărului este verificată la sfârșitul fiecărei iterații și nu la început. Principala diferență
față de buclele while obișnuite este că prima iterație a unei bucle do-while are execuția garantată
(expresia adevărului este verificată numai la sfârșitul iterației), în timp ce execuția unei bucle while
obișnuite nu este neapărat garantată (expresia adevărului este verificată la începutul fiecărei iterații;
dacă aceasta este evaluată la fals chiar de la început, execuția buclei se va încheia imediat).

<?php
$i = 0;
do {
echo $i;
} while ($i > 0);
?>

Important buclele for sunt cele mai complexe bucle din PHP. Ele se comportă ca omologii lor din C.
Sintaxa unei bucle for este:

for (expr1; expr2; expr3)


instrucțiune
Important Prima expresie (expr1) este evaluată (executată) o dată necondiționat la începutul buclei.
La începutul fiecărei iterații, expr2 este evaluată. Dacă se evaluează la true, bucla continuă și se
execută instrucțiunea (instrucțiunile) imbricate. Dacă se evaluează la false, execuția buclei se
încheie. La sfârșitul fiecărei iterații, expr3 este evaluată (executată).
Important Fiecare dintre expresii poate fi goală sau poate conține mai multe expresii separate prin
virgulă. În expr2, toate expresiile separate prin virgulă sunt evaluate, dar rezultatul este preluat din
ultima parte. expr2 fiind goală înseamnă că bucla ar trebui să fie executată la nesfârșit (PHP o
consideră implicit ca fiind adevărată, ca C). Este posibil ca acest lucru să nu fie atât de inutil pe cât
s-ar putea crede, deoarece adesea ați dori să încheiați bucla utilizând o instrucțiune de întrerupere
condiționată în loc să utilizați expresia for truth.

<?php
$i = 1;
for (; ; ) {
if ($i > 10) {
break;
}
echo $i;
$i++;
}
?>

Important Construcția foreach oferă o modalitate ușoară de a itera peste matrici. foreach
funcționează numai pe matrici și obiecte și va produce o eroare atunci când încercați să o utilizați pe
o variabilă cu un tip de date diferit sau pe o variabilă neinițializată. Există două sintaxe:

foreach (iterable_expression as $value)


instrucțiune
foreach (iterable_expression as $key => $value)
declarație

Important Prima formă traversează iterabilul dat de iterable_expression. La fiecare iterație, valoarea
elementului curent este atribuită lui $value. A doua formă va atribui în plus cheia elementului curent
variabilei $key la fiecare iterație. Rețineți că foreach nu modifică pointerul matricei interne, care
este utilizat de funcții

<?php
$arr = array(1, 2, 3, 4);
foreach ($arr as &$value) {
$value = $value * 2;
}
// $arr is now array(2, 4, 6, 8)
unset($value); // break the reference with the last element
?>

Important break încheie execuția structurii curente for, foreach, while, do-while sau switch. break
acceptă un argument numeric opțional care îi indică numărul de structuri de închidere imbricate din
care trebuie să fie întreruptă. Valoarea implicită este 1, numai structura de închidere imediată este
întreruptă.
<?php
$arr = array('one', 'two', 'three', 'four', 'stop', 'five');
foreach ($arr as $val) {
if ($val == 'stop') {
break; /* You could also write 'break 1;' here. */
}
echo "$val<br />\n";
}
?>

Important continue este utilizat în cadrul structurilor de buclă pentru a sări peste restul iterației
buclei curente și a continua execuția la evaluarea condiției și apoi la începutul iterației următoare.

<?php
$arr = ['zero', 'one', 'two', 'three', 'four', 'five', 'six'];
foreach ($arr as $key => $value) {
if (0 === ($key % 2)) { // skip members with even key
continue;
}
echo $value . "\n";
}
?>

Important Instrucțiunea switch este similară cu o serie de instrucțiuni IF pentru aceeași expresie. În
multe cazuri, este posibil să doriți să comparați aceeași variabilă (sau expresie) cu mai multe valori
diferite și să executați o parte diferită de cod în funcție de valoarea la care este egală. Acesta este
exact scopul instrucțiunii switch.
<?php
// This switch statement:

switch ($i) {
case 0:
echo "i equals 0";
break;
case 1:
echo "i equals 1";
break;
case 2:
echo "i equals 2";
break;
}

// Is equivalent to:

if ($i == 0) {
echo "i equals 0";
} elseif ($i == 1) {
echo "i equals 1";
} elseif ($i == 2) {
echo "i equals 2";
}
?>
Important Un caz special este cazul default. Acest caz se potrivește cu orice lucru care nu a fost
potrivit în celelalte cazuri. De exemplu:

<?php
switch ($i) {
case 0:
echo "i equals 0";
break;
case 1:
echo "i equals 1";
break;
case 2:
echo "i equals 2";
break;
default:
echo "i is not equal to 0, 1 or 2";
}
?>

Important Expresia match ramifică evaluarea pe baza unei verificări a identității unei valori. La fel
ca o instrucțiune switch, o expresie match are o expresie subiect care este comparată cu mai multe
alternative. Spre deosebire de switch, aceasta va fi evaluată la o valoare, la fel ca expresiile ternare.
Spre deosebire de switch, comparația este o verificare a identității (===) mai degrabă decât o
verificare slabă a egalității (==). Expresiile Match sunt disponibile începând cu PHP 8.0.0.

<?php
$return_value = match (subject_expression) {
single_conditional_expression => return_expression,
conditional_expression1, conditional_expression2 => return_expression,
};
?>

Important Expresia match este similară cu o instrucțiune switch, dar are câteva diferențe esențiale:
• O expresie de potrivire compară valorile strict (===) în loc de liber, așa cum face
instrucțiunea switch.
• O expresie match returnează o valoare.
• brațele match nu trec la cazuri ulterioare, așa cum fac instrucțiunile switch.
• O expresie match trebuie să fie exhaustivă.

Important Ca și instrucțiunile switch, expresiile match sunt executate braț cu braț. La început, nu se
execută niciun cod. Expresiile condiționale sunt evaluate numai dacă toate expresiile condiționale
anterioare nu au reușit să corespundă expresiei subiect. Va fi evaluată numai expresia de revenire
corespunzătoare expresiei condiționale potrivite. De exemplu:

<?php
$result = match ($x) {
foo() => ...,
$this->bar() => ..., // $this->bar() isn't called if foo() === $x
$this->baz => beep(), // beep() isn't called unless $x === $this->baz
// etc.
};
?>
Important brațele expresiei de potrivire pot conține mai multe expresii separate prin virgulă. Acesta
este un OR logic și este o prescurtare pentru mai multe brațe de potrivire cu aceeași parte dreaptă.

<?php
$result = match ($x) {
// This match arm:
$a, $b, $c => 5,
// Is equivalent to these three match arms:
$a => 5,
$b => 5,
$c => 5,
};
?>

Important Un caz special este modelul implicit. Acest model se potrivește cu orice lucru care nu a
fost potrivit anterior. De exemplu:

<?php
$condition = 5;

try {
match ($condition) {
1, 2 => foo(),
3, 4 => bar(),
};
} catch (\UnhandledMatchError $e) {
var_dump($e);
}
?>

Important Construcția declare este folosită pentru a seta directive de execuție pentru un bloc de cod.
Sintaxa declare este similară cu sintaxa altor constructe de control al fluxului:

declara (directiva)
declaraţie

Important Secțiunea directive permite setarea comportamentului blocului de declarare. În prezent


sunt recunoscute doar trei directive:
• căpușe
• codificare
• strict_types
Important Deoarece directivele sunt gestionate pe măsură ce fișierul este compilat, numai literalele
pot fi date ca valori de directive. Variabilele și constantele nu pot fi utilizate. Pentru a ilustra:

<?php
// This is valid:
declare(ticks=1);

// This is invalid:
const TICK_VALUE = 1;
declare(ticks=TICK_VALUE);
?>
Important Partea de instrucțiune a blocului declare va fi executată - cum este executată și ce efecte
secundare apar în timpul execuției pot depinde de directiva setată în blocul de directive.
Important Construcția declare poate fi folosită și în domeniul global, afectând tot codul care îl
urmează (cu toate acestea, dacă fișierul cu declarare a fost inclus, atunci nu afectează fișierul
părinte).

<?php
// these are the same:

// you can use this:


declare(ticks=1) {
// entire script here
}

// or you can use this:


declare(ticks=1);
// entire script here
?>

Important Un tick este un eveniment care are loc pentru fiecare N instrucțiuni bifabile de nivel
scăzut executate de parser în blocul declare. Valoarea pentru N este specificată folosind ticks=N în
secțiunea de directive a blocului de declarare.
Important Nu toate afirmațiile sunt bifabile. De obicei, expresiile de condiție și expresiile de
argument nu pot fi bifate.
Important Evenimentele care apar pe fiecare bifă sunt specificate folosind funcția
register_tick_function().

Important return returnează controlul programului către modulul apelant. Execuția se reia la
expresia care urmează invocării modulului apelat.
Important Dacă este apelată dintr-o funcție, instrucțiunea return încheie imediat execuția funcției
curente și returnează argumentul acesteia ca valoare a apelului funcției. return încheie, de asemenea,
execuția unei instrucțiuni eval() sau a unui fișier script.
Important Dacă este apelat din domeniul global, atunci execuția fișierului script curent este
încheiată. Dacă fișierul script curent a fost inclus sau necesar, atunci controlul este transmis înapoi
fișierului apelant. În plus, dacă fișierul script curent a fost inclus, atunci valoarea dată pentru
returnare va fi returnată ca valoare a apelului include. Dacă return este apelat din interiorul fișierului
script principal, atunci execuția scriptului se termină. Dacă fișierul script curent a fost denumit de
opțiunile de configurare auto_prepend_file sau auto_append_file din [Link], atunci execuția acelui
fișier script este încheiată.

Important require este identic cu includerea, cu excepția cazului în care va produce, de asemenea, o
eroare fatală la nivel E_COMPILE_ERROR. Cu alte cuvinte, va opri scriptul, în timp ce include
emite doar un avertisment (E_WARNING) care permite script-ului să continue.

Important Expresia include include și evaluează fișierul specificat. Documentația de mai jos se
aplică și pentru solicitarea. Fișierele sunt incluse în funcție de calea fișierului dată sau, dacă nu este
specificată nici una, de calea_include specificată. Dacă fișierul nu este găsit în include_path, include
va verifica în sfârșit propriul director al scriptului de apelare și directorul de lucru curent înainte de
a eșua. Construcția include va emite un E_WARNING dacă nu poate găsi un fișier; acesta este un
comportament diferit de require, care va emite un E_ERROR.
Important Rețineți că ambele includ și necesită ridicarea E_WARNING-uri suplimentare, dacă
fișierul nu poate fi accesat, înainte de a genera E_WARNING sau, respectiv, E_ERROR final.
Important Dacă este definită o cale — fie absolută (începând cu o litera de unitate sau \ pe
Windows, sau / pe sisteme Unix/Linux) sau relativ la directorul curent (începând cu . sau ..) —
include_path va fi ignorată cu totul. De exemplu, dacă un nume de fișier începe cu ../, analizatorul
va căuta în directorul părinte pentru a găsi fișierul solicitat.
Important Când un fișier este inclus, codul pe care îl conține moștenește domeniul variabil al liniei
pe care are loc includerea. Orice variabilă disponibilă la acea linie din fișierul apelant va fi
disponibilă în fișierul apelat, din acel moment înainte. Cu toate acestea, toate funcțiile și clasele
definite în fișierul inclus au domeniul de aplicare global.
Important Dacă includerea are loc în interiorul unei funcții din fișierul apelant, atunci tot codul
conținut în fișierul apelat se va comporta ca și cum ar fi fost definit în interiorul acelei funcții. Deci,
va urma domeniul variabil al acelei funcții. O excepție de la această regulă sunt constantele magice
care sunt evaluate de parser înainte de includerea.
Important Dacă „URL include wrappers” este activat în PHP, puteți specifica fișierul care urmează
să fie inclus folosind o adresă URL (prin HTTP sau alt wrapper acceptat - consultați Protocoale și
Wrappers acceptate pentru o listă de protocoale) în loc de o cale locală. Dacă serverul țintă
interpretează fișierul țintă ca cod PHP, variabilele pot fi transmise fișierului inclus folosind un șir de
solicitare URL așa cum este utilizat cu HTTP GET. Acest lucru nu înseamnă, strict vorbind, același
lucru cu includerea fișierului și ca acesta să moștenească domeniul de aplicare al variabilei fișierului
părinte; scriptul este de fapt rulat pe serverul de la distanță și rezultatul este apoi inclus în scriptul
local.

<?php
$foo = include '[Link]';
echo $foo; // prints 'PHP'
$bar = include '[Link]';
echo $bar; // prints 1
?>

<?php
$string = get_include_contents('[Link]');

function get_include_contents($filename) {
if (is_file($filename)) {
ob_start();
include $filename;
return ob_get_clean();
}
return false;
}

?>

Important Expresia require_once este identică cu require, cu excepția faptului că PHP va verifica
dacă fișierul a fost deja inclus și, dacă da, nu îl va include (require) din nou.

Important Expresia include_once include și evaluează fișierul specificat în timpul execuției


scriptului. Acesta este un comportament similar cu expresia include, cu singura diferență fiind că,
dacă codul dintr-un fișier a fost deja inclus, acesta nu va fi inclus din nou și include_once returnează
true. După cum sugerează și numele, fișierul va fi inclus o singură dată.
Important include_once poate fi folosit în cazurile în care același fișier ar putea fi inclus și evaluat
de mai multe ori în timpul unei anumite execuții a unui script, astfel încât în acest caz poate ajuta la
evitarea problemelor precum redefinirea funcțiilor, reatribuirea valorii variabile etc.

Important Operatorul goto poate fi folosit pentru a trece la o altă secțiune a programului. Punctul
țintă este specificat printr-o etichetă sensibilă la majuscule, urmată de două puncte, iar instrucțiunea
este dată ca goto urmată de eticheta țintă dorită. Acesta nu este un acces complet nerestricționat.
Eticheta țintă trebuie să fie în același fișier și context, ceea ce înseamnă că nu puteți sări dintr-o
funcție sau metodă și nici nu puteți sări într-una. De asemenea, nu puteți sări în nici un fel de buclă
sau structură de comutare. Puteți sări din acestea, iar o utilizare obișnuită este utilizarea unui goto în
locul unei pauze pe mai multe niveluri.

<?php
goto a;
echo 'Foo';
a:
echo 'Bar';
?>

Important Orice cod PHP valid poate apărea în interiorul unei funcții, chiar și alte funcții și definiții
de clasă.
Important Numele funcțiilor urmează aceleași reguli ca și alte etichete în PHP. Un nume valid de
funcție începe cu o literă sau liniuță de subliniere, urmată de orice număr de litere, cifre sau liniuțe
de subliniere. Ca expresie regulată, ar fi exprimată astfel: ^[a-zA-Z_\x80-\xff][a-zA-Z0-9_\x80-\
xff]*$.

<?php
function foo($arg_1, $arg_2, /* ..., */ $arg_n)
{
echo "Example function.\n";
return $retval;
}
?>

Important Funcțiile nu trebuie definite înainte de a fi referite, cu excepția cazului în care o funcție
este definită condiționat, așa cum se arată în cele două exemple de mai jos.
Important Când o funcție este definită într-o manieră condiționată, cum ar fi cele două exemple
prezentate. Definiția sa trebuie procesată înainte de a fi apelată.
Important Toate funcțiile și clasele din PHP au sfera globală - pot fi apelate în afara unei funcții
chiar dacă au fost definite în interior și invers. PHP nu acceptă supraîncărcarea funcțiilor și nici nu
este posibilă nedefinirea sau redefinirea funcțiilor declarate anterior.

Important Parametrii funcției sunt declarați în semnătura funcției. Informațiile pot fi transmise
funcțiilor prin lista de argumente, care este o listă de expresii delimitată prin virgulă. Argumentele
sunt evaluate de la stânga la dreapta și rezultatul este atribuit parametrilor funcției, înainte ca funcția
să fie apelată efectiv (eager evaluation).
Important PHP acceptă transmiterea argumentelor după valoare (implicit), transmiterea prin
referință și valorile argumentelor implicite. Sunt acceptate și listele de argumente cu lungime
variabilă și Argumentele numite.
<?php
function takes_many_args(
$first_arg,
$second_arg,
$a_very_long_argument_name,
$arg_with_default = 5,
$again = 'a default string', // This trailing comma was not permitted before 8.0.0.
)
{
// ...
}
?>

Important În mod implicit, argumentele funcției sunt transmise după valoare (astfel încât, dacă
valoarea argumentului din cadrul funcției este modificată, aceasta nu este modificată în afara
funcției). Pentru a permite unei funcții să își modifice argumentele, acestea trebuie să fie transmise
prin referință.
Important Pentru a avea un argument pentru o funcție transmis întotdeauna prin referință, adăugați
un ampersand (&) la numele parametrului în definiția funcției:

<?php
function add_some_extra(&$string)
{
$string .= 'and something extra.';
}
$str = 'This is a string, ';
add_some_extra($str);
echo $str; // outputs 'This is a string, and something extra.'
?>

Important O funcție poate defini valori implicite pentru parametri folosind o sintaxă similară cu
alocarea unei variabile. Valoarea implicită este utilizată numai atunci când argumentul parametrului
nu este transmis. Rețineți că trecerea null nu atribuie valoarea implicită.

<?php
function makecoffee($type = "cappuccino")
{
return "Making a cup of $type.\n";
}
echo makecoffee();
echo makecoffee(null);
echo makecoffee("espresso");
?>

Important Valorile implicite ale parametrilor pot fi valori scalare, matrice, tipul special null și,
începând cu PHP 8.1.0, obiecte care utilizează noua sintaxă ClassName().

Important Valoarea implicită trebuie să fie o expresie constantă, nu (de exemplu) o variabilă, un
membru al clasei sau un apel de funcție. Rețineți că orice parametri opționali trebuie specificati
după orice parametri solicitați, altfel nu pot fi omisi din apeluri.
<?php
function makecoffee($types = array("cappuccino"), $coffeeMaker = NULL)
{
$device = is_null($coffeeMaker) ? "hands" : $coffeeMaker;
return "Making a cup of ".join(", ", $types)." with $device.\n";
}
echo makecoffee();
echo makecoffee(array("cappuccino", "lavazza"), "teapot");?>

<?php
class DefaultCoffeeMaker {
public function brew() {
return "Making coffee.\n";
}
}
class FancyCoffeeMaker {
public function brew() {
return "Crafting a beautiful coffee just for you.\n";
}
}
function makecoffee($coffeeMaker = new DefaultCoffeeMaker)
{
return $coffeeMaker->brew();
}
echo makecoffee();
echo makecoffee(new FancyCoffeeMaker);
?>

Important Începând cu PHP 8.0.0, argumentele numite pot fi folosite pentru a sări peste mai mulți
parametri opționali.
Important Începând cu PHP 8.0.0, declararea parametrilor obligatorii după parametrii opționali este
depreciată. În general, acest lucru poate fi rezolvat prin eliminarea valorii implicite, deoarece nu va
fi niciodată folosită. O excepție de la această regulă sunt parametrii de forma Type $param = null,
unde implicit nul face ca tipul să fie implicit nul. Această utilizare este depreciată începând cu PHP
8.4.0 și ar trebui folosit un tip explicit nullabil.

<?php

function foo($a = [], $b) {} // Default not used; deprecated as of PHP 8.0.0
function foo($a, $b) {} // Functionally equivalent, no deprecation notice

function bar(A $a = null, $b) {} // As of PHP 8.1.0, $a is implicitly required


// (because it comes before the required one),
// but implicitly nullable (deprecated as of PHP 8.4.0),
// because the default parameter value is null
function bar(?A $a, $b) {} // Recommended

?>
Important PHP are suport pentru liste de argumente cu lungime variabilă în funcțiile definite de
utilizator prin utilizarea simbolului .... Listele de parametri pot include simbolul ... pentru a indica
faptul că funcția acceptă un număr variabil de argumente. Argumentele vor fi trecute în variabila
dată ca o matrice:

<?php
function sum(...$numbers) {
$acc = 0;
foreach ($numbers as $n) {
$acc += $n;
}
return $acc;
}

echo sum(1, 2, 3, 4);


?>

<?php
function add($a, $b) {
return $a + $b;
}

echo add(...[1, 2])."\n";

$a = [1, 2];
echo add(...$a);
?>

Important Puteți specifica parametrii de poziție normali înainte de simbolul.... În acest caz, numai
argumentele de sfârșit care nu se potrivesc cu un argument pozițional vor fi adăugate la tabloul
generat de .... De asemenea, este posibil să adăugați o declarație de tip înainte de simbolul .... Dacă
acesta este prezent, atunci toate argumentele capturate de... trebuie să se potrivească cu acel tip de
parametru.

Important PHP 8.0.0 a introdus argumente numite ca o extensie a parametrilor poziționali existenți.
Argumentele denumite permit transmiterea argumentelor unei funcții bazate pe numele
parametrului, mai degrabă decât pe poziția parametrului. Acest lucru face ca sensul argumentului să
se auto-documenteze, face ca argumentele să fie independente de ordine și permite sărirea în mod
arbitrar a valorilor implicite.
Important Argumentele numite sunt transmise prin prefixarea valorii cu numele parametrului urmat
de două puncte. Este permisă utilizarea cuvintelor cheie rezervate ca nume de parametri. Numele
parametrului trebuie să fie un identificator, nu este permisă specificarea dinamică.

<?php
myFunction(paramName: $value);
array_foobar(array: $value);

// NOT supported.
function_name($variableStoringParamName: $value);
?>
<?php
// Using positional arguments:
array_fill(0, 100, 50);

// Using named arguments:


array_fill(start_index: 0, count: 100, value: 50);
?>

Important Argumentele numite pot fi combinate cu argumente poziționale. În acest caz,


argumentele numite trebuie să vină după argumentele poziționale. De asemenea, este posibil să se
specifice doar unele dintre argumentele opționale ale unei funcții, indiferent de ordinea acestora.

<?php
htmlspecialchars($string, double_encode: false);
// Same as
htmlspecialchars($string, ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML401, 'UTF-8', false);
?>

Important Trecerea unui argument la același parametru numit de mai multe ori duce la o excepție
Error.
Important Începând cu PHP 8.1.0, este posibil să se utilizeze argumente numite după despachetarea
argumentelor. Un argument numit nu trebuie să suprascrie un argument deja dezambalat.

<?php
function foo($a, $b, $c = 3, $d = 4) {
return $a + $b + $c + $d;
}

var_dump(foo(...[1, 2], d: 40)); // 46


var_dump(foo(...['b' => 2, 'a' => 1], d: 40)); // 46

var_dump(foo(...[1, 2], b: 20)); // Fatal error. Named parameter $b overwrites previous argument
?>

Important Valorile sunt returnate prin utilizarea instrucțiunii return opționale. Orice tip poate fi
returnat, inclusiv matrice și obiecte. Acest lucru face ca funcția să își încheie imediat execuția și să
treacă controlul înapoi la linia de la care a fost apelată. Consultați retur pentru mai multe informații.
Important O funcție nu poate returna mai multe valori, dar rezultate similare pot fi obținute prin
returnarea unui tablou.
Important Pentru a returna o referință dintr-o funcție, utilizați operatorul de referință & atât în
declarația funcției, cât și atunci când atribuiți valoarea returnată unei variabile:

<?php
function small_numbers()
{
return [0, 1, 2];
}
// Array destructuring will collect each member of the array individually
[$zero, $one, $two] = small_numbers();
// Prior to 7.1.0, the only equivalent alternative is using list() construct
list($zero, $one, $two) = small_numbers();
?>
<?php
function &returns_reference()
{
return $someref;
}

$newref =& returns_reference();


?>

Important PHP suportă conceptul de funcții variabile. Aceasta înseamnă că, dacă un nume de
variabilă are paranteze atașate, PHP va căuta o funcție cu același nume ca oricare la care evaluează
variabila și va încerca să o execute. Printre altele, aceasta poate fi folosită pentru a implementa
apeluri inverse, tabele de funcții și așa mai departe.
Important Funcțiile variabile nu vor funcționa cu constructe de limbaj precum echo, print, unset(),
isset(), empty(), include, require și altele asemenea. Utilizați funcțiile wrapper pentru a utiliza
oricare dintre aceste construcții ca funcții variabile.

<?php
function foo() {
echo "In foo()<br />\n";
}

function bar($arg = '')


{
echo "In bar(); argument was '$arg'.<br />\n";
}

// This is a wrapper function around echo


function echoit($string)
{
echo $string;
}

$func = 'foo';
$func(); // This calls foo()

$func = 'bar';
$func('test'); // This calls bar()

$func = 'echoit';
$func('test'); // This calls echoit()
?>

Important Funcțiile anonime, cunoscute și sub numele de închideri, permit crearea de funcții care
nu au un nume specificat. Ele sunt cele mai utile ca valoare a parametrilor apelabili, dar au multe
alte utilizări.
Important Funcțiile anonime sunt implementate folosind clasa Closure.

Important Închiderile pot fi folosite și ca valori ale variabilelor; PHP convertește automat astfel de
expresii în instanțe ale clasei interne Closure. Atribuirea unei închideri unei variabile folosește
aceeași sintaxă ca orice altă atribuire, inclusiv punctul și virgulă final:
<?php
$greet = function($name) {
printf("Hello %s\r\n", $name);
};

$greet('World');
$greet('PHP');
?>

Important Închiderile pot moșteni și variabile din domeniul părinte. Orice astfel de variabile trebuie
transmise constructului de utilizare a limbajului. Începând cu PHP 7.1, aceste variabile nu trebuie să
includă superglobale, $this sau variabile cu același nume ca parametru. O declarație de tip returnare
a funcției trebuie plasată după clauza de utilizare.

Important Începând cu PHP 8.0.0, lista de variabile moștenite de domeniul de aplicare poate include
o virgulă finală, care va fi ignorată.
Important Moștenirea variabilelor din domeniul părinte nu este același lucru cu utilizarea
variabilelor globale. Variabilele globale există în domeniul global, care este același, indiferent de
funcția care se execută. Sfera părinte a unei închideri este funcția în care a fost declarată închiderea
(nu neapărat funcția de la care a fost apelată). Vezi următorul exemplu:

<?php
// A basic shopping cart which contains a list of added products
// and the quantity of each product. Includes a method which
// calculates the total price of the items in the cart using a
// closure as a callback.
class Cart
{
const PRICE_BUTTER = 1.00;
const PRICE_MILK = 3.00;
const PRICE_EGGS = 6.95;

protected $products = array();

public function add($product, $quantity)


{
$this->products[$product] = $quantity;
}

public function getQuantity($product)


{
return isset($this->products[$product]) ? $this->products[$product] :
FALSE;
}

public function getTotal($tax)


{
$total = 0.00;

$callback = function ($quantity, $product) use ($tax, &$total)


{
$pricePerItem = constant(__CLASS__ . "::PRICE_" .
strtoupper($product));
$total += ($pricePerItem * $quantity) * ($tax + 1.0);
};

array_walk($this->products, $callback);
return round($total, 2);
}
}

$my_cart = new Cart;

// Add some items to the cart


$my_cart->add('butter', 1);
$my_cart->add('milk', 3);
$my_cart->add('eggs', 6);

// Print the total with a 5% sales tax.


print $my_cart->getTotal(0.05) . "\n";
// The result is 54.29
?>

Important Când este declarată în contextul unei clase, clasa curentă este legată automat de aceasta,
făcând $this disponibil în domeniul de aplicare al funcției. Dacă această legare automată a clasei
curente nu este dorită, atunci pot fi folosite funcții anonime statice.

Important Funcțiile anonime pot fi declarate static. Acest lucru îi împiedică să aibă clasa curentă
legată automat de ei. De asemenea, obiectele pot să nu fie legate de ele în timpul execuției.

<?php

class Foo
{
function __construct()
{
$func = static function() {
var_dump($this);
};
$func();
};
new Foo();

?>

Important Funcțiile săgeți au fost introduse în PHP 7.4 ca o sintaxă mai concisă pentru funcțiile
anonime. Atât funcțiile anonime, cât și funcțiile săgeți sunt implementate folosind clasa Closure.
Funcțiile săgeată au forma de bază fn (argument_list) => expr. Funcțiile săgeată acceptă aceleași
caracteristici ca și funcțiile anonime, cu excepția faptului că utilizarea variabilelor din domeniul
părinte este întotdeauna automată. Când o variabilă utilizată în expresie este definită în domeniul
părinte, aceasta va fi implicit capturată după valoare. În exemplul următor, funcțiile $fn1 și $fn2 se
comportă în același mod.
<?php

$y = 1;

$fn1 = fn($x) => $x + $y;


// equivalent to using $y by value:
$fn2 = function ($x) use ($y) {
return $x + $y;
};

var_export($fn1(3));
?>

Important Similar cu funcțiile anonime, sintaxa funcției săgeată permite semnături de funcții
arbitrare, inclusiv tipuri de parametri și returnări, valori implicite, variadici, precum și trecerea și
returnarea referințelor secundare. Toate următoarele sunt exemple valide de funcții săgeți:

<?php

fn(array $x) => $x;


static fn($x): int => $x;
fn($x = 42) => $x;
fn(&$x) => $x;
fn&($x) => $x;
fn($x, ...$rest) => $rest;

?>

Important Funcțiile săgeată folosesc legarea variabilelor după valoare. Acest lucru este aproximativ
echivalent cu efectuarea unei utilizări ($x) pentru fiecare variabilă $x utilizată în interiorul funcției
săgeată. O legare a valorii secundare înseamnă că nu este posibil să se modifice nicio valoare din
domeniul exterior. Funcțiile anonime pot fi utilizate în schimb pentru legăturile by-ref.

<?php

$x = 1;
$fn = fn() => $x++; // Has no effect
$fn();
var_export($x); // Outputs 1

?>

Important Sintaxa apelabilă de primă clasă este introdusă începând cu PHP 8.1.0, ca o modalitate de
a crea funcții anonime din apelabile. Acesta înlocuiește sintaxa apelabilă existentă folosind șiruri de
caractere și matrice. Avantajul acestei sintaxe este că este accesibilă analizei statice și utilizează
domeniul de aplicare în punctul în care este achiziționat apelabilul.
Important Sintaxa CallableExpr(...) este folosită pentru a crea un obiect Closure din apelabil.
CallableExpr acceptă orice expresie care poate fi apelată direct în gramatica PHP:
<?php

class Foo {
public function method() {}
public static function staticmethod() {}
public function __invoke() {}
}

$obj = new Foo();


$classStr = 'Foo';
$methodStr = 'method';
$staticmethodStr = 'staticmethod';

$f1 = strlen(...);
$f2 = $obj(...); // invokable object
$f3 = $obj->method(...);
$f4 = $obj->$methodStr(...);
$f5 = Foo::staticmethod(...);
$f6 = $classStr::$staticmethodStr(...);

// traditional callable using string, array


$f7 = 'strlen'(...);
$f8 = [$obj, 'method'](...);
$f9 = [Foo::class, 'staticmethod'](...);
?>

Important CallableExpr(...) are aceeași semantică ca Closure::fromCallable(). Adică, spre deosebire


de apelabil folosind șiruri și matrice, CallableExpr(...) respectă domeniul de aplicare în punctul în
care este creat:

<?php

class Foo {
public function getPrivateMethod() {
return [$this, 'privateMethod'];
}

private function privateMethod() {


echo __METHOD__, "\n";
}
}

$foo = new Foo;


$privateMethod = $foo->getPrivateMethod();
$privateMethod();
// Fatal error: Call to private method Foo::privateMethod() from global scope
// This is because call is performed outside from Foo and visibility will be checked from this point.

class Foo1 {
public function getPrivateMethod() {
/ / Uses the scope where the callable is acquired.
return $this->privateMethod(...); // identical to Closure::fromCallable([$this,
'privateMethod']);
}

private function privateMethod() {


echo __METHOD__, "\n";
}
}

$foo1 = new Foo1;


$privateMethod = $foo1->getPrivateMethod();
$privateMethod(); // Foo1::privateMethod
?>

Important Crearea de obiecte prin această sintaxă (de exemplu, new Foo(...)) nu este acceptată,
deoarece noua sintaxă Foo() nu este considerată un apel.
Important Sintaxa apelabilă de primă clasă nu poate fi combinată cu operatorul nullsafe. Ambele
următoarele au ca rezultat o eroare la timp de compilare:

Important Definițiile de bază ale clasei încep cu cuvântul cheie class, urmat de un nume de clasă,
urmat de o pereche de acolade care includ definițiile proprietăților și metodelor aparținând clasei.
Important Numele clasei poate fi orice etichetă validă, cu condiția să nu fie un cuvânt rezervat PHP.
Începând cu PHP 8.4.0, utilizarea unui singur caracter de subliniere _ ca nume de clasă este
depreciată. Un nume de clasă valid începe cu o literă sau liniuță de subliniere, urmată de orice
număr de litere, cifre sau liniuțe de subliniere. Ca expresie regulată, ar fi exprimată astfel: ^[a-zA-
Z_\x80-\xff][a-zA-Z0-9_\x80-\xff]*$.
Important O clasă poate conține propriile sale constante, variabile (numite „proprietăți”) și funcții
(numite „metode”).

<?php
class SimpleClass
{
// property declaration
public $var = 'a default value';

// method declaration
public function displayVar() {
echo $this->var;
}
}
?>

Important Pseudovariabila $this este disponibilă atunci când o metodă este apelată din contextul
unui obiect. $this este valoarea obiectului apelant.

Important Începând cu PHP 8.2.0, o clasă poate fi marcată cu modificatorul numai citire. Marcarea
unei clase ca doar citire va adăuga modificatorul numai pentru citire la fiecare proprietate declarată
și va împiedica crearea de proprietăți dinamice. Mai mult, este imposibil să adăugați suport pentru
ele utilizând atributul AllowDynamicProperties. Încercarea de a face acest lucru va declanșa o
eroare de compilare.
Important Deoarece nici proprietățile netipizate și nici proprietățile statice nu pot fi marcate cu
modificatorul readonly, nici clasele readonly nu le pot declara:
<?php
#[\AllowDynamicProperties]
readonly class Foo {
}

// Fatal error: Cannot apply #[AllowDynamicProperties] to readonly class Foo


?>

<?php
readonly class Foo
{
public $bar;
}

// Fatal error: Readonly property Foo::$bar must have type


?>

<?php
readonly class Foo
{
public static int $bar;
}

// Fatal error: Readonly class Foo cannot declare static properties


?>

Important O clasă numai în citire poate fi extinsă dacă și numai dacă clasa copil este și o clasă
numai în citire.

Important Pentru a crea o instanță a unei clase, trebuie folosit cuvântul cheie nou. Un obiect va fi
creat întotdeauna, cu excepția cazului în care obiectul are un constructor definit care aruncă o
excepție în caz de eroare. Clasele ar trebui definite înainte de instanțiere (și în unele cazuri aceasta
este o cerință).
Important Dacă o variabilă care conține un șir cu numele unei clase este folosită cu new, va fi creată
o nouă instanță a acelei clase. Dacă clasa se află într-un spațiu de nume, numele complet calificat
trebuie utilizat atunci când faceți acest lucru.

<?php
$instance = new SimpleClass();

// This can also be done with a variable:


$className = 'SimpleClass';
$instance = new $className(); // new SimpleClass()
?>

Important Începând cu PHP 8.0.0, este acceptată utilizarea new cu expresii arbitrare. Acest lucru
permite instanțierea mai complexă dacă expresia produce un șir. Expresiile trebuie împachetate între
paranteze.
<?php

class ClassA extends \stdClass {}


class ClassB extends \stdClass {}
class ClassC extends ClassB {}
class ClassD extends ClassA {}

function getSomeClass(): string


{
return 'ClassA';
}

var_dump(new (getSomeClass()));
var_dump(new ('Class' . 'B'));
var_dump(new ('Class' . 'C'));
var_dump(new (ClassD::class));
?>

Important În contextul clasei, este posibil să se creeze un nou obiect de către un nou sine și un nou
părinte.
Important Când atribuiți o instanță deja creată a unei clase unei variabile noi, noua variabilă va
accesa aceeași instanță ca și obiectul care a fost atribuit. Acest comportament este același atunci
când se transmite instanțe unei funcții. O copie a unui obiect deja creat poate fi realizată prin
clonarea acestuia.

<?php

$instance = new SimpleClass();

$assigned = $instance;
$reference =& $instance;

$instance->var = '$assigned will have this value';

$instance = null; // $instance and $reference become null

var_dump($instance);
var_dump($reference);
var_dump($assigned);
?>

Important Proprietățile și metodele clasei trăiesc în „spații de nume” separate, deci este posibil să
existe o proprietate și o metodă cu același nume. Referirea atât la o proprietate, cât și la o metodă
are aceeași notație și dacă o proprietate va fi accesată sau o metodă va fi apelată, depinde numai de
context, adică dacă utilizarea este un acces variabil sau un apel de funcție.
Important Dacă încercați să atribuiți unei proprietăți inexistente pe un obiect, PHP va crea automat
o proprietate corespunzătoare. Această proprietate creată dinamic va fi disponibilă numai pentru
această instanță de clasă. Proprietățile dinamice sunt depreciate începând cu PHP 8.2.0. Se
recomandă declararea proprietății în schimb. Pentru a gestiona nume de proprietăți arbitrare, clasa
ar trebui să implementeze metodele magice __get() și __set(). În ultimă instanță, clasa poate fi
marcată cu atributul #[\AllowDynamicProperties].
<?php
class Foo
{
public $bar = 'property';

public function bar() {


return 'method';
}
}

$obj = new Foo();


echo $obj->bar, PHP_EOL, $obj->bar(), PHP_EOL;

Important Aceasta înseamnă că apelarea unei funcții anonime care a fost atribuită unei proprietăți
nu este direct posibilă. În schimb, proprietatea trebuie să fie atribuită mai întâi unei variabile, de
exemplu. Este posibil să apelați direct o astfel de proprietate prin includerea ei între paranteze.

Important O clasă poate moșteni constantele, metodele și proprietățile unei alte clase folosind
cuvântul cheie extinde în declarația clasei. Nu este posibilă extinderea mai multor clase; o clasă
poate moșteni doar de la o clasă de bază.
Important Constantele, metodele și proprietățile moștenite pot fi suprascrise prin redeclararea lor cu
același nume definit în clasa părinte. Cu toate acestea, dacă clasa părinte a definit o metodă sau
constantă ca finală, acestea nu pot fi suprascrise. Este posibil să accesați metodele suprascrise sau
proprietățile statice, referindu-le cu parent::.

<?php
class ExtendClass extends SimpleClass
{
// Redefine the parent method
function displayVar()
{
echo "Extending class\n";
parent::displayVar();
}
}

$extended = new ExtendClass();


$extended->displayVar();
?>

Important Când suprascrieți o metodă, semnătura acesteia trebuie să fie compatibilă cu metoda
părinte. În caz contrar, este emisă o eroare fatală sau, înainte de PHP 8.0.0, este generată o eroare la
nivel E_WARNING. O semnătură este compatibilă dacă respectă regulile de variație, face ca un
parametru obligatoriu să fie opțional, adaugă doar noi parametri opționali și nu limitează, ci doar
relaxează vizibilitatea. Acesta este cunoscut sub numele de Liskov Substitution Principle, sau LSP
pe scurt. Constructorul și metodele private sunt scutite de aceste reguli de compatibilitate cu
semnături și, prin urmare, nu vor emite o eroare fatală în cazul unei nepotriviri de semnătură.
<?php

class Base
{
public function foo(int $a) {
echo "Valid\n";
}
}

class Extend1 extends Base


{
function foo(int $a = 5)
{
parent::foo($a);
}
}

class Extend2 extends Base


{
function foo(int $a, $b = 5)
{
parent::foo($a);
}
}

$extended1 = new Extend1();


$extended1->foo();
$extended2 = new Extend2();
$extended2->foo(1);

Important Începând cu PHP 8.0.0, proprietățile și metodele pot fi accesate și cu operatorul


„nullsafe”: ?->. Operatorul nullsafe funcționează la fel ca accesul la proprietate sau la metodă ca
mai sus, cu excepția faptului că, dacă obiectul care este dereferențiat este nul, atunci null va fi
returnat mai degrabă decât o excepție aruncată. Dacă dereferința face parte dintr-un lanț, restul
lanțului este omis.
Important Efectul este similar cu includerea fiecărui acces într-o verificare is_null() mai întâi, dar
mai compact.
Important În cadrul metodelor de clasă, proprietățile non-statice pot fi accesate folosind -> (Object
Operator): $this->property (unde proprietate este numele proprietății). Proprietățile statice sunt
accesate utilizând :: (Double Colon): self::$property. Consultați Cuvânt cheie static pentru mai
multe informații despre diferența dintre proprietățile statice și non-statice.

<?php
class User
{
public int $id;
public ?string $name;
public function __construct(int $id, ?string $name)
{
$this->id = $id;
$this->name = $name;
}
}

$user = new User(1234, null);

var_dump($user->id);
var_dump($user->name);

?>

<?php
class SimpleClass
{
public $var1 = 'hello ' . 'world';
public $var2 = <<<EOD
hello world
EOD;
public $var3 = 1+2;
// invalid property declarations:
public $var4 = self::myStaticMethod();
public $var5 = $myVar;

// valid property declarations:


public $var6 = myConstant;
public $var7 = [true, false];

public $var8 = <<<'EOD'


hello world
EOD;

// Without visibility modifier:


static $var9;
readonly int $var10;
}
?>

Important Cârligele de proprietate, cunoscute și ca „accesori de proprietate” în alte limbi, sunt o


modalitate de a intercepta și de a anula comportamentul de citire și scriere al unei proprietăți.
Această funcționalitate are două scopuri:
• Permite ca proprietățile să fie utilizate direct, fără metode get- și set-, lăsând în același timp
opțiunea deschisă pentru a adăuga un comportament suplimentar în viitor. Acest lucru face
ca majoritatea metodelor de obținere/setare boilerplate să fie inutile, chiar și fără a utiliza
cârlige.
• Permite proprietăți care descriu un obiect fără a fi nevoie să stocheze o valoare direct.
Important Există două cârlige disponibile pe proprietăți non-statice: get și set. Acestea permit
suprascrierea comportamentului de citire și, respectiv, de scriere al unei proprietăți. Cârligele sunt
disponibile atât pentru proprietăți tipizate, cât și pentru proprietăți netipizate.
Important O proprietate poate fi „susținută” sau „virtuală”. O proprietate susținută este una care
stochează de fapt o valoare. Orice proprietate care nu are cârlige este susținută. O proprietate
virtuală este una care are cârlige și acele cârlige nu interacționează cu proprietatea în sine. În acest
caz, cârligele sunt efectiv aceleași cu metodele, iar obiectul nu folosește niciun spațiu pentru a stoca
o valoare pentru acea proprietate.
Important Cârligele de proprietate sunt incompatibile cu proprietățile numai pentru citire. Dacă este
nevoie să restricționați accesul la o operațiune de obținere sau setare în plus față de modificarea
comportamentului acesteia, utilizați vizibilitatea proprietăților asimetrice.

<?php
class Example
{
private bool $modified = false;

public string $foo = 'default value' {


get {
if ($this->modified) {
return $this->foo . ' (modified)';
}
return $this->foo;
}
set(string $value) {
$this->foo = strtolower($value);
$this->modified = true;
}
}
}

$example = new Example();


$example->foo = 'changed';
print $example->foo;
?>

Important Proprietatea $foo se termină cu {}, nu cu punct și virgulă. Asta indică prezența cârligelor.
Sunt definite atât un cârlig get cât și set, deși este permis să se definească doar unul sau altul.
Ambele cârlige au un corp, notat cu {}, care poate conține cod arbitrar.
Important Cârligul set permite suplimentar specificarea tipului și numelui unei valori primite,
folosind aceeași sintaxă ca metodă. Tipul trebuie să fie fie același cu tipul proprietății, fie
contravariant (mai larg) cu acesta. De exemplu, o proprietate de tip șir poate avea un set hook care
acceptă șir|Stringable, dar nu unul care acceptă doar matrice.
Important Cel puțin unul dintre cârlige face referire la $this->foo, proprietatea în sine. Asta
înseamnă că proprietatea va fi „susținută”. Când apelați $example->foo = 'schimbat', șirul furnizat
va fi mai întâi transformat în litere mici, apoi salvat în valoarea de bază. Când citiți din proprietate,
valoarea salvată anterior poate fi adăugată condiționat cu text suplimentar.
Important Există și o serie de variante de sintaxă scurtă pentru a gestiona cazurile obișnuite.
Important Dacă hook-ul get este o singură expresie, atunci {} poate fi omis și înlocuit cu o expresie
săgeată.
Important Dacă tipul de parametru al cârligului setat este același cu tipul de proprietate (care este
tipic), acesta poate fi omis. În acest caz, valoarea de setată primește automat numele $value.
<?php
class Example
{
private bool $modified = false;

public string $foo = 'default value' {


get => $this->foo . ($this->modified ? ' (modified)' : '');

set {
$this->foo = strtolower($value);
$this->modified = true;
}
}
}
?>

Important Dacă cârligul setează doar o versiune modificată a valorii transmise, atunci poate fi, de
asemenea, simplificată la o expresie săgeată. Valoarea la care evaluează expresia va fi setată pe
valoarea de suport.

<?php
class Example
{
public string $foo = 'default value' {
get => $this->foo . ($this->modified ? ' (modified)' : '');
set => strtolower($value);
}
}
?>

Important Proprietățile virtuale sunt proprietăți care nu au valoare de suport. O proprietate este
virtuală dacă nici hook-ul său get, nici set nu face referire la proprietatea însăși folosind sintaxa
exactă. Adică, o proprietate numită $foo al cărei cârlig conține $this->foo va fi susținută. Dar
următoarea nu este o proprietate susținută și va returna eroarea:

<?php
class Example
{
public string $foo {
get {
$temp = __PROPERTY__;
return $this->$temp; // Doesn't refer to $this->foo, so it doesn't count.
}
}
}
?>

Important Pentru proprietățile virtuale, dacă un cârlig este omis, atunci acea operație nu există și
încercarea de a o utiliza va produce o eroare. Proprietățile virtuale nu ocupă spațiu de memorie într-
un obiect. Proprietățile virtuale sunt potrivite pentru proprietăți „derivate”, cum ar fi cele care sunt o
combinație a altor două proprietăți.
<?php
readonly class Rectangle
{
// A virtual property.
public int $area {
get => $this->h * $this->w;
}

public function __construct(public int $h, public int $w) {}

$s = new Rectangle(4, 5);


print $s->area; // prints 20
$s->area = 30; // Error, as there is no set operation defined.
?>

Important Toate cârligele funcționează în domeniul obiectului modificat. Aceasta înseamnă că au


acces la toate metodele publice, private sau protejate ale obiectului, precum și la orice proprietăți
publice, private sau protejate, inclusiv proprietăți care pot avea propriile cârlige de proprietate.
Accesarea unei alte proprietăți din interiorul unui cârlig nu ocolește cârligele definite pe acea
proprietate. Cea mai notabilă implicație a acestui lucru este că cârligele non-triviale pot apela la o
metodă arbitrar complexă, dacă doresc.

<?php
class Person {
public string $phone {
set => $this->sanitizePhone($value);
}

private function sanitizePhone(string $value): string {


$value = ltrim($value, '+');
$value = ltrim($value, '1');

if (!preg_match('/\d\d\d\-\d\d\d\-\d\d\d\d/', $value)) {
throw new \InvalidArgumentException();
}
return $value;
}
}
?>

Important Deoarece prezența cârligelor interceptează procesul de citire și scriere pentru proprietăți,
acestea cauzează probleme la achiziționarea unei referințe la o proprietate sau cu modificări
indirecte, cum ar fi $this->arrayProp['key'] = 'value';. Asta pentru că orice încercare de modificare a
valorii prin referință ar ocoli un cârlig setat, dacă este definit unul.
Important În cazul rar în care este necesară obținerea unei referințe la o proprietate care are hook-
uri definite, get hook-ul poate fi prefixat cu & pentru a-l face să revină prin referință. Definirea
ambelor get și &get pe aceeași proprietate este o eroare de sintaxă.
Important Definirea ambelor cârlige &get și set pe o proprietate susținută nu este permisă. După
cum sa menționat mai sus, scrierea la valoarea returnată prin referință ar ocoli cârligul setat. Pe
proprietățile virtuale, nu există o valoare comună necesară împărțită între cele două cârlige, așa că
este permisă definirea ambelor.
Important Scrierea într-un index al unei proprietăți de matrice implică și o referință implicită. Din
acest motiv, scrierea într-o proprietate de matrice susținută cu cârlige definite este permisă dacă și
numai dacă definește doar un cârlig &get. Pe o proprietate virtuală, scrierea în matricea returnată fie
de la get, fie de la &get este legală, dar dacă acest lucru are vreun impact asupra obiectului depinde
de implementarea hook.
Important Suprascrierea întregii proprietăți a matricei este bine și se comportă la fel ca orice altă
proprietate. Numai lucrul cu elemente ale matricei necesită îngrijire specială.

Important O proprietate poate fi, de asemenea, declarată definitivă. O proprietate finală nu poate fi
redeclarată de către o clasă de copii în niciun fel, ceea ce împiedică modificarea cârligelor sau
lărgirea accesului acesteia.
Important Declararea hook-urilor definitive pe o proprietate care este declarată definitivă este
redundantă și va fi ignorată în tăcere. Acesta este același comportament ca și metodele finale.
Important O clasă copil poate defini sau redefini cârlige individuale pe o proprietate prin redefinirea
proprietății și doar cârligele pe care dorește să le depășească. O clasă copil poate adăuga, de
asemenea, cârlige la o proprietate care nu avea niciuna. Acest lucru este în esență același ca și cum
cârligele ar fi metode.

<?php
class User
{
public string $username {
final set => strtolower($value);
}
}

class Manager extends User


{
public string $username {
// This is allowed
get => strtoupper($this->username);

// But this is NOT allowed, because set is final in the parent.


set => strtoupper($value);
}
}
?>

Important Un hook dintr-o clasă copil poate accesa proprietatea clasei părinte folosind cuvântul
cheie parent::$prop, urmat de hook-ul dorit. De exemplu, parent::$propName::get(). Poate fi citit ca
„accesați prop definit în clasa părinte și apoi executați operația de obținere” (sau setați operația,
după caz).
Important Dacă nu este accesat în acest fel, cârligul clasei părinte este ignorat. Acest comportament
este în concordanță cu modul în care funcționează toate metodele. Aceasta oferă, de asemenea, o
modalitate de a accesa spațiul de stocare al clasei părinte, dacă există. Dacă nu există niciun cârlig
pe proprietatea părinte, va fi folosit comportamentul implicit get/set. Cârligele nu pot accesa niciun
alt cârlig, cu excepția propriului părinte pe proprietatea lor.
<?php
class Point
{
public int $x;
public int $y;
}

class PositivePoint extends Point


{
public int $x {
set {
if ($value < 0) {
throw new \InvalidArgumentException('Too small');
}
$this->x = $value;
}
}
}
?>

Important PHP are o serie de moduri diferite prin care un obiect poate fi serializat, fie pentru
consumul public, fie pentru scopuri de depanare. Comportamentul cârligelor variază în funcție de
cazul de utilizare. În unele cazuri, valoarea brută de suport a unei proprietăți va fi utilizată, ocolind
orice cârlige. În altele, proprietatea va fi citită sau scrisă „prin” cârlig, la fel ca orice altă acțiune
normală de citire/scriere.

var_dump(): Use raw value


serialize(): Use raw value
unserialize(): Use raw value
__serialize()/__unserialize(): Custom logic, uses get/set hook
Array casting: Use raw value
var_export(): Use get hook
json_encode(): Use get hook
JsonSerializable: Custom logic, uses get hook
get_object_vars(): Use get hook
get_mangled_object_vars(): Use raw value

Important Este posibil să se definească constante pe o clasă, rămânând aceleași și neschimbabile.


Vizibilitatea implicită a constantelor clasei este publică.
Important Constantele clasei pot fi redefinite de o clasă copil. Începând cu PHP 8.1.0, constantele
de clasă nu pot fi redefinite de o clasă copil dacă este definită ca finală.

Important Constanta specială ::class permite rezoluția complet calificată a numelor de clasă în
timpul compilării, aceasta este utilă pentru clasele cu spații de nume:

<?php
namespace foo {
class bar {
}
echo bar::class; // foo\bar
}
?>
<?php
class MyClass
{
const CONSTANT = 'constant value';

function showConstant() {
echo self::CONSTANT . "\n";
}
}

echo MyClass::CONSTANT . "\n";

$classname = "MyClass";
echo $classname::CONSTANT . "\n";

$class = new MyClass();


$class->showConstant();

echo $class::CONSTANT."\n";
?>

Important Funcția spl_autoload_register() înregistrează orice număr de încărcătoare automate,


permițând ca clasele și interfețele să fie încărcate automat dacă nu sunt definite în prezent. Prin
înregistrarea încărcătoarelor automate, PHP are o ultimă șansă de a încărca clasa sau interfața
înainte de a eșua cu o eroare.
Important Orice construcție asemănătoare clasei poate fi încărcată automat în același mod. Aceasta
include clase, interfețe, trăsături și enumerări.
Important Înainte de PHP 8.0.0, era posibil să se folosească __autoload() pentru a încărca automat
clasele și interfețele. Cu toate acestea, este o alternativă mai puțin flexibilă la
spl_autoload_register() și __autoload() este depreciată începând cu PHP 7.2.0 și eliminată începând
cu PHP 8.0.0.
Important spl_autoload_register() poate fi apelat de mai multe ori pentru a înregistra mai multe
încărcătoare automate. Totuși, aruncarea unei excepții de la o funcție de încărcare automată va
întrerupe acel proces și nu va permite rularea altor funcții de încărcare automată. Din acest motiv,
aruncarea de excepții de la o funcție de încărcare automată este puternic descurajată.
<?php
spl_autoload_register(function ($class_name) {
include $class_name . '.php';
});

$obj = new MyClass1();


$obj2 = new MyClass2();
?>
Important Composer generează un vendor/[Link] care este configurat pentru a încărca
automat pachetele care sunt gestionate de Composer. Prin includerea acestui fișier, acele pachete pot
fi utilizate fără nicio muncă suplimentară.
<?php
require __DIR__ . '/vendor/[Link]';
$uuid = new Ramsey\Uuid\Uuid::uuid7();
echo "Generated new UUID -> ", $uuid->toString(), "\n";
?>
Important Spre deosebire de alte metode, __construct() este scutit de regulile obișnuite de
compatibilitate cu semnăturile atunci când este extins.
Important Constructorii sunt metode obișnuite care sunt apelate în timpul instanțierii obiectului lor
corespunzător. Ca atare, ele pot defini un număr arbitrar de argumente, care pot fi necesare, pot avea
un tip și pot avea o valoare implicită. Argumentele constructorului sunt apelate prin plasarea
argumentelor în paranteze după numele clasei.

<?php
class Point {
protected int $x;
protected int $y;

public function __construct(int $x, int $y = 0) {


$this->x = $x;
$this->y = $y;
}
}

// Pass both parameters.


$p1 = new Point(4, 5);
// Pass only the required parameter. $y will take its default value of 0.
$p2 = new Point(4);
// With named parameters (as of PHP 8.0):
$p3 = new Point(y: 5, x: 4);
?>

Important Înainte de PHP 8.0.0, clasele din spațiul de nume global vor interpreta o metodă numită
la fel ca și clasa ca un constructor de stil vechi. Sintaxa respectivă este depreciată și va avea ca
rezultat o eroare E_DEPRECATED, dar totuși apelează acea funcție ca constructor. Dacă sunt
definite atât __construct() cât și o metodă cu același nume, __construct() va fi apelată.
Important În clasele cu spații de nume sau în orice clasă începând cu PHP 8.0.0, o metodă numită la
fel ca și clasa nu are niciodată vreo semnificație specială.
Important Utilizați întotdeauna __construct() în codul nou.

Important Când un argument de constructor include un modificator, PHP îl va interpreta atât ca o


proprietate de obiect, cât și ca un argument de constructor și va atribui valoarea argumentului
proprietății. Corpul constructorului poate fi apoi gol sau poate conține alte instrucțiuni. Orice
instrucțiuni suplimentare vor fi executate după ce valorile argumentului au fost atribuite
proprietăților corespunzătoare.
Important Nu toate argumentele trebuie promovate. Este posibil să amestecați și să potriviți
argumentele promovate și nepromovate, în orice ordine. Argumentele promovate nu au niciun
impact asupra apelării codului constructorului.
Important Utilizarea unui modificator de vizibilitate (public, protejat sau privat) este cea mai
probabilă modalitate de a aplica promovarea proprietății, dar orice alt modificator unic (cum ar fi
numai citire) va avea același efect.
Important Proprietățile obiectului pot să nu fie tastate apelabile din cauza ambiguității motorului
care ar introduce. Prin urmare, argumentele promovate nu pot fi introduse apelabile. Orice altă
declarație de tip este totuși permisă.
Important Deoarece proprietățile promovate sunt eliminate atât pentru o proprietate, cât și pentru un
parametru de funcție, se aplică toate și toate restricțiile de denumire atât pentru proprietăți, cât și
pentru parametri.
Important Atributele plasate pe un argument de constructor promovat vor fi replicate atât în
proprietate, cât și în argument. Valorile implicite ale unui argument de constructor promovat vor fi
replicate numai pentru argument și nu pentru proprietate.

<?php

// All allowed:
static $x = new Foo;

const C = new Foo;

function test($param = new Foo) {}

#[AnAttribute(new Foo)]
class Test {
public function __construct(
public $prop = new Foo,) {}
}

// All not allowed (compile-time error):


function test(
$a = new (CLASS_NAME_CONSTANT)(), // dynamic class name
$b = new class {}, // anonymous class
$c = new A(...[]), // argument unpacking
$d = new B($abc), // unsupported constant expression
) {}
?>

Important PHP acceptă doar un singur constructor per clasă. În unele cazuri, totuși, poate fi de dorit
să se permită ca un obiect să fie construit în moduri diferite cu intrări diferite. Modul recomandat de
a face acest lucru este folosirea metodelor statice ca wrapper-uri de constructor.

<?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, true);
return new static($data['id'], $data['name']);
}
public static function fromXml(string $xml): static {
// Custom 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);

Important Constructorul poate fi privat sau protejat pentru a preveni apelarea externă. Dacă da, doar
o metodă statică va putea instanția clasa. Deoarece se află în aceeași definiție de clasă, au acces la
metode private, chiar dacă nu aparțin aceleiași instanțe de obiect. Constructorul privat este opțional
și poate avea sens sau nu, în funcție de cazul de utilizare.
Important Cele trei metode statice publice demonstrează apoi moduri diferite de instanțiere a
obiectului.
• fromBasicData() ia exact parametrii necesari, apoi creează obiectul apelând constructorul și
returnând rezultatul.
• fromJson() acceptă un șir JSON și efectuează o preprocesare pe el însuși pentru a-l converti
în formatul dorit de constructor. Apoi returnează noul obiect.
• fromXml() acceptă un șir XML, îl preprocesează și apoi creează un obiect gol.
Constructorul este încă apelat, dar deoarece toți parametrii sunt opționali, metoda îi omite.
Apoi atribuie valori proprietăților obiectului direct înainte de a returna rezultatul.

Important În toate cele trei cazuri, cuvântul cheie static este tradus în numele clasei în care se află
codul. În acest caz, Product.

Important PHP posedă un concept de destructor similar cu cel al altor limbaje orientate pe obiecte,
cum ar fi C++. Metoda destructorului va fi apelată de îndată ce nu există alte referințe la un anumit
obiect sau în orice ordine în timpul secvenței de oprire.
Important La fel ca constructorii, destructorii părinte nu vor fi apelați implicit de motor. Pentru a
rula un destructor părinte, ar trebui să apelați explicit parent::__destruct() în corpul destructorului.
De asemenea, ca și constructorii, o clasă copil poate moșteni destructorul părintelui dacă nu
implementează unul singur.
Important Destructorul va fi apelat chiar dacă execuția scriptului este oprită folosind exit().
Apelarea exit() într-un destructor va împiedica executarea rutinelor de închidere rămase.
Important Dacă un destructor creează noi referințe la obiectul său, nu va fi apelat a doua oară când
numărul de referințe ajunge din nou la zero sau în timpul secvenței de oprire.
Important Începând cu PHP 8.4.0, când colectarea ciclului are loc în timpul execuției unei Fibre,
destructorii de obiecte programate pentru colectare sunt executați într-o Fibră separată, numită
gc_destructor_fiber. Dacă această Fibră este suspendată, va fi creată una nouă pentru a executa orice
destructori rămași. Gc_destructor_fiber anterior nu va mai fi referit de către colectorul de gunoi și
poate fi colectat dacă nu este referit în altă parte. Obiectele al căror destructor este suspendat nu vor
fi colectate până la întoarcerea destructorului sau până la colectarea Fibrei în sine.
<?php

class MyDestructableClass
{
function __construct() {
print "In constructor\n";
}

function __destruct() {
print "Destroying " . __CLASS__ . "\n";
}
}

$obj = new MyDestructableClass();

Important Vizibilitatea unei proprietăți, a unei metode sau (începând cu PHP 7.1.0) a unei constante
poate fi definită prin prefixarea declarației cu cuvintele cheie public, protected sau private. Membrii
clasei declarați publici pot fi accesați oriunde. Membrii declarați protejați pot fi accesați numai în
cadrul clasei în sine și prin clasele moștenitoare și părinte. Membrii declarați ca privați pot fi
accesați numai de clasa care definește membrul.
Important Proprietățile de clasă pot fi definite ca publice, private sau protejate. Proprietățile
declarate fără niciun cuvânt cheie de vizibilitate explicit sunt definite ca publice.

<?php
/**
* Define MyClass
*/
class MyClass
{
public $public = 'Public';
protected $protected = 'Protected';
private $private = 'Private';

function printHello() {
echo $this->public;
echo $this->protected;
echo $this->private;
}
}

$obj = new MyClass();


echo $obj->public; // Works
echo $obj->protected; // Fatal Error
echo $obj->private; // Fatal Error
$obj->printHello(); // Shows Public, Protected and Private

Important Începând cu PHP 8.4, proprietățile pot avea și vizibilitatea setată asimetric, cu un
domeniu diferit de citire (get) și scriere (set). Mai exact, vizibilitatea setată poate fi specificată
separat, cu condiția să nu fie mai permisivă decât vizibilitatea implicită.
<?php
class Book
{
public function __construct(
public private(set) string $title,
public protected(set) string $author,
protected private(set) int $pubYear,
) {}
}

class SpecialBook extends Book


{
public function update(string $author, int $year): void
{
$this->author = $author; // OK
$this->pubYear = $year; // Fatal Error
}
}

$b = new Book('How to PHP', 'Peter H. Peterson', 2024);

echo $b->title; // Works


echo $b->author; // Works
echo $b->pubYear; // Fatal Error

$b->title = 'How not to PHP'; // Fatal Error


$b->author = 'Pedro H. Peterson'; // Fatal Error
$b->pubYear = 2023; // Fatal Error
?>

Important Există câteva avertismente cu privire la vizibilitatea asimetrică:


• Numai proprietățile tastate pot avea o vizibilitate separată.
• Vizibilitatea setată trebuie să fie aceeași cu get sau mai restrictivă. Adică public
protected(set) și protected protected(set) sunt permise, dar public protected(set) va cauza o
eroare de sintaxă.
• Dacă o proprietate este publică, atunci vizibilitatea principală poate fi omisă. Adică public
private(set) și private(set) vor avea același rezultat.
• O proprietate cu vizibilitate privată (setată) este automat definitivă și nu poate fi redeclarată
într-o clasă de copii.
• Obținerea unei referințe la o proprietate urmează vizibilitatea setată, nu obținerea. Acest
lucru se datorează faptului că o referință poate fi utilizată pentru a modifica valoarea
proprietății.
• În mod similar, încercarea de a scrie într-o proprietate de matrice implică atât o operație de
obținere, cât și o operație de setare în interior și, prin urmare, va urma vizibilitatea setată,
deoarece aceasta este întotdeauna mai restrictivă.
Important Spațiile nu sunt permise în declarația de vizibilitate setată. private(set) este corectă.
private( set ) nu este corectă și va duce la o eroare de analiză.
Important Când o clasă extinde alta, clasa copil poate redefini orice proprietate care nu este
definitivă. Atunci când face acest lucru, poate lărgi fie vizibilitatea principală, fie vizibilitatea setată,
cu condiția ca noua vizibilitate să fie aceeași sau mai largă decât clasa părinte. Cu toate acestea,
rețineți că, dacă o proprietate privată este înlocuită, aceasta nu modifică de fapt proprietatea
părintelui, ci creează o nouă proprietate cu un nume intern diferit.
<?php
class Book
{
protected string $title;
public protected(set) string $author;
protected private(set) int $pubYear;
}

class SpecialBook extends Book


{
public protected(set) $title; // OK, as reading is wider and writing the same.
public string $author; // OK, as reading is the same and writing is wider.
public protected(set) int $pubYear; // Fatal Error. private(set) properties are final.
}
?>

Important Metodele de clasă pot fi definite ca publice, private sau protejate. Metodele declarate fără
niciun cuvânt cheie explicit de vizibilitate sunt definite ca publice.

<?php
/**
* Define MyClass
*/
class MyClass
{
// Declare a public constructor
public function __construct() { }

// Declare a public method


public function MyPublic() { }

// Declare a protected method


protected function MyProtected() { }

// Declare a private method


private function MyPrivate() { }

// This is public
function Foo()
{
$this->MyPublic();
$this->MyProtected();
$this->MyPrivate();
}
}

$myclass = new MyClass;


$myclass->MyPublic(); // Works
$myclass->MyProtected(); // Fatal Error
$myclass->MyPrivate(); // Fatal Error
$myclass->Foo(); // Public, Protected and Private work
Important Începând cu PHP 7.1.0, constantele de clasă pot fi definite ca publice, private sau
protejate. Constanțele declarate fără niciun cuvânt cheie de vizibilitate explicit sunt definite ca
publice.

<?php
/**
* Define MyClass
*/
class MyClass
{
// Declare a public constant
public const MY_PUBLIC = 'public';

// Declare a protected constant


protected const MY_PROTECTED = 'protected';

// Declare a private constant


private const MY_PRIVATE = 'private';

public function foo()


{
echo self::MY_PUBLIC;
echo self::MY_PROTECTED;
echo self::MY_PRIVATE;
}
}

$myclass = new MyClass();


MyClass::MY_PUBLIC; // Works
MyClass::MY_PROTECTED; // Fatal Error
MyClass::MY_PRIVATE; // Fatal Error
$myclass->foo(); // Public, Protected and Private work

Important Moștenirea este un principiu de programare bine stabilit, iar PHP folosește acest
principiu în modelul său obiect. Acest principiu va afecta modul în care multe clase și obiecte se
raportează între ele.
Important De exemplu, la extinderea unei clase, subclasa moștenește toate metodele, proprietățile și
constantele publice și protejate din clasa părinte. Cu excepția cazului în care o clasă înlocuiește
aceste metode, acestea își vor păstra funcționalitatea inițială.
Important Acest lucru este util pentru definirea și abstractizarea funcționalității și permite
implementarea de funcționalități suplimentare în obiecte similare fără a fi nevoie de
reimplementarea tuturor funcționalităților partajate.
Important Metodele private ale unei clase părinte nu sunt accesibile unei clase secundare. Ca
rezultat, clasele copil pot reimplementa o metodă privată, fără a ține cont de regulile normale de
moștenire. Înainte de PHP 8.0.0, totuși, restricțiile finale și statice erau aplicate metodelor private.
Începând cu PHP 8.0.0, singura restricție de metodă privată care este impusă sunt constructorii
finali privați, deoarece aceasta este o modalitate obișnuită de a „dezactiva” constructorul atunci
când se utilizează metode statice din fabrică.
Important Vizibilitatea metodelor, proprietăților și constantelor poate fi relaxată, de ex. o metodă
protejată poate fi marcată ca publică, dar nu poate fi restricționată, de ex. marcarea unei proprietăți
publice ca fiind privată. O excepție sunt constructorii, a căror vizibilitate poate fi restricționată, de
ex. un constructor public poate fi marcat ca privat într-o clasă copil.
<?php

class Foo
{
public function printItem($string)
{
echo 'Foo: ' . $string . PHP_EOL;
}

public function printPHP()


{
echo 'PHP is great.' . PHP_EOL;
}
}

class Bar extends Foo


{
public function printItem($string)
{
echo 'Bar: ' . $string . PHP_EOL;
}
}

$foo = new Foo();


$bar = new Bar();
$foo->printItem('baz'); // Output: 'Foo: baz'
$foo->printPHP(); // Output: 'PHP is great'
$bar->printItem('baz'); // Output: 'Bar: baz'
$bar->printPHP(); // Output: 'PHP is great'

?>

Important Operatorul de rezoluție a domeniului de aplicare (numit și Paamayim Nekudotayim) sau,


în termeni mai simpli, două puncte duble, este un simbol care permite accesul la o proprietate
constantă, statică sau la o metodă statică a unei clase sau a unuia dintre părinții acesteia. Mai mult,
proprietățile sau metodele statice pot fi depășite prin legarea statică târzie.
Important Când faceți referire la aceste elemente din afara definiției clasei, utilizați numele clasei.
Important Este posibil să faceți referire la clasă folosind o variabilă. Valoarea variabilei nu poate fi
un cuvânt cheie (de exemplu, self, parent and static).

<?php
class MyClass {
const CONST_VALUE = 'A constant value';
}

$classname = 'MyClass';
echo $classname::CONST_VALUE;

echo MyClass::CONST_VALUE;
?>
Important Trei cuvinte cheie speciale self, parent și static sunt folosite pentru a accesa proprietăți
sau metode din interiorul definiției clasei.

<?php
class OtherClass extends MyClass
{
public static $my_static = 'static var';

public static function doubleColon() {


echo parent::CONST_VALUE . "\n";
echo self::$my_static . "\n";
}
}

$classname = 'OtherClass';
$classname::doubleColon();

OtherClass::doubleColon();
?>

Important Când o clasă extinsă suprascrie definiția părintelui a unei metode, PHP nu va apela
metoda părintelui. Depinde de clasa extinsă dacă este apelată sau nu metoda părintelui. Acest lucru
se aplică și definițiilor metodelor Constructorilor și Destructorilor, Supraîncărcării și Magic.

<?php
class MyClass
{
protected function myFunc() {
echo "MyClass::myFunc()\n";
}
}

class OtherClass extends MyClass


{
// Override parent's definition
public function myFunc()
{
// But still call the parent function
parent::myFunc();
echo "OtherClass::myFunc()\n";
}
}

$class = new OtherClass();


$class->myFunc();
?>

Important Declararea proprietăților sau metodelor clasei ca fiind statice le face accesibile fără a fi
nevoie de o instanțiere a clasei. Acestea pot fi, de asemenea, accesate static într-un obiect de clasă
instanțiat.
Important Deoarece metodele statice sunt apelabile fără o instanță a obiectului creat,
pseudovariabila $this nu este disponibilă în cadrul metodelor declarate ca statice.
<?php
class Foo {
public static function aStaticMethod() {
// ...
}
}

Foo::aStaticMethod();
$classname = 'Foo';
$classname::aStaticMethod();
?>

Important Proprietățile statice sunt accesate folosind operatorul de rezoluție scop (::) și nu pot fi
accesate prin operatorul obiect (->). Este posibil să faceți referire la clasă folosind o variabilă.
Valoarea variabilei nu poate fi un cuvânt cheie (de exemplu, sine, părinte și static).

<?php
class Foo
{
public static $my_static = 'foo';

public function staticValue() {


return self::$my_static;
}
}

class Bar extends Foo


{
public function fooStatic() {
return parent::$my_static;
}
}

print Foo::$my_static . "\n";

$foo = new Foo();


print $foo->staticValue() . "\n";
print $foo->my_static . "\n"; // Undefined "Property" my_static

print $foo::$my_static . "\n";


$classname = 'Foo';
print $classname::$my_static . "\n";

print Bar::$my_static . "\n";


$bar = new Bar();
print $bar->fooStatic() . "\n";
?>
Important PHP are clase, metode și proprietăți abstracte. Clasele definite ca abstracte nu pot fi
instanțiate și orice clasă care conține cel puțin o metodă sau o proprietate abstractă trebuie să fie, de
asemenea, abstractă. Metodele definite ca abstracte declară pur și simplu semnătura metodei și dacă
aceasta este publică sau protejată; nu pot defini implementarea. Proprietățile definite ca abstracte
pot declara o cerință pentru comportamentul get sau set și pot oferi o implementare pentru una, dar
nu pentru ambele operații.
Important Când se moștenește dintr-o clasă abstractă, toate metodele marcate abstract în declarația
de clasă a părintelui trebuie să fie definite de clasa copil și să urmeze regulile obișnuite de
moștenire și compatibilitate cu semnătura.
Important Începând cu PHP 8.4, o clasă abstractă poate declara o proprietate abstractă, fie publică,
fie protejată. O proprietate abstractă protejată poate fi satisfăcută de o proprietate care poate fi
citită/scrisă fie din domeniul protejat, fie din domeniul public.
Important O proprietate abstractă poate fi satisfăcută fie de o proprietate standard, fie de o
proprietate cu cârlige definite, corespunzătoare operației necesare.

<?php

abstract class AbstractClass


{
// Force extending class to define this method
abstract protected function getValue();
abstract protected function prefixValue($prefix);

// Common method
public function printOut()
{
print $this->getValue() . "\n";
}
}

class ConcreteClass1 extends AbstractClass


{
protected function getValue()
{
return "ConcreteClass1";
}

public function prefixValue($prefix)


{
return "{$prefix}ConcreteClass1";
}
}

class ConcreteClass2 extends AbstractClass


{
public function getValue()
{
return "ConcreteClass2";
}

public function prefixValue($prefix)


{
return "{$prefix}ConcreteClass2";
}
}

$class1 = new ConcreteClass1();


$class1->printOut();
echo $class1->prefixValue('FOO_'), "\n";

$class2 = new ConcreteClass2();


$class2->printOut();
echo $class2->prefixValue('FOO_'), "\n";

?>

Important Interfețele obiect vă permit să creați cod care specifică ce metode și proprietăți trebuie să
implementeze o clasă, fără a fi nevoie să definiți modul în care aceste metode sau proprietăți sunt
implementate. Interfețele partajează un spațiu de nume cu clase, trăsături și enumerări, astfel încât
nu pot folosi același nume.
Important Interfețele sunt definite în același mod ca o clasă, dar cu cuvântul cheie interfață
înlocuind cuvântul cheie class și fără ca vreuna dintre metode să aibă conținutul definit.
Toate metodele declarate într-o interfață trebuie să fie publice; aceasta este natura unei interfețe.
Important În practică, interfețele servesc două scopuri complementare:
• Pentru a permite dezvoltatorilor să creeze obiecte de clase diferite care pot fi folosite
interschimbabil, deoarece implementează aceeași interfață sau interfețe. Un exemplu comun
este serviciile de acces la baze de date multiple, mai multe gateway-uri de plată sau diferite
strategii de stocare în cache. Diferite implementări pot fi schimbate fără a necesita nicio
modificare a codului care le folosește.
• Pentru a permite unei funcții sau metode să accepte și să opereze pe un parametru care se
conformează unei interfețe, fără să-i pese de ce altceva poate face obiectul sau de cum este
implementat. Aceste interfețe sunt adesea numite ca Iterable, Cacheable, Renderable sau așa
mai departe pentru a descrie semnificația comportamentului.
Important Interfețele pot defini metode magice pentru a solicita clase de implementare pentru a
implementa acele metode.
Important Pentru a implementa o interfață, se folosește operatorul de instrumente. Toate metodele
din interfață trebuie implementate în cadrul unei clase; nerespectarea acestui lucru va duce la o
eroare fatală. Clasele pot implementa mai mult de o interfață dacă se dorește, separând fiecare
interfață cu o virgulă.
Important O clasă care implementează o interfață poate folosi un nume diferit pentru parametrii săi
decât interfața. Cu toate acestea, începând cu PHP 8.0, limbajul acceptă argumente numite, ceea ce
înseamnă că apelanții se pot baza pe numele parametrului din interfață. Din acest motiv, se
recomandă insistent ca dezvoltatorii să folosească aceleași nume de parametri ca și interfața
implementată.
Important Interfețele pot fi extinse ca și clase folosind operatorul extins.
Important Clasa care implementează interfața trebuie să declare toate metodele din interfață cu o
semnătură compatibilă. O clasă poate implementa mai multe interfețe care declară o metodă cu
același nume. În acest caz, implementarea trebuie să respecte regulile de compatibilitate cu
semnături pentru toate interfețele. Deci covarianța și contravarianța pot fi aplicate.
Important Este posibil ca interfețele să aibă constante. Constantele de interfață funcționează exact
ca constantele de clasă. Înainte de PHP 8.1.0, acestea nu pot fi suprascrise de o clasă/interfață care
le moștenește. Proprietăți
Important Începând cu PHP 8.4.0, interfețele pot declara și proprietăți. Dacă o fac, declarația trebuie
să specifice dacă proprietatea trebuie să fie lizibilă, scrisă sau ambele. Declarația de interfață se
aplică numai accesului public de citire și scriere.
Important O clasă poate satisface o proprietate de interfață în mai multe moduri. Poate defini o
proprietate publică. Poate defini o proprietate virtuală publică care implementează doar cârligul
corespunzător. Sau o proprietate de citire poate fi satisfăcută de o proprietate numai de citire. Cu
toate acestea, o proprietate de interfață care poate fi setată nu poate fi doar în citire.

<?php
interface A
{
public function foo();
}

interface B
{
public function bar();
}

interface C extends A, B
{
public function baz();
}

class D implements C
{
public function foo(){}

public function bar(){}

public function baz(){}


}
?>

Important PHP implementează o modalitate de reutilizare a codului numită Trăsături.


Important Trăsăturile sunt un mecanism pentru reutilizarea codului în limbaje cu moștenire unică,
cum ar fi PHP. O trăsătură are scopul de a reduce unele limitări ale moștenirii unice, permițând unui
dezvoltator să refolosească în mod liber seturi de metode în mai multe clase independente care
trăiesc în ierarhii de clasă diferite. Semantica combinației de trăsături și clase este definită într-un
mod care reduce complexitatea și evită problemele tipice asociate cu moștenirea multiplă și Mixins.
Important O trăsătură este similară cu o clasă, dar este destinată doar grupării funcționalității într-un
mod precis și consistent. Nu este posibil să instanțiați o trăsătură pe cont propriu. Este un plus față
de moștenirea tradițională și permite compunerea orizontală a comportamentului; adică aplicarea
membrilor clasei fără a necesita moștenire.
<?php

trait TraitA {
public function sayHello() {
echo 'Hello';
}
}

trait TraitB {
public function sayWorld() {
echo 'World';
}
}

class MyHelloWorld
{
use TraitA, TraitB; // A class can use multiple traits

public function sayHelloWorld() {


$this->sayHello();
echo ' ';
$this->sayWorld();
echo "!\n";
}
}

$myHelloWorld = new MyHelloWorld();


$myHelloWorld->sayHelloWorld();

?>

Important Un membru moștenit dintr-o clasă de bază este suprascris de un membru inserat de o
trăsătură. Ordinea de precedență este aceea că membrii din clasa curentă suprascriu metodele Trait,
care la rândul lor suprascriu metodele moștenite.
Important O metodă moștenită dintr-o clasă de bază este suprascrisă de metoda inserată în
MyHelloWorld din trăsătura SayWorld. Comportamentul este același pentru metodele definite în
clasa MyHelloWorld. Ordinea de prioritate este aceea că metodele din clasa curentă suprascriu
metodele Trait, care la rândul lor suprascriu metodele din clasa de bază.

<?php
class Base {
public function sayHello() {
echo 'Hello ';
}
}

trait SayWorld {
public function sayHello() {
parent::sayHello();
echo 'World!';
}
}
class MyHelloWorld extends Base {
use SayWorld;
}

$o = new MyHelloWorld();
$o->sayHello();
?>

Important Mai multe trăsături pot fi inserate într-o clasă, listându-le în instrucțiunea de utilizare,
separate prin virgule.

<?php
trait Hello {
public function sayHello() {
echo 'Hello ';
}
}

trait World {
public function sayWorld() {
echo 'World';
}
}

class MyHelloWorld {
use Hello, World;
public function sayExclamationMark() {
echo '!';
}
}

$o = new MyHelloWorld();
$o->sayHello();
$o->sayWorld();
$o->sayExclamationMark();
?>

Important Dacă două Trăsături introduc o metodă cu același nume, se produce o eroare fatală, dacă
conflictul nu este rezolvat în mod explicit.
Important Pentru a rezolva conflictele de denumire între trăsăturile utilizate în aceeași clasă,
operatorul insteadof trebuie să fie folosit pentru a alege exact una dintre metodele conflictuale.
Important În acest exemplu, Talker folosește trăsăturile A și B. Deoarece A și B au metode
conflictuale, definește utilizarea variantei smallTalk din trăsătura B și varianta bigTalk din trăsătura
A.
<?php
trait A {
public function smallTalk() {
echo 'a';
}
public function bigTalk() {
echo 'A';
}
}

trait B {
public function smallTalk() {
echo 'b';
}
public function bigTalk() {
echo 'B';
}
}

class Talker {
use A, B {
B::smallTalk insteadof A;
A::bigTalk insteadof B;
}
}

class Aliased_Talker {
use A, B {
B::smallTalk insteadof A;
A::bigTalk insteadof B;
B::bigTalk as talk;
}
}
?>

Important Așa cum clasele pot folosi trăsături, la fel pot face și alte trăsături. Folosind una sau mai
multe trăsături într-o definiție de trăsătură, aceasta poate fi compusă parțial sau în întregime din
membrii definiți în acele alte trăsături.

<?php
trait Hello {
public function sayHello() {
echo 'Hello ';
}
}

trait World {
public function sayWorld() {
echo 'World!';
}
}
trait HelloWorld {
use Hello, World;
}

class MyHelloWorld {
use HelloWorld;
}

$o = new MyHelloWorld();
$o->sayHello();
$o->sayWorld();
?>

Important Trăsăturile sprijină utilizarea metodelor abstracte pentru a impune cerințe clasei
expozante. Sunt acceptate metode publice, protejate și private. Înainte de PHP 8.0.0, erau acceptate
numai metode abstracte publice și protejate.

<?php
trait Hello {
public function sayHelloWorld() {
echo 'Hello'.$this->getWorld();
}
abstract public function getWorld();
}

class MyHelloWorld {
private $world;
use Hello;
public function getWorld() {
return $this->world;
}
public function setWorld($val) {
$this->world = $val;
}
}
?>

Important Trăsăturile pot defini variabile statice, metode statice și proprietăți statice.

<?php

trait Counter
{
public function inc()
{
static $c = 0;
$c = $c + 1;
echo "$c\n";
}
}

class C1
{
use Counter;
}

class C2
{
use Counter;
}

$o = new C1();
$o->inc();
$p = new C2();
$p->inc();

?>

Important Trăsăturile pot defini, de asemenea, proprietăți.

<?php

trait PropertiesTrait
{
public $x = 1;
}

class PropertiesExample
{
use PropertiesTrait;
}

$example = new PropertiesExample();


$example->x;

?>

Important Dacă o trăsătură definește o proprietate, atunci o clasă nu poate defini o proprietate cu
același nume decât dacă aceasta este compatibilă (aceeași vizibilitate și tip, modificator numai
pentru citire și valoare inițială), în caz contrar, este emisă o eroare fatală.
<?php
trait PropertiesTrait {
public $same = true;
public $different1 = false;
public bool $different2;
public bool $different3;
}
class PropertiesExample {
use PropertiesTrait;
public $same = true;
public $different1 = true; // Fatal error
public string $different2; // Fatal error
readonly protected bool $different3; // Fatal error
}
?>
Important Începând cu PHP 8.2.0, trăsăturile pot defini și constante.

<?php
trait ConstantsTrait {
public const FLAG_MUTABLE = 1;
final public const FLAG_IMMUTABLE = 5;
}

class ConstantsExample {
use ConstantsTrait;
}

$example = new ConstantsExample;


echo $example::FLAG_MUTABLE;
?>

Important Dacă o trăsătură definește o constantă, atunci o clasă nu poate defini o constantă cu
același nume decât dacă este compatibilă (aceeași vizibilitate, valoare inițială și finalitate), în caz
contrar este emisă o eroare fatală.

<?php
trait ConstantsTrait {
public const FLAG_MUTABLE = 1;
final public const FLAG_IMMUTABLE = 5;
}

class ConstantsExample {
use ConstantsTrait;
public const FLAG_IMMUTABLE = 5; // Fatal error
}
?>

Important Începând cu PHP 8.3.0, modificatorul final poate fi aplicat folosind operatorul as pentru
metodele importate din trăsături. Acest lucru poate fi folosit pentru a preveni ca clasele copil să
suprascrie metodei. Cu toate acestea, clasa care folosește trăsătura poate încă suprascrie metoda.
<?php
trait CommonTrait
{
public function method()
{
echo 'Hello';
}
}
class FinalExampleA
{
use CommonTrait {
CommonTrait::method as final; // The 'final' prevents child classes from overriding
the method
}
}
class FinalExampleB extends FinalExampleA
{public function method() {}}
?>
Important Clasele anonime sunt utile atunci când trebuie create obiecte simple, unice.

<?php

// Using an explicit class


class Logger
{
public function log($msg)
{
echo $msg;
}
}

$util->setLogger(new Logger());

// Using an anonymous class


$util->setLogger(new class {
public function log($msg)
{
echo $msg;
}
});

Important Ei pot transmite argumente către constructorii lor, pot extinde alte clase, pot implementa
interfețe și pot folosi trăsături la fel ca o clasă normală:

<?php

class SomeClass {}
interface SomeInterface {}
trait SomeTrait {}

var_dump(new class(10) extends SomeClass implements SomeInterface {


private $num;

public function __construct($num)


{
$this->num = $num;
}

use SomeTrait;
});

Important Imbricarea unei clase anonime într-o altă clasă nu îi oferă acces la nicio metodă sau
proprietăți private sau protejate ale acelei clase exterioare. Pentru a utiliza proprietățile sau
metodele protejate ale clasei exterioare, clasa anonimă poate extinde clasa exterioară. Pentru a
utiliza proprietățile private ale clasei exterioare în clasa anonimă, acestea trebuie să fie trecute prin
constructorul său:

<?php

class Outer
{
private $prop = 1;
protected $prop2 = 2;

protected function func1()


{
return 3;
}

public function func2()


{
return new class($this->prop) extends Outer {
private $prop3;

public function __construct($prop)


{
$this->prop3 = $prop;
}

public function func3()


{
return $this->prop2 + $this->prop3 + $this->func1();
}
};
}
}

echo (new Outer)->func2()->func3();

Important Începând cu PHP 8.3.0, modificatorul numai citire poate fi aplicat claselor anonime.

<?php

// Using an anonymous class


$util->setLogger(new readonly class('[DEBUG]') {
public function __construct(private string $prefix){}

public function log($msg)


{
echo $this->prefix . ' ' . $msg;
}
});
Important Supraîncărcarea în PHP oferă mijloace pentru a „crea” în mod dinamic proprietăți și
metode. Aceste entități dinamice sunt procesate prin metode magice pe care le pot stabili într-o
clasă pentru diferite tipuri de acțiuni.
Important Metodele de supraîncărcare sunt invocate atunci când interacționează cu proprietăți sau
metode care nu au fost declarate sau nu sunt vizibile în domeniul curent. Restul acestei secțiuni va
folosi termenii „proprietăți inaccesibile” și „metode inaccesibile” pentru a se referi la această
combinație de declarare și vizibilitate.
Important Toate metodele de supraîncărcare trebuie definite ca publice.

public __set(string $name, mixed $value): void


public __get(string $name): mixed
public __isset(string $name): bool
public __unset(string $name): void

__set() este rulat atunci când scrieți date pe proprietăți inaccesibile (protejate sau private) sau
inexistente.
__get() este utilizat pentru citirea datelor din proprietăți inaccesibile (protejate sau private) sau
inexistente.
__isset() este declanșat prin apelarea isset() sau empty() pe proprietăți inaccesibile (protejate sau
private) sau inexistente.
__unset() este invocat atunci când unset() este folosit pe proprietăți inaccesibile (protejate sau
private) sau inexistente.

Important Argumentul $name este numele proprietății cu care se interacționează. Argumentul


$value al metodei __set() specifică valoarea la care ar trebui să fie setată proprietatea $named.
Important Supraîncărcarea proprietăților funcționează numai în contextul obiectului. Aceste metode
magice nu vor fi declanșate în context static. Prin urmare, aceste metode nu trebuie declarate statice.
Este emis un avertisment dacă una dintre metodele de supraîncărcare magică este declarată statică.

<?php
class PropertyTest
{
/** Location for overloaded data. */
private $data = array();

/** Overloading not used on declared properties. */


public $declared = 1;

/** Overloading only used on this when accessed outside the class. */
private $hidden = 2;

public function __set($name, $value)


{
echo "Setting '$name' to '$value'\n";
$this->data[$name] = $value;
}

public function __get($name)


{
echo "Getting '$name'\n";
if (array_key_exists($name, $this->data)) {
return $this->data[$name];
}

$trace = debug_backtrace();
trigger_error(
'Undefined property via __get(): ' . $name .
' in ' . $trace[0]['file'] .
' on line ' . $trace[0]['line'],
E_USER_NOTICE);
return null;
}

public function __isset($name)


{
echo "Is '$name' set?\n";
return isset($this->data[$name]);
}

public function __unset($name)


{
echo "Unsetting '$name'\n";
unset($this->data[$name]);
}

/** Not a magic method, just here for example. */


public function getHidden()
{
return $this->hidden;
}
}

echo "<pre>\n";

$obj = new PropertyTest;

$obj->a = 1;
echo $obj->a . "\n\n";

var_dump(isset($obj->a));
unset($obj->a);
var_dump(isset($obj->a));
echo "\n";

echo $obj->declared . "\n\n";

echo "Let's experiment with the private property named 'hidden':\n";


echo "Privates are visible inside the class, so __get() not used...\n";
echo $obj->getHidden() . "\n";
echo "Privates not visible outside of class, so __get() is used...\n";
echo $obj->hidden . "\n";
?>
public __call(șir $nume, matrice $argumente): mixt
public static __callStatic(șir $nume, matrice $argumente): mixt
__call() este declanșat atunci când se invocă metode inaccesibile într-un context de obiect.
__callStatic() este declanșat atunci când se invocă metode inaccesibile într-un context static.
Argumentul $name este numele metodei apelate. Argumentul $arguments este o matrice enumerată
care conține parametrii trecuți la metoda $name'ed.

<?php
class MethodTest
{
public function __call($name, $arguments)
{
// Note: value of $name is case sensitive.
echo "Calling object method '$name' ". implode(', ', $arguments). "\n";
}

public static function __callStatic($name, $arguments)


{
// Note: value of $name is case sensitive.
echo "Calling static method '$name' ". implode(', ', $arguments). "\n";
}
}

$obj = new MethodTest;


$obj->runTest('in object context');

MethodTest::runTest('in static context');


?>

Important PHP oferă o modalitate prin care obiectele să fie definite, astfel încât să fie posibilă
iterarea printr-o listă de elemente, cu, de exemplu, o instrucțiune foreach. În mod implicit, toate
proprietățile vizibile vor fi utilizate pentru iterație.

<?php
class MyClass
{
public $var1 = 'value 1';
public $var2 = 'value 2';
public $var3 = 'value 3';

protected $protected = 'protected var';


private $private = 'private var';

function iterateVisible() {
echo "MyClass::iterateVisible:\n";
foreach ($this as $key => $value) {
print "$key => $value\n";
}
}
}

$class = new MyClass();


foreach($class as $key => $value) {
print "$key => $value\n";
}
echo "\n";
$class->iterateVisible();
?>

Important Magic methods are special methods which override PHP's default's action when certain
actions are performed on an object.
Important Următoarele nume de metode sunt considerate magice: __construct(), __destruct(),
__call(), __callStatic(), __get(), __set(), __isset(), __unset(), __sleep(), __wakeup(), __serialize( ),
__unserialize(), __toString(), __invoke(), __set_state(), __clone() și __debugInfo().

public __sleep(): array


public __wakeup(): void

Important serialize() verifică dacă clasa are o funcție cu numele magic __sleep(). Dacă da, acea
funcție este executată înainte de orice serializare. Poate curăța obiectul și ar trebui să returneze o
matrice cu numele tuturor variabilelor acelui obiect care ar trebui serializate. Dacă metoda nu
returnează nimic, atunci null este serializat și E_NOTICE este emis.
Important Utilizarea intenționată a __sleep() este să comite date în așteptare sau să efectueze sarcini
de curățare similare. De asemenea, funcția este utilă dacă un obiect foarte mare nu trebuie să fie
salvat complet.
Important În schimb, unserialize() verifică prezența unei funcții cu numele magic __wakeup(). Dacă
este prezentă, această funcție poate reconstrui orice resurse pe care le poate avea obiectul.
Important Utilizarea intenționată a __wakeup() este de a restabili orice conexiuni de bază de date
care s-ar fi putut pierde în timpul serializării și de a efectua alte sarcini de reinițializare.

<?php
class Connection
{
protected $link;
private $dsn, $username, $password;

public function __construct($dsn, $username, $password)


{
$this->dsn = $dsn;
$this->username = $username;
$this->password = $password;
$this->connect();
}

private function connect()


{
$this->link = new PDO($this->dsn, $this->username, $this->password);
}

public function __sleep()


{
return array('dsn', 'username', 'password');
}
public function __wakeup()
{
$this->connect();
}
}?>

public __serialize(): array


public __unserialize(array $data): void

Important serialize() verifică dacă clasa are o funcție cu numele magic __serialize(). Dacă da, acea
funcție este executată înainte de orice serializare. Trebuie să construiască și să returneze o matrice
asociativă de perechi cheie/valoare care reprezintă forma serializată a obiectului. Dacă nu se
returnează nicio matrice, va fi aruncată o TypeError.
Important Utilizarea intenționată a lui __serialize() este de a defini o reprezentare arbitrară
prietenoasă cu serializarea a obiectului. Elementele matricei pot corespunde proprietăților
obiectului, dar acest lucru nu este necesar.
Important În schimb, unserialize() verifică prezența unei funcții cu numele magic __unserialize().
Dacă este prezentă, acestei funcții i se va trece matricea restaurată care a fost returnată de la
__serialize(). Apoi, poate restabili proprietățile obiectului din acea matrice, după caz.
Important Dacă atât __unserialize() cât și __wakeup() sunt definite în același obiect, va fi apelat
doar __unserialize(). __wakeup() va fi ignorat.

<?php
class Connection
{
protected $link;
private $dsn, $username, $password;

public function __construct($dsn, $username, $password)


{
$this->dsn = $dsn;
$this->username = $username;
$this->password = $password;
$this->connect();
}

private function connect()


{
$this->link = new PDO($this->dsn, $this->username, $this->password);
}

public function __serialize(): array


{
return [
'dsn' => $this->dsn,
'user' => $this->username,
'pass' => $this->password,
];
}
public function __unserialize(array $data): void
{
$this->dsn = $data['dsn'];
$this->username = $data['user'];
$this->password = $data['pass'];
$this->connect();
}
}?>
public __toString(): string
Metoda __toString() permite unei clase să decidă cum va reacționa atunci când este tratată ca un șir.
De exemplu, ce echo $obj; va imprima.

<?php
// Declare a simple class
class TestClass
{
public $foo;

public function __construct($foo)


{
$this->foo = $foo;
}

public function __toString()


{
return $this->foo;
}
}

$class = new TestClass('Hello');


echo $class;
?>

__invoke( ...$values): mixed


Metoda __invoke() este apelată atunci când un script încearcă să apeleze un obiect ca funcție.

<?php
class CallableClass
{
public function __invoke($x)
{
var_dump($x);
}
}
$obj = new CallableClass;
$obj(5);
var_dump(is_callable($obj));
?>

static __set_state(array $properties): object


Această metodă statică este apelată pentru clasele exportate de var_export().
Singurul parametru al acestei metode este o matrice care conține proprietăți exportate sub forma
['proprietate' => valoare, ...].

<?php
class A
{
public $var1;
public $var2;

public static function __set_state($an_array)


{
$obj = new A;
$obj->var1 = $an_array['var1'];
$obj->var2 = $an_array['var2'];
return $obj;
}
}

$a = new A;
$a->var1 = 5;
$a->var2 = 'foo';

$b = var_export($a, true);
var_dump($b);
eval('$c = ' . $b . ';');
var_dump($c);
?>

__debugInfo(): array
Această metodă este apelată de var_dump() atunci când aruncați un obiect pentru a obține
proprietățile care ar trebui să fie afișate. Dacă metoda nu este definită pe un obiect, atunci toate
proprietățile publice, protejate și private vor fi afișate.

<?php
class C {
private $prop;

public function __construct($val) {


$this->prop = $val;
}

public function __debugInfo() {


return [
'propSquared' => $this->prop ** 2,
];
}
}

var_dump(new C(42));
?>
Important Cuvântul cheie final împiedică clasele copil să suprascrie o metodă, o proprietate sau o
constantă prin prefixarea definiției cu final. Dacă clasa în sine este definită finală, atunci nu poate fi
extinsă.

<?php
class BaseClass {
public function test() {
echo "BaseClass::test() called\n";
}

final public function moreTesting() {


echo "BaseClass::moreTesting() called\n";
}
}

class ChildClass extends BaseClass {


public function moreTesting() {
echo "ChildClass::moreTesting() called\n";
}
}
// Results in Fatal error: Cannot override final method BaseClass::moreTesting()
?>

Important O copie a obiectului este creată utilizând cuvântul cheie clone (care apelează metoda
__clone() a obiectului, dacă este posibil).
$copie_obiect = clona $obiect;

Important Când un obiect este clonat, PHP va efectua o copie superficială a tuturor proprietăților
obiectului. Orice proprietăți care sunt referințe la alte variabile vor rămâne referințe. __clone(): nul
Important Odată ce clonarea este completă, dacă este definită o metodă __clone(), atunci metoda
__clone() a obiectului nou creat va fi apelată, pentru a permite orice proprietăți necesare care
trebuie modificate.

<?php
class SubObject
{
static $instances = 0;
public $instance;

public function __construct() {


$this->instance = ++self::$instances;
}

public function __clone() {


$this->instance = ++self::$instances;
}
}

class MyCloneable
{
public $object1;
public $object2;

function __clone()
{
// Force a copy of this->object, otherwise
// it will point to same object.
$this->object1 = clone $this->object1;
}
}

$obj = new MyCloneable();

$obj->object1 = new SubObject();


$obj->object2 = new SubObject();

$obj2 = clone $obj;


print "Original Object:\n";
print_r($obj);

print "Cloned Object:\n";


print_r($obj2);

?>

Este posibil să accesați un membru al unui obiect proaspăt clonat într-o singură expresie:

<?php
$dateTime = new DateTime();
echo (clone $dateTime)->format('Y');
?>

Important Când se utilizează operatorul de comparare (==), variabilele obiect sunt comparate într-
un mod simplu, și anume: Două instanțe de obiect sunt egale dacă au aceleași atribute și valori
(valorile sunt comparate cu ==) și sunt instanțe ale aceleiași clase .
Important Când se utilizează operatorul de identitate (===), variabilele obiect sunt identice dacă și
numai dacă se referă la aceeași instanță a aceleiași clase.

<?php
function bool2str($bool)
{
if ($bool === false) {
return 'FALSE';
} else {
return 'TRUE';
}
}

function compareObjects(&$o1, &$o2)


{
echo 'o1 == o2 : ' . bool2str($o1 == $o2) . "\n";
echo 'o1 != o2 : ' . bool2str($o1 != $o2) . "\n";
echo 'o1 === o2 : ' . bool2str($o1 === $o2) . "\n";
echo 'o1 !== o2 : ' . bool2str($o1 !== $o2) . "\n";
}

class Flag
{
public $flag;

function __construct($flag = true) {


$this->flag = $flag;
}
}

class OtherFlag
{
public $flag;

function __construct($flag = true) {


$this->flag = $flag;
}
}

$o = new Flag();
$p = new Flag();
$q = $o;
$r = new OtherFlag();

echo "Two instances of the same class\n";


compareObjects($o, $p);

echo "\nTwo references to the same instance\n";


compareObjects($o, $q);

echo "\nInstances of two different classes\n";


compareObjects($o, $r);
?>

Important PHP implementează o caracteristică numită legături statice tardive care poate fi folosită
pentru a face referire la clasa apelată într-un context de moștenire statică.
Important Mai precis, legăturile statice tardive funcționează prin stocarea clasei numite în ultimul
„apel fără redirecționare”. În cazul apelurilor de metode statice, aceasta este clasa denumită în mod
explicit (de obicei cea din stânga operatorului ::); în cazul apelurilor de metode non-statice, aceasta
este clasa obiectului. Un „apel de redirecționare” este unul static care este introdus de self::,
parent::, static:: sau, dacă urcă în ierarhia clasei, forward_static_call(). Funcția get_called_class()
poate fi folosită pentru a prelua un șir cu numele clasei apelate și static:: introduce domeniul său de
aplicare.
Important Această caracteristică a fost numită „legături statice tardive” având în vedere o
perspectivă internă. „Legarea tardivă” provine din faptul că static:: nu va fi rezolvată folosind clasa
în care este definită metoda, ci mai degrabă va fi calculată folosind informațiile de rulare. A fost
numită și „legare statică”, deoarece poate fi folosită pentru (dar nu se limitează la) apeluri de
metode statice.
Important Referințele statice la clasa curentă, cum ar fi self:: sau __CLASS__, sunt rezolvate
folosind clasa căreia îi aparține funcția, așa cum a fost definită:
<?php
class A {
public static function who() {
echo __CLASS__;
}
public static function test() {
self::who();
}
}

class B extends A {
public static function who() {
echo __CLASS__;
}
}

B::test();
?>

Important Legăturile statice tardive încearcă să rezolve această limitare prin introducerea unui
cuvânt cheie care face referire la clasa care a fost inițial apelată în timpul execuției. Practic, un
cuvânt cheie care ar permite referirea B din test() în exemplul anterior. S-a decis să nu se introducă
un cuvânt cheie nou, ci mai degrabă să se folosească static care era deja rezervat.

<?php
class A {
public static function who() {
echo __CLASS__;
}
public static function test() {
static::who(); // Here comes Late Static Bindings
}
}

class B extends A {
public static function who() {
echo __CLASS__;
}
}

B::test();
?>

Important În contexte non-statice, clasa apelată va fi clasa instanței obiectului. Deoarece $this-> va
încerca să apeleze metode private din același domeniu, utilizarea static:: poate da rezultate diferite.
O altă diferență este că static:: se poate referi doar la proprietăți statice.

<?php
class A {
private function foo() {
echo "success!\n";
}
public function test() {
$this->foo();
static::foo();
}
}

class B extends A {
/* foo() will be copied to B, hence its scope will still be A and
* the call be successful */
}

class C extends A {
private function foo() {
/* original method is replaced; the scope of the new one is C */
}
}

$b = new B();
$b->test();
$c = new C();
$c->test(); //fails
?>

Important Unul dintre punctele cheie ale PHP OOP care este adesea menționat este că „obiectele
sunt transmise prin referințe în mod implicit”. Acest lucru nu este complet adevărat. Această
secțiune rectifică această gândire generală folosind câteva exemple.
Important O referință PHP este un alias, care permite a două variabile diferite să scrie la aceeași
valoare. În PHP, o variabilă obiect nu conține obiectul în sine ca valoare. Conține doar un
identificator de obiect care permite accesoriilor obiectului să găsească obiectul real. Când un obiect
este trimis prin argument, returnat sau atribuit unei alte variabile, diferitele variabile nu sunt alias-
uri: ele dețin o copie a identificatorului, care indică același obiect.

<?php
class A {public $foo = 1;}
$a = new A;
$b = $a; // $a and $b are copies of the same identifier
// ($a) = ($b) = <id>
$b->foo = 2;
echo $a->foo."\n";
$c = new A;
$d = &$c; // $c and $d are references
// ($c,$d) = <id>
$d->foo = 2;
echo $c->foo."\n";
$e = new A;
function foo($obj) {
// ($obj) = ($e) = <id>
$obj->foo = 2;
}
foo($e);
echo $e->foo."\n";
?>
Important serialize() returnează un șir care conține o reprezentare în flux de octeți a oricărei valori
care poate fi stocată în PHP. unserialize() poate folosi acest șir pentru a recrea valorile variabilelor
originale. Utilizarea serializei pentru a salva un obiect va salva toate variabilele dintr-un obiect.
Metodele dintr-un obiect nu vor fi salvate, ci doar numele clasei.
Important Pentru a putea deserializa() un obiect, trebuie definită clasa acelui obiect. Adică, dacă
aveți un obiect din clasa A și îl serializați, veți obține un șir care se referă la clasa A și conține toate
valorile variabilelor conținute în acesta. Dacă doriți să puteți deserializa acest lucru într-un alt fișier,
un obiect din clasa A, definiția clasei A trebuie să fie mai întâi prezentă în acel fișier. Acest lucru se
poate face, de exemplu, prin stocarea definiției de clasă a clasei A într-un fișier include și includerea
acestui fișier sau folosind funcția spl_autoload_register().
Important Se recomandă insistent ca, dacă o aplicație serializează obiecte, pentru a fi utilizate
ulterior în aplicație, aplicația să includă definiția clasei pentru acel obiect în întreaga aplicație. Dacă
nu faceți acest lucru, un obiect poate fi deserializat fără o definiție de clasă, ceea ce va avea ca
rezultat PHP să dea obiectului o clasă de __PHP_Incomplete_Class_Name, care nu are metode și ar
face obiectul inutil.
Important Deci, dacă în exemplul de mai sus $a a devenit parte a unei sesiuni prin adăugarea unei
noi chei la matricea superglobală $_SESSION, ar trebui să includeți fișierul [Link] pe toate paginile
dvs., nu numai [Link] și [Link].

Important Covarianța permite metodei unui copil să returneze un tip mai specific decât tipul de
returnare al metodei părintelui său. Contravarianța permite unui tip de parametru să fie mai puțin
specific într-o metodă copil decât cea a părintelui său.
Important O declarație de tip este considerată mai specifică în următorul caz:
• Un tip este eliminat dintr-un tip de uniune
• Un tip este adăugat unui tip de intersecție
• Un tip de clasă este schimbat într-un tip de clasă copil
• iterable este schimbat în array sau Traversable

abstract class Animal


{
protected string $name;
public function __construct(string $name) {
$this->name = $name;
}
abstract public function speak();
}

class Dog extends Animal


{
public function speak() {
echo $this->name . " barks";
}
}

class Cat extends Animal


{
public function speak(){
echo $this->name . " meows";
}
}
Important În mod implicit, proprietățile nu sunt nici covariante, nici contravariante, deci invariante.
Adică, este posibil ca tipul lor să nu se schimbe deloc într-o clasă de copii. Motivul este că
operațiunile „get” trebuie să fie covariante, iar operațiunile „set” trebuie să fie contravariante.
Singura modalitate prin care o proprietate poate satisface ambele cerințe este să fie invariantă.
Important Începând cu PHP 8.4.0, cu adăugarea de proprietăți abstracte (pe o interfață sau clasă
abstractă) și proprietăți virtuale, este posibil să se declare o proprietate care are doar o operație get
sau set. Ca rezultat, proprietățile abstracte sau proprietățile virtuale care au nevoie doar de o
operație „obținere” pot fi covariante. În mod similar, o proprietate abstractă sau o proprietate
virtuală care are necesară doar o operațiune „set” poate fi contravariantă.
Important Odată ce o proprietate are atât o operație de obținere, cât și o operație de setare, totuși, nu
mai este covariantă sau contravariantă pentru extinderea ulterioară. Adică acum este invariant.

<?php
class Animal {}
class Dog extends Animal {}
class Poodle extends Dog {}

interface PetOwner
{
// Only a get operation is required, so this may be covariant.
public Animal $pet { get; }
}

class DogOwner implements PetOwner


{
// This may be a more restrictive type since the "get" side
// still returns an Animal. However, as a native property
// children of this class may not change the type anymore.
public Dog $pet;
}

class PoodleOwner extends DogOwner


{
// This is NOT ALLOWED, because DogOwner::$pet has both
// get and set operations defined and required.
public Poodle $pet;
}
?>

Important Un obiect leneș este un obiect a cărui inițializare este amânată până când starea sa este
observată sau modificată. Unele exemple de cazuri de utilizare includ componente de injecție de
dependență care oferă servicii lene inițializate complet numai dacă este necesar, ORM-uri care oferă
entități leneșe care se hidratează din baza de date numai atunci când sunt accesate sau un parser
JSON care întârzie analizarea până când elementele sunt accesate.
Important Sunt acceptate două strategii de obiecte leneșe: obiecte fantomă și proxy virtuale,
denumite în continuare „fantome leneșe” și „proxy leneși”. În ambele strategii, obiectul leneș este
atașat unui inițializator sau fabrică care este apelat automat atunci când starea sa este observată sau
modificată pentru prima dată. Din punct de vedere al abstractizării, obiectele fantomă leneșe nu se
pot distinge de cele neleneșe: pot fi folosite fără să știe că sunt leneși, permițându-le să fie transmise
și folosite de un cod care nu este conștient de lene. Proxy-urile lazy sunt la fel de transparente, dar
trebuie avut grijă când se utilizează identitatea lor, deoarece proxy-ul și instanța sa reală au
identități diferite.
Important Este posibil să creați o instanță leneșă a oricărei clase definite de utilizator sau a clasei
stdClass (alte clase interne nu sunt acceptate) sau să resetați o instanță a acestor clase pentru a o
face leneșă. Punctele de intrare pentru crearea unui obiect leneș sunt metodele
ReflectionClass::newLazyGhost() și ReflectionClass::newLazyProxy().
Important Ambele metode acceptă o funcție care este apelată atunci când obiectul necesită
inițializare. Comportamentul așteptat al funcției variază în funcție de strategia utilizată, așa cum
este descris în documentația de referință pentru fiecare metodă.

<?php
class Example
{
public function __construct(public int $prop)
{
echo __METHOD__, "\n";
}
}

$reflector = new ReflectionClass(Example::class);


$lazyObject = $reflector->newLazyGhost(function (Example $object) {
// Initialize object in-place
$object->__construct(1);
});

var_dump($lazyObject);
var_dump(get_class($lazyObject));

// Triggers initialization
var_dump($lazyObject->prop);
?>

Important Fantomele leneșe sunt obiecte care se inițializează în loc și, odată inițializate, nu se pot
distinge de un obiect care nu a fost niciodată leneș. Această strategie este potrivită atunci când
controlăm atât instanțiarea, cât și inițializarea obiectului, făcându-l nepotrivit dacă oricare dintre
acestea este gestionat de o altă parte.
Important Proxy-urile lazy, odată inițializate, acționează ca proxy pentru o instanță reală: orice
operație pe un proxy leneș inițializat este redirecționată către instanța reală. Crearea instanței reale
poate fi delegată unei alte părți, făcând această strategie utilă în cazurile în care fantomele leneșe
sunt nepotrivite. Deși proxy-urile leneșe sunt aproape la fel de transparente ca fantomele leneșe,
este necesară prudență atunci când se utilizează identitatea lor, deoarece proxy-ul și instanța sa reală
au identități distincte.

Important Obiectele pot fi leneșe la momentul instanțierii folosind


ReflectionClass::newLazyGhost() sau ReflectionClass::newLazyProxy(), sau după instanțiere
folosind ReflectionClass::resetAsLazyGhost() sau ReflectionClass::resetAsLazyProxy(). După
aceasta, un obiect leneș poate fi inițializat printr-una dintre următoarele operații:
• Interacționarea cu obiectul într-un mod care declanșează inițializarea automată.
• Marcarea tuturor proprietăților sale ca non-lene folosind
ReflectionProperty::skipLazyInitialization() sau
ReflectionProperty::setRawValueWithoutLazyInitialization().
• Apelarea explicită a ReflectionClass::initializeLazyObject() sau
ReflectionClass::markLazyObjectAsInitialized().
Important Pe măsură ce obiectele leneșe devin inițializate când toate proprietățile lor sunt marcate
ca nelene, metodele de mai sus nu vor marca un obiect ca leneș dacă nicio proprietate nu poate fi
marcată ca leneș.

Important Obiectele lazy sunt concepute pentru a fi complet transparente pentru consumatorii lor,
astfel încât operațiunile normale care observă sau modifică starea obiectului vor declanșa automat
inițializarea înainte de efectuarea operației. Aceasta include, dar nu se limitează la, următoarele
operațiuni:
• Citirea sau scrierea unei proprietăți.
• Testarea dacă o proprietate este setată sau dezactivată.
• Accesarea sau modificarea unei proprietăți prin ReflectionProperty::getValue(),
ReflectionProperty::getRawValue(), ReflectionProperty::setValue() sau
ReflectionProperty::setRawValue().
• Listarea proprietăților cu ReflectionObject::getProperties(), ReflectionObject::getProperty(),
get_object_vars().
• Iterarea asupra proprietăților unui obiect care nu implementează Iterator sau
IteratorAggregate folosind foreach.
• Serializarea obiectului cu serialize(), json_encode(), etc.
• Clonarea obiectului.
Important Apelurile de metodă care nu accesează starea obiectului nu vor declanșa inițializarea. În
mod similar, interacțiunile cu obiectul care invocă metode magice sau funcții hook nu vor declanșa
inițializarea dacă aceste metode sau funcții nu accesează starea obiectului.

Important Următoarele metode specifice sau operațiuni de nivel scăzut permit accesul sau
modificarea obiectelor leneșe fără a declanșa inițializarea:
• Marcarea proprietăților ca non-lene cu ReflectionProperty::skipLazyInitialization() sau
ReflectionProperty::setRawValueWithoutLazyInitialization().
• Preluarea reprezentării interne a proprietăților folosind get_mangled_object_vars() sau prin
turnarea obiectului într-o matrice.
• Utilizarea serialize() când ReflectionClass::SKIP_INITIALIZATION_ON_SERIALIZE este
setat, cu excepția cazului în care __serialize() sau __sleep() declanșează inițializarea.
• Apelarea la ReflectionObject::__toString().
• Folosind var_dump() sau debug_zval_dump(), cu excepția cazului în care __debugInfo()
declanșează inițializarea.

Important Obiecte fantomă


• Obiectul este marcat ca non-leneș.
• Proprietățile care nu sunt inițializate cu ReflectionProperty::skipLazyInitialization() sau
ReflectionProperty::setRawValueWithoutLazyInitialization() sunt setate la valorile
implicite, dacă există. În această etapă, obiectul seamănă cu cel creat cu
ReflectionClass::newInstanceWithoutConstructor(), cu excepția proprietăților deja
inițializate.
• Funcția de inițializare este apoi apelată cu obiectul ca prim parametru. Funcția este de
așteptat, dar nu este necesară, pentru a inițializa starea obiectului și trebuie să returneze
valoare nulă sau nicio valoare. Obiectul nu mai este leneș în acest moment, așa că funcția își
poate accesa proprietățile direct.

Important Obiecte proxy


• Obiectul este marcat ca non-leneș.
• Spre deosebire de obiectele fantomă, proprietățile obiectului nu sunt modificate în această
etapă.
• Funcția din fabrică este apelată cu obiectul ca prim parametru și trebuie să returneze o
instanță non-lenesă a unei clase compatibile (vezi ReflectionClass::newLazyProxy()).
• Instanța returnată este denumită instanță reală și este atașată proxy-ului.
• Valorile proprietăților proxy-ului sunt eliminate ca și cum ar fi apelat unset().
Important După inițializare, accesarea oricărei proprietăți de pe proxy va produce același rezultat ca
accesarea proprietății corespunzătoare pe instanța reală; toate accesele de proprietate de pe proxy
sunt redirecționate către instanța reală, inclusiv proprietățile declarate, dinamice, inexistente sau
marcate cu ReflectionProperty::skipLazyInitialization() sau
ReflectionProperty::setRawValueWithoutLazyInitialization().
Important Obiectul proxy în sine nu este înlocuit sau înlocuit cu instanța reală.
Important În timp ce fabrica primește proxy-ul ca prim parametru, nu este de așteptat să îl modifice
(modificările sunt permise, dar se vor pierde în timpul pasului final de inițializare). Cu toate acestea,
proxy-ul poate fi folosit pentru decizii bazate pe valorile proprietăților inițializate, ale clasei,
obiectului în sine sau identității acestuia. De exemplu, inițializatorul poate folosi valoarea unei
proprietăți inițializate atunci când creează instanța reală.
Important Sfera și contextul $this ale funcției de inițializare sau fabrică rămân neschimbate și se
aplică constrângerile obișnuite de vizibilitate.
Important După inițializarea cu succes, inițializatorul sau funcția din fabrică nu mai este referită de
obiect și poate fi eliberată dacă nu are alte referințe.
Important Dacă inițializatorul lansează o excepție, starea obiectului este revenită la starea de pre-
inițializare și obiectul este marcat din nou ca leneș. Cu alte cuvinte, toate efectele asupra obiectului
în sine sunt inversate. Alte efecte secundare, cum ar fi efectele asupra altor obiecte, nu sunt
inversate. Acest lucru previne expunerea unei instanțe parțial inițializate în caz de eșec.

Important Clonarea unui obiect leneș declanșează inițializarea acestuia înainte ca clona să fie creată,
rezultând un obiect inițializat.
Important Pentru obiectele proxy, atât proxy-ul, cât și instanța sa reală sunt clonate, iar clona proxy-
ului este returnată. Metoda __clone este apelată pe instanța reală, nu pe proxy. Proxy-ul clonat și
instanța reală sunt legate așa cum sunt în timpul inițializării, astfel încât accesele la clona proxy sunt
redirecționate către clona instanței reale.
Important Acest comportament asigură că clona și obiectul original mențin stări separate.
Modificările aduse obiectului original sau stării inițializatorului său după clonare nu afectează
clona. Clonarea atât a proxy-ului, cât și a instanței sale reale, în loc să returneze o clonă a instanței
reale, asigură că operația de clonare returnează în mod constant un obiect din aceeași clasă.

Important Pentru fantomele leneșe, destructorul este apelat doar dacă obiectul a fost inițializat.
Pentru proxy, destructorul este apelat doar în instanța reală, dacă există unul.
Important Metodele ReflectionClass::resetAsLazyGhost() și ReflectionClass::resetAsLazyProxy()
pot invoca destructorul obiectului resetat.

28. Namespace
Important Ce sunt spațiile de nume? În cea mai largă definiție, spațiile de nume sunt o modalitate de
încapsulare a elementelor. Acesta poate fi văzut ca un concept abstract în multe locuri. De exemplu,
în orice sistem de operare, directoarele servesc la gruparea fișierelor asociate și acționează ca un
spațiu de nume pentru fișierele din ele. Ca exemplu concret, fișierul [Link] poate exista atât în
directorul /home/greg, cât și în /home/other, dar două copii ale [Link] nu pot coexista în același
director. În plus, pentru a accesa fișierul [Link] în afara directorului /home/greg, trebuie să
introducem numele directorului înaintea numelui fișierului folosind separatorul de director pentru a
obține /home/greg/[Link]. Același principiu se extinde la spațiile de nume din lumea programării.
Important În lumea PHP, spațiile de nume sunt concepute pentru a rezolva două probleme pe care
autorii de biblioteci și aplicații le întâmpină atunci când creează elemente de cod reutilizabile, cum
ar fi clase sau funcții:
• Ciocnirile de nume dintre codul pe care îl creați și clasele/funcțiile/constantele PHP interne
sau clasele/funcțiile/constantele terțe.
• Abilitatea de a alias (sau de a scurta) Extra_Long_Names conceput pentru a atenua prima
problemă, îmbunătățind lizibilitatea codului sursă.

<?php
namespace my\name; // see "Defining Namespaces" section

class MyClass {}
function myfunction() {}
const MYCONST = 1;

$a = new MyClass;
$c = new \my\name\MyClass; // see "Global Space" section

$a = strlen('hi'); // see "Using namespaces: fallback to global


// function/constant" section

$d = namespace\MYCONST; // see "namespace operator and __NAMESPACE__


// constant" section
$d = __NAMESPACE__ . '\MYCONST';
echo constant($d); // see "Namespaces and dynamic language features" section
?>

Important Deși orice cod PHP valid poate fi conținut într-un spațiu de nume, numai următoarele
tipuri de cod sunt afectate de spații de nume: clase (inclusiv rezumate și trăsături), interfețe, funcții
și constante.
Important Spațiile de nume sunt declarate folosind cuvântul cheie namespace. Un fișier care conține
un spațiu de nume trebuie să declare spațiul de nume din partea de sus a fișierului înainte de orice
alt cod - cu o excepție: cuvântul cheie declare.

<?php
namespace MyProject;

const CONNECT_OK = 1;
class Connection { /* ... */ }
function connect() { /* ... */ }

?>

Important Singura construcție de cod permisă înaintea unei declarații de spațiu de nume este
instrucțiunea declare, pentru definirea codificării unui fișier sursă. În plus, nici un cod non-PHP nu
poate precede o declarație de spațiu de nume, inclusiv spații albe suplimentare:

<?php
namespace MyProject; // fatal error - namespace must be the first statement in the script
?>
Important La fel ca directoarele și fișierele, spațiile de nume PHP conțin și capacitatea de a
specifica o ierarhie de nume de spații de nume. Astfel, un nume de spațiu de nume poate fi definit
cu sub-niveluri:

<?php
namespace MyProject\Sub\Level;

const CONNECT_OK = 1;
class Connection { /* ... */ }
function connect() { /* ... */ }

?>

Important Mai multe spații de nume pot fi, de asemenea, declarate în același fișier. Există două
sintaxe permise.

<?php
namespace MyProject;

const CONNECT_OK = 1;
class Connection { /* ... */ }
function connect() { /* ... */ }

namespace AnotherProject;

const CONNECT_OK = 1;
class Connection { /* ... */ }
function connect() { /* ... */ }
?>

Important Această sintaxă nu este recomandată pentru combinarea spațiilor de nume într-un singur
fișier. În schimb, este recomandat să utilizați sintaxa alternativă între paranteze.

<?php
namespace MyProject {

const CONNECT_OK = 1;
class Connection { /* ... */ }
function connect() { /* ... */ }
}
namespace AnotherProject {
const CONNECT_OK = 1;
class Connection { /* ... */ }
function connect() { /* ... */ }}?>
Important Pentru a combina codul global fără spații de nume cu codul cu spații de nume, este
acceptată numai sintaxa între paranteze. Codul global ar trebui să fie inclus într-o instrucțiune de
spațiu de nume fără nume de spațiu de nume, ca în:

<?php
namespace MyProject {

const CONNECT_OK = 1;
class Connection { /* ... */ }
function connect() { /* ... */ }
}

namespace { // global code


session_start();
$a = MyProject\connect();
echo MyProject\Connection::start();
}
?>

Important Niciun cod PHP nu poate exista în afara parantezelor spațiului de nume, cu excepția unei
declarații de deschidere.

<?php
declare(encoding='UTF-8');
namespace MyProject {

const CONNECT_OK = 1;
class Connection { /* ... */ }
function connect() { /* ... */ }
}

namespace { // global code


session_start();
$a = MyProject\connect();
echo MyProject\Connection::start();
}
?>

Important Înainte de a discuta despre utilizarea spațiilor de nume, este important să înțelegeți cum
PHP știe ce element cu spații de nume solicită codul dvs. Se poate face o analogie simplă între
spațiile de nume PHP și un sistem de fișiere. Există trei moduri de a accesa un fișier într-un sistem
de fișiere:
• Nume relativ al fișierului, cum ar fi [Link]. Acest lucru se rezolvă la currentdirectory/[Link]
unde currentdirectory este directorul ocupat în prezent. Deci, dacă directorul curent este
/home/foo, numele se rezolvă în /home/foo/[Link].
• Nume relativ de cale, cum ar fi subdirector/[Link]. Acest lucru se rezolvă la
actualdirectory/subdirectory/[Link].
• Nume absolut de cale, cum ar fi /main/[Link]. Aceasta se rezolvă în /main/[Link].

Important Același principiu poate fi aplicat elementelor cu spații de nume în PHP. De exemplu, un
nume de clasă poate fi referit în trei moduri:
• Nume necalificat, sau un nume de clasă fără prefix, cum ar fi $a = new foo(); sau
foo::staticmethod();. Dacă spațiul de nume curent este spațiul de nume curent, acesta se
rezolvă la spațiul de nume curent\foo. Dacă codul este cod global, fără spații de nume,
acesta se rezolvă în foo. O avertizare: numele necalificate pentru funcții și constante se vor
rezolva în funcții și constante globale dacă funcția sau constanta cu spațiu de nume nu este
definită. Consultați Utilizarea spațiilor de nume: alternativă la funcția/constantele globale
pentru detalii.
• Nume calificat, sau un nume de clasă prefixat, cum ar fi $a = new subnamespace\foo(); sau
subnamespace\foo::staticmethod();. Dacă spațiul de nume curent este spațiu de nume curent,
acesta se rezolvă la spațiu de nume curent\subnamespace\foo. Dacă codul este cod global,
fără spații de nume, acesta se rezolvă în subnamespace\foo.
• Nume complet calificat, sau un nume prefixat cu operator de prefix global, cum ar fi $a =
new \currentnamespace\foo(); sau \currentnamespace\foo::staticmethod();. Aceasta se
rezolvă întotdeauna la numele literal specificat în cod, currentnamespace\foo.

<?php
namespace Foo\Bar\subnamespace;

const FOO = 1;
function foo() {}
class foo
{
static function staticmethod() {}
}
?>

Important Implementarea de către PHP a spațiilor de nume este influențată de natura sa dinamică ca
limbaj de programare. Astfel, pentru a converti codul ca exemplul următor în cod spațial de nume:

<?php
class classname
{
function __construct()
{
echo __METHOD__,"\n";
}
}
function funcname()
{
echo __FUNCTION__,"\n";
}
const constname = "global";

$a = 'classname';
$obj = new $a; // prints classname::__construct
$b = 'funcname';
$b(); // prints funcname
echo constant('constname'), "\n"; // prints global
?>

Important Trebuie să utilizați numele complet calificat (nume de clasă cu prefix de spațiu de nume).
Rețineți că, deoarece nu există nicio diferență între un nume calificat și unul complet calificat în
interiorul unui nume de clasă dinamică, un nume de funcție sau un nume constant, bara oblică
inversă nu este necesară.

<?php
namespace namespacename;
class classname
{
function __construct()
{
echo __METHOD__,"\n";
}
}
function funcname()
{
echo __FUNCTION__,"\n";
}
const constname = "namespaced";

/* note that if using double quotes, "\\namespacename\\classname" must be used */


$a = '\namespacename\classname';
$obj = new $a; // prints namespacename\classname::__construct
$a = 'namespacename\classname';
$obj = new $a; // also prints namespacename\classname::__construct
$b = 'namespacename\funcname';
$b(); // prints namespacename\funcname
$b = '\namespacename\funcname';
$b(); // also prints namespacename\funcname
echo constant('\namespacename\constname'), "\n"; // prints namespaced
echo constant('namespacename\constname'), "\n"; // also prints namespaced
?>

Important PHP acceptă două moduri de accesare abstractă a elementelor din spațiul de nume curent,
constanta magică __NAMESPACE__ și cuvântul cheie pentru spațiul de nume. Valoarea lui
__NAMESPACE__ este un șir care conține numele actual al spațiului de nume. În codul global, fără
spații de nume, acesta conține un șir gol.

<?php
namespace MyProject;

echo '"', __NAMESPACE__, '"'; // outputs "MyProject"


?>

<?php

echo '"', __NAMESPACE__, '"'; // outputs ""


?>

Important Constanta __NAMESPACE__ este utilă pentru construirea dinamică a numelor, de


exemplu:
<?php
namespace MyProject;

function get($classname)
{
$a = __NAMESPACE__ . '\\' . $classname;
return new $a;
}
?>
Important Cuvântul cheie namespace poate fi folosit pentru a solicita în mod explicit un element din
spațiul de nume curent sau dintr-un sub-spațiu de nume. Este echivalentul spațiului de nume al
operatorului self pentru clase.

<?php
namespace MyProject;

use blah\blah as mine; // see "Using namespaces: Aliasing/Importing"

blah\mine(); // calls function MyProject\blah\mine()


namespace\blah\mine(); // calls function MyProject\blah\mine()

namespace\func(); // calls function MyProject\func()


namespace\sub\func(); // calls function MyProject\sub\func()
namespace\cname::method(); // calls static method "method" of class MyProject\cname
$a = new namespace\sub\cname(); // instantiates object of class MyProject\sub\cname
$b = namespace\CONSTANT; // assigns value of constant MyProject\CONSTANT to $b
?>

<?php

namespace\func(); // calls function func()


namespace\sub\func(); // calls function sub\func()
namespace\cname::method(); // calls static method "method" of class cname
$a = new namespace\sub\cname(); // instantiates object of class sub\cname
$b = namespace\CONSTANT; // assigns value of constant CONSTANT to $b
?>

Important Abilitatea de a face referire la un nume extern complet calificat cu un alias, sau de a
importa, este o caracteristică importantă a spațiilor de nume. Acest lucru este similar cu capacitatea
sistemelor de fișiere bazate pe Unix de a crea legături simbolice către un fișier sau către un director.
Important PHP poate alias(/import) constante, funcții, clase, interfețe, trăsături, enumerari și spații
de nume.
Important Aliasarea se realizează cu operatorul de utilizare. Iată un exemplu care arată toate cele 5
tipuri de import:

<?php
namespace foo;
use My\Full\Classname as Another;

// this is the same as use My\Full\NSname as NSname


use My\Full\NSname;

// importing a global class


use ArrayObject;

// importing a function
use function My\Full\functionName;

// aliasing a function
use function My\Full\functionName as func;
// importing a constant
use const My\Full\CONSTANT;

$obj = new namespace\Another; // instantiates object of class foo\Another


$obj = new Another; // instantiates object of class My\Full\Classname
NSname\subns\func(); // calls function My\Full\NSname\subns\func
$a = new ArrayObject(array(1)); // instantiates object of class ArrayObject
// without the "use ArrayObject" we would instantiate an object of class foo\ArrayObject
func(); // calls function My\Full\functionName
echo CONSTANT; // echoes the value of My\Full\CONSTANT
?>

Important PHP acceptă în plus o comandă rapidă convenabilă pentru a plasa mai multe instrucțiuni
de utilizare pe aceeași linie

<?php
use My\Full\Classname as Another, My\Full\NSname;

$obj = new Another; // instantiates object of class My\Full\Classname


NSname\subns\func(); // calls function My\Full\NSname\subns\func
?>

<?php
use My\Full\Classname as Another, My\Full\NSname;

$obj = new Another; // instantiates object of class My\Full\Classname


$obj = new \Another; // instantiates object of class Another
$obj = new Another\thing; // instantiates object of class My\Full\Classname\thing
$obj = new \Another\thing; // instantiates object of class Another\thing
?>

Important Cuvântul cheie use trebuie declarat în sfera cea mai exterioară a unui fișier (sfera
globală) sau în declarațiile de spațiu de nume. Acest lucru se datorează faptului că importul se face
în timpul compilării și nu în timpul rulării, deci nu poate fi blocat. Următorul exemplu va arăta o
utilizare ilegală a cuvântului cheie use:

<?php
namespace Languages;
function toGreenlandic()
{ use Languages\Danish;// ...}
?>

Important Clasele, funcțiile și constantele importate din același spațiu de nume pot fi grupate într-o
singură instrucțiune de utilizare.

<?php

use some\namespace\ClassA;
use some\namespace\ClassB;
use some\namespace\ClassC as C;

use function some\namespace\fn_a;


use function some\namespace\fn_b;
use function some\namespace\fn_c;

use const some\namespace\ConstA;


use const some\namespace\ConstB;
use const some\namespace\ConstC;

// is equivalent to the following groupped use declaration


use some\namespace\{ClassA, ClassB, ClassC as C};
use function some\namespace\{fn_a, fn_b, fn_c};
use const some\namespace\{ConstA, ConstB, ConstC};

Important Fără nicio definiție a spațiului de nume, toate definițiile de clasă și funcții sunt plasate în
spațiul global - așa cum era în PHP înainte ca spațiile de nume să fie suportate. Prefixarea unui
nume cu \ va specifica faptul că numele este necesar din spațiul global chiar și în contextul spațiului
de nume.

<?php
namespace A\B\C;

/* This function is A\B\C\fopen */


function fopen() {
/* ... */
$f = \fopen(...); // call global fopen
return $f;
}
?>

Important În interiorul unui spațiu de nume, când PHP întâlnește un nume necalificat într-un nume
de clasă, funcție sau context constant, le rezolvă cu priorități diferite. Numele claselor se rezolvă
întotdeauna la numele actual al spațiului de nume. Astfel, pentru a accesa clase de utilizatori interne
sau fără spații de nume, trebuie să faceți referire la ele cu numele lor complet calificat, ca în:

<?php
namespace A\B\C;
class Exception extends \Exception {}

$a = new Exception('hi'); // $a is an object of class A\B\C\Exception


$b = new \Exception('hi'); // $b is an object of class Exception

$c = new ArrayObject; // fatal error, class A\B\C\ArrayObject not found


?>
Important Pentru funcții și constante, PHP va reveni la funcții sau constante globale dacă nu există
o funcție sau o constantă cu spațiu de nume.

<?php
namespace A\B\C;

const E_ERROR = 45;


function strlen($str)
{
return \strlen($str) - 1;
}

echo E_ERROR, "\n"; // prints "45"


echo INI_ALL, "\n"; // prints "7" - falls back to global INI_ALL

echo strlen('hi'), "\n"; // prints "1"


if (is_array('hi')) { // prints "is not array"
echo "is array\n";
} else {
echo "is not array\n";
}
?>

Nume necalificat
Acesta este un identificator fără un separator de spațiu de nume, cum ar fi Foo
Nume calificat
Acesta este un identificator cu un separator de spațiu de nume, cum ar fi Foo\Bar
Nume complet calificat
Acesta este un identificator cu un separator de spațiu de nume care începe cu un separator de
spațiu de nume, cum ar fi \Foo\Bar. Spațiul de nume \Foo este, de asemenea, un nume complet
calificat.
Nume relativ
Acesta este un identificator care începe cu namespace, cum ar fi namespace\Foo\Bar.
Numele sunt rezolvate urmând aceste reguli de rezoluție:
• Numele complet calificate se rezolvă întotdeauna la nume fără separator principal de spațiu
de nume. De exemplu, \A\B se rezolvă în A\B.
• Numele relative se rezolvă întotdeauna la numele cu spațiul de nume înlocuit cu spațiul de
nume curent. Dacă numele apare în spațiul de nume global, prefixul de spațiu de nume\ este
eliminat. De exemplu, namespace\A din interiorul namespace X\Y se rezolvă în X\Y\A.
Același nume în interiorul spațiului de nume global se rezolvă în A.
• Pentru numele calificate, primul segment al numelui este tradus conform tabelului curent de
import de clasă/spațiu de nume. De exemplu, dacă spațiul de nume A\B\C este importat ca
C, numele C\D\E este tradus în A\B\C\D\E.
• Pentru numele calificate, dacă nu se aplică nicio regulă de import, spațiul de nume curent
este adăugat înaintea numelui. De exemplu, numele C\D\E din spațiul de nume A\B, se
rezolvă în A\B\C\D\E.
• Pentru numele necalificate, numele este tradus conform tabelului de import curent pentru
tipul de simbol respectiv. Aceasta înseamnă că numele de clasă sunt traduse conform
tabelului de import clasă/spațiu de nume, numele funcțiilor conform tabelului de import al
funcției și constantele conform tabelului de import constant. De exemplu, după utilizarea A\
B\C; o utilizare precum noul C() se rezolvă la numele A\B\C(). În mod similar, după
utilizare funcția A\B\foo; o utilizare precum foo() se rezolvă la numele A\B\foo.
• Pentru numele necalificate, dacă nu se aplică nicio regulă de import și numele se referă la un
simbol asemănător clasei, spațiul de nume curent este adăugat înainte. De exemplu, noul C()
în spațiul de nume A\B se rezolvă la numele A\B\C.
• Pentru numele necalificate, dacă nu se aplică nicio regulă de import și numele se referă la o
funcție sau constantă și codul se află în afara spațiului de nume global, numele este rezolvat
în timpul execuției. Presupunând că codul se află în spațiul de nume A\B, iată cum este
rezolvat un apel la funcția foo():
◦ Caută o funcție din spațiul de nume curent: A\B\foo().
◦ Încearcă să găsească și să apeleze funcția globală foo().
<?php
namespace A;
use B\D, C\E as F;

// function calls

foo(); // first tries to call "foo" defined in namespace "A"


// then calls global function "foo"

\foo(); // calls function "foo" defined in global scope

my\foo(); // calls function "foo" defined in namespace "A\my"

F(); // first tries to call "F" defined in namespace "A"


// then calls global function "F"

// class references

new B(); // creates object of class "B" defined in namespace "A"


// if not found, it tries to autoload class "A\B"

new D(); // using import rules, creates object of class "D" defined in namespace "B"
// if not found, it tries to autoload class "B\D"

new F(); // using import rules, creates object of class "E" defined in namespace "C"
// if not found, it tries to autoload class "C\E"

new \B(); // creates object of class "B" defined in global scope


// if not found, it tries to autoload class "B"

new \D(); // creates object of class "D" defined in global scope


// if not found, it tries to autoload class "D"

new \F(); // creates object of class "F" defined in global scope


// if not found, it tries to autoload class "F"

// static methods/namespace functions from another namespace

B\foo(); // calls function "foo" from namespace "A\B"

B::foo(); // calls method "foo" of class "B" defined in namespace "A"


// if class "A\B" not found, it tries to autoload class "A\B"

D::foo(); // using import rules, calls method "foo" of class "D" defined in namespace "B"
// if class "B\D" not found, it tries to autoload class "B\D"

\B\foo(); // calls function "foo" from namespace "B"

\B::foo(); // calls method "foo" of class "B" from global scope


// if class "B" not found, it tries to autoload class "B"

// static methods/namespace functions of current namespace


A\B::foo(); // calls method "foo" of class "B" from namespace "A\A"
// if class "A\A\B" not found, it tries to autoload class "A\A\B"

\A\B::foo(); // calls method "foo" of class "B" from namespace "A"


// if class "A\B" not found, it tries to autoload class "A\B"
?>

29. Enumerarile
Important Enumerările, sau „Enumări”, permit unui dezvoltator să definească un tip personalizat
care este limitat la una dintr-un număr discret de valori posibile. Acest lucru poate fi deosebit de util
la definirea unui model de domeniu, deoarece permite „facerea stărilor nevalide nereprezentabile”.
Important Enumerările apar în multe limbi cu o varietate de caracteristici diferite. În PHP, Enums-
urile sunt un tip special de obiect. Enum în sine este o clasă, iar cazurile sale posibile sunt toate
obiecte cu o singură instanță ale acelei clase. Aceasta înseamnă că cazurile Enum sunt obiecte
valide și pot fi folosite oriunde poate fi folosit un obiect, inclusiv verificări de tip.
Important Cel mai popular exemplu de enumerare este tipul boolean încorporat, care este un tip
enumerat cu valori legale true și false. Enums permite dezvoltatorilor să-și definească propriile
enumerari arbitrar robuste.

Important Enumerările sunt similare cu clasele și au aceleași spații de nume ca și clasele, interfețele
și trăsăturile. De asemenea, sunt autoîncărcabile în același mod. O Enum definește un nou tip, care
are un număr fix, limitat de valori legale posibile.

<?php
enum Suit
{
case Hearts;
case Diamonds;
case Clubs;
case Spades;
}
?>

Important Această declarație creează un nou tip enumerat numit Suit, care are patru și doar patru
valori legale: Suit::Hearts, Suit::Diamonds, Suit::Clubs și Suit::Spades. Variabilele pot fi atribuite
uneia dintre aceste valori legale. O funcție poate fi verificată cu un tip enumerat, caz în care pot fi
transmise numai valorile acelui tip.
Important O enumerare poate avea zero sau mai multe definiții de caz, fără maxim. O enumerare cu
cazuri zero este validă din punct de vedere sintactic, chiar dacă mai degrabă inutilă.
Important În mod implicit, cazurile nu sunt susținute intrinsec de o valoare scalară. Adică,
Suit::Hearts nu este egal cu „0”. În schimb, fiecare caz este susținut de un obiect singleton cu acel
nume. Asta înseamnă că:
<?php

$a = Suit::Spades;
$b = Suit::Spades;

$a === $b; // true


$a instanceof Suit; // true
?>

Important De asemenea, înseamnă că valorile enumerate nu sunt niciodată < sau > una pe cealaltă,
deoarece acele comparații nu sunt semnificative pentru obiecte. Aceste comparații vor returna
întotdeauna false atunci când se lucrează cu valori enumerate.
Important Acest tip de caz, fără date aferente, se numește „caz pur”. O Enum care conține doar
cazuri pure se numește Enum pur.
Important Toate cazurile pure sunt implementate ca instanțe de tipul lor de enumerare. Tipul de
enumerare este reprezentat intern ca o clasă.
Important Toate cazurile au o proprietate de numai citire, nume, adică numele casei în sine care face
distincție între majuscule și minuscule.

<?php

print Suit::Spades->name;
// prints "Spades"
?>

Important De asemenea, este posibil să utilizați funcțiile definite() și constant() pentru a verifica
existența sau pentru a citi un caz de enumerare dacă numele este obținut dinamic. Acest lucru este,
totuși, descurajat, deoarece utilizarea enumărilor susținute ar trebui să funcționeze pentru
majoritatea cazurilor de utilizare.

Important În mod implicit, cazurile enumerate nu au echivalent scalar. Sunt pur și simplu obiecte
singleton. Cu toate acestea, există cazuri ample în care un caz enumerat trebuie să poată merge dus-
întors la o bază de date sau un depozit de date similar, astfel încât este util să existe un echivalent
scalar încorporat (și astfel trivial serializabil) definit intrinsec. Pentru a defini un echivalent scalar
pentru o Enumerare, sintaxa este următoarea:

<?php

enum Suit: string


{
case Hearts = 'H';
case Diamonds = 'D';
case Clubs = 'C';
case Spades = 'S';
}
?>

Important Un caz care are un echivalent scalar se numește un caz susținut, deoarece este „susținut”
de o valoare mai simplă. O enumerare care conține toate cazurile susținute se numește „Enumerare
susținută”. O enumerare susținută poate conține doar cazuri susținute. O enumerare pură poate
conține doar cazuri pure.
Important O enumerare susținută poate fi susținută de tipuri de int sau șir, iar o enumerare dată
acceptă doar un singur tip la un moment dat (adică, nicio unire a int|șir). Dacă o enumerare este
marcată ca având un echivalent scalar, atunci toate cazurile trebuie să aibă un echivalent scalar unic
definit în mod explicit. Nu există echivalente scalare autogenerate (de exemplu, numere întregi
secvențiale). Carcasele susținute trebuie să fie unice; este posibil ca două cazuri de enumerare
susținute să nu aibă același echivalent scalar. Cu toate acestea, o constantă se poate referi la un caz,
creând efectiv un alias. Consultați Constante de enumerare.
Important Valorile echivalente trebuie să fie literale sau expresii literale. Constantele și expresiile
constante nu sunt acceptate. Adică, 1 + 1 este permis, dar 1 + SOME_CONST nu este.
Important Carcasele susținute au o proprietate suplimentară de numai citire, value, care este
valoarea specificată în definiție.

<?php

print Suit::Clubs->value;
// Prints "C"
?>

<?php

$suit = Suit::Clubs;
$ref = &$suit->value;
// Error: Cannot acquire reference to property Suit::$value
?>

Enumerările susținute implementează o interfață internă BackedEnum, care expune două metode
suplimentare:
• from(int|string): self va lua un scalar și va returna Enum Case corespunzătoare. Dacă nu se
găsește unul, va arunca o valoare ValueError. Acest lucru este util în principal în cazurile în
care scalarul de intrare este de încredere și o valoare de enumerare lipsă ar trebui considerată
o eroare de oprire a aplicației.
• tryFrom(int|string): ?self va lua un scalar și va returna Enum Case corespunzătoare. Dacă nu
se găsește unul, va returna null. Acest lucru este util în principal în cazurile în care scalarul
de intrare nu este de încredere și apelantul dorește să-și implementeze propria lor gestionare
a erorilor sau logica valorii implicite.
Important Metodele from() și tryFrom() urmează regulile standard de tastare slabe/puternice. În
modul de tastare slabă, trecerea unui număr întreg sau șir este acceptabilă și sistemul va forța
valoarea în consecință. De asemenea, trecerea unui flotor va funcționa și va fi forțată. În modul de
tastare strictă, trecerea unui număr întreg la from() pe o enumerare susținută de șir (sau invers) va
avea ca rezultat o TypeError, la fel ca un float în toate circumstanțele. Toate celelalte tipuri de
parametri vor genera o TypeError în ambele moduri.

<?php
$record = get_stuff_from_database($id);
print $record['suit'];
$suit = Suit::from($record['suit']);
// Invalid data throws a ValueError: "X" is not a valid scalar value for enum "Suit"
print $suit->value;
$suit = Suit::tryFrom('A') ?? Suit::Spades;
// Invalid data returns null, so Suit::Spades is used instead.
print $suit->value;
?>
Important Enumerările (atât Pure Enums, cât și Backed Enums) pot conține metode și pot
implementa interfețe. Dacă o Enum implementează o interfață, atunci orice verificare de tip pentru
acea interfață va accepta, de asemenea, toate cazurile acelei Enum.
<?php

interface Colorful
{
public function color(): string;
}

enum Suit implements Colorful


{
case Hearts;
case Diamonds;
case Clubs;
case Spades;

// Fulfills the interface contract.


public function color(): string
{
return match($this) {
Suit::Hearts, Suit::Diamonds => 'Red',
Suit::Clubs, Suit::Spades => 'Black',
};
}

// Not part of an interface; that's fine.


public function shape(): string
{
return "Rectangle";
}
}

function paint(Colorful $c)


{
/* ... */
}

paint(Suit::Clubs); // Works

print Suit::Diamonds->shape(); // prints "Rectangle"


?>

Important În acest exemplu, toate cele patru instanțe ale lui Suit au două metode, color() și shape().
În ceea ce privește codul de apelare și verificările de tip, acestea se comportă exact la fel ca orice
altă instanță de obiect. Pe o enumerare susținută, declarația interfeței merge după declarația tipului
de suport.

Important În acest exemplu, toate cele patru instanțe ale lui Suit au două metode, color() și shape().
În ceea ce privește codul de apelare și verificările de tip, acestea se comportă exact la fel ca orice
altă instanță de obiect. Pe o enumerare susținută, declarația interfeței merge după declarația tipului
de suport.
<?php

interface Colorful
{
public function color(): string;
}

enum Suit: string implements Colorful


{
case Hearts = 'H';
case Diamonds = 'D';
case Clubs = 'C';
case Spades = 'S';

// Fulfills the interface contract.


public function color(): string
{
return match($this) {
Suit::Hearts, Suit::Diamonds => 'Red',
Suit::Clubs, Suit::Spades => 'Black',
};
}
}
?>

Important În interiorul unei metode, variabila $this este definită și se referă la instanța Case.
Metodele pot fi în mod arbitrar complexe, dar în practică vor returna de obicei o valoare statică sau
potrivire pe $this pentru a oferi rezultate diferite pentru cazuri diferite.

<?php

interface Colorful
{
public function color(): string;
}

final class Suit implements UnitEnum, Colorful


{
public const Hearts = new self('Hearts');
public const Diamonds = new self('Diamonds');
public const Clubs = new self('Clubs');
public const Spades = new self('Spades');

private function __construct(public readonly string $name) {}

public function color(): string


{
return match($this) {
Suit::Hearts, Suit::Diamonds => 'Red',
Suit::Clubs, Suit::Spades => 'Black',
};
}
public function shape(): string
{
return "Rectangle";
}

public static function cases(): array


{
// Illegal method, because manually defining a cases() method on an Enum is
disallowed.
// See also "Value listing" section.
}
}
?>

Important Metodele pot fi publice, private sau protejate, deși în practică private și protejate sunt
echivalente, deoarece moștenirea nu este permisă.

Important Enumerările pot avea și metode statice. Utilizarea metodelor statice pe enumerarea în
sine este în primul rând pentru constructori alternativi. de ex.:
<?php

enum Size
{
case Small;
case Medium;
case Large;

public static function fromLength(int $cm): static


{
return match(true) {
$cm < 50 => static::Small,
$cm < 100 => static::Medium,
default => static::Large,
};
}
}
?>

Important Metodele statice pot fi publice, private sau protejate, deși în practică private și protejate
sunt echivalente, deoarece moștenirea nu este permisă.

Important Enumerările pot include constante, care pot fi publice, private sau protejate, deși în
practică private și protejate sunt echivalente, deoarece moștenirea nu este permisă. O constantă de
enumerare se poate referi la un caz de enumerare:

<?php

enum Size
{
case Small;
case Medium;
case Large;
public const Huge = self::Large;
}
?>

Important Enumerările pot folosi trăsături, care se vor comporta la fel ca la clase. Avertismentul
este că trăsăturile utilizate într-o enumerare nu trebuie să conțină proprietăți. Acestea pot include
numai metode și metode statice. O trăsătură cu proprietăți va duce la o eroare fatală.

<?php

interface Colorful
{
public function color(): string;
}

trait Rectangle
{
public function shape(): string {
return "Rectangle";
}
}

enum Suit implements Colorful


{
use Rectangle;

case Hearts;
case Diamonds;
case Clubs;
case Spades;

public function color(): string


{
return match($this) {
Suit::Hearts, Suit::Diamonds => 'Red',
Suit::Clubs, Suit::Spades => 'Black',
};
}
}
?>

Important Deoarece cazurile sunt reprezentate ca constante pe enumerarea în sine, ele pot fi
utilizate ca valori statice în majoritatea expresiilor constante: valorile implicite ale proprietăților,
valorile implicite ale variabilelor statice, valorile implicite ale parametrilor, valorile globale și
constante de clasă. Ele nu pot fi utilizate în alte valori de caz enumerare, dar constantele normale se
pot referi la un caz enumerare.
Important Cu toate acestea, apelurile implicite de metode magice, cum ar fi ArrayAccess pe
enumerari, nu sunt permise în definițiile statice sau constante, deoarece nu putem garanta în mod
absolut că valoarea rezultată este deterministă sau că invocarea metodei este lipsită de efecte
secundare. Apelurile de funcții, apelurile de metode și accesul la proprietate continuă să fie operații
nevalide în expresiile constante.
<?php
// This is an entirely legal Enum definition.
enum Direction implements ArrayAccess
{
case Up;
case Down;
public function offsetExists($offset): bool
{
return false;
}
public function offsetGet($offset): mixed
{
return null;
}
public function offsetSet($offset, $value): void
{
throw new Exception();
}
public function offsetUnset($offset): void
{
throw new Exception();
}
}

class Foo
{
// This is allowed.
const DOWN = Direction::Down;
// This is disallowed, as it may not be deterministic.
const UP = Direction::Up['short'];
// Fatal error: Cannot use [] on enums in constant expression
}
// This is entirely legal, because it's not a constant expression.
$x = Direction::Up['short'];
var_dump("\$x is " . var_export($x, true));

$foo = new Foo();


?>

Important Deși Enum-urile sunt construite pe clase și obiecte, ele nu acceptă toate funcționalitățile
legate de obiecte. În special, cazurile Enum sunt interzise de a avea stat.
• Constructorii și Destructorii sunt interzise.
• Moștenirea nu este acceptată. Enumerările nu pot fi extinse sau extinse.
• Proprietățile statice sau ale obiectului nu sunt permise.
• Clonarea unui caz Enum nu este acceptată, deoarece cazurile trebuie să fie instanțe
singleton.
• Metodele magice, cu excepția celor enumerate mai jos, sunt interzise.
• Enumerările trebuie întotdeauna declarate înainte de a fi utilizate.

Important Următoarea funcționalitate a obiectului este disponibilă și se comportă la fel ca pe orice


alt obiect:
• Metode publice, private și protejate.
• Metode statice publice, private și protejate.
• Constante publice, private și protejate.
• Enums poate implementa orice număr de interfețe.
• Enumerările și cazurile pot avea atribute atașate. Filtrul țintă TARGET_CLASS include
Enumerările în sine. Filtrul țintă TARGET_CLASS_CONST include Enum Cases.
• __call, __callStatic și __invoca metode magice
• Constantele __CLASS__ și __FUNCTION__ se comportă normal

Important Constanta magică ::class pe un tip Enum evaluează numele tipului, inclusiv orice spațiu
de nume, exact la fel ca un obiect. Constanta magică ::class pe o instanță Case evaluează, de
asemenea, tipul Enum, deoarece este o instanță de acel tip.
Important În plus, cazurile enumerate nu pot fi instanțiate direct cu new, nici cu
ReflectionClass::newInstanceWithoutConstructor() în reflectare. Ambele vor avea ca rezultat o
eroare.

<?php

$clovers = new Suit();


// Error: Cannot instantiate enum Suit

$horseshoes = (new ReflectionClass(Suit::class))->newInstanceWithoutConstructor()


// Error: Cannot instantiate enum Suit
?>

Important Atât Pure Enums, cât și Backed Enums implementează o interfață internă numită
UnitEnum. UnitEnum include o metodă statică case(). cases() returnează o matrice împachetată cu
toate cazurile definite în ordinea declarației.

<?php

Suit::cases();
// Produces: [Suit::Hearts, Suit::Diamonds, Suit::Clubs, Suit::Spades]
?>

Important Enumerările sunt serializate diferit de obiecte. Mai exact, au un nou cod de serializare,
„E”, care specifică numele cazului de enumerare. Rutina de deserializare este apoi capabilă să o
folosească pentru a seta o variabilă la valoarea singleton existentă. Aceasta asigură că:

<?php

Suit::Hearts === unserialize(serialize(Suit::Hearts));

print serialize(Suit::Hearts);
// E:11:"Suit:Hearts";
?>

Important La deserializare, dacă nu se pot găsi o enumerare și un caz care să se potrivească cu o


valoare serializată, va fi emis un avertisment și va fi returnat false.
Important Dacă un Pure Enum este serializat la JSON, va fi generată o eroare. Dacă o enumerare
susținută este serializată la JSON, aceasta va fi reprezentată numai de valoarea sa scalară, în tipul
corespunzător. Comportamentul ambelor poate fi suprascris prin implementarea JsonSerializable.
Important Pentru print_r(), ieșirea unui caz de enumerare este ușor diferită de obiecte pentru a
minimiza confuzia.

<?php

enum Foo {
case Bar;
}

enum Baz: int {


case Beep = 5;
}

print_r(Foo::Bar);
print_r(Baz::Beep);

/* Produces

Foo Enum (
[name] => Bar
)
Baz Enum:int {
[name] => Beep
[value] => 5
}
*/
?>

Clasele au contracte privind metodele lor:

<?php
class A {}
class B extends A {}
function foo(A $a) {}
function bar(B $b) {
foo($b);
}
?>

Important Acest cod este sigur de tip, deoarece B urmează contractul lui A, iar prin magia
co/contra-varianță, orice așteptare pe care cineva o poate avea de la metode va fi păstrată, cu
excepții.
Important Enumerările au contracte pentru cazurile lor, nu metode:

<?php

enum ErrorCode {
case SOMETHING_BROKE;
}

function quux(ErrorCode $errorCode)


{
// When written, this code appears to cover all cases
match ($errorCode) {
ErrorCode::SOMETHING_BROKE => true,
}
}

?>

Important Declarația de potrivire din funcția quux poate fi analizată static pentru a acoperi toate
cazurile din ErrorCode.
Important Dar imaginați-vă că era permisă extinderea enumerarilor:

<?php

// Thought experiment code where enums are not final.


// Note, this won't actually work in PHP.
enum MoreErrorCode extends ErrorCode {
case PEBKAC;
}

function fot(MoreErrorCode $errorCode) {


quux($errorCode);
}

fot(MoreErrorCode::PEBKAC);

?>

Important Conform regulilor normale de moștenire, o clasă care extinde alta va trece verificarea de
tip. Problema ar fi că declarația de potrivire din quux() nu mai acoperă toate cazurile. Deoarece nu
știe despre MoreErrorCode::PEBKAC, meciul va arunca o excepție. Din acest motiv, enumerarile
sunt definitive si nu pot fi extinse.

29. Erori
Important PHP raportează erori ca răspuns la o serie de condiții interne de eroare. Acestea pot fi
utilizate pentru a semnala o serie de condiții diferite și pot fi afișate și/sau înregistrate după cum
este necesar.
Important Fiecare eroare generată de PHP include un tip. Este disponibilă o listă a acestor tipuri de
erori, împreună cu o scurtă descriere a comportamentului lor și a modului în care pot fi cauzate.

Important Dacă nu este setat niciun handler de erori, atunci PHP va gestiona orice erori care apar
conform configurației sale. Ce erori sunt raportate și care sunt ignorate este controlată de directiva
error_reporting [Link] sau în timpul execuției apelând error_reporting(). Cu toate acestea, este
recomandat ca directiva de configurare să fie setată, deoarece pot apărea unele erori înainte de a
începe execuția scriptului.
Important Într-un mediu de dezvoltare, ar trebui să setați întotdeauna error_reporting la E_ALL,
deoarece trebuie să fiți conștient și să remediați problemele ridicate de PHP. În producție, este
posibil să doriți să setați acest lucru la un nivel mai puțin pronunțat, cum ar fi E_ALL &
~E_NOTICE & ~E_DEPRECATED, dar în multe cazuri E_ALL este, de asemenea, adecvat,
deoarece poate oferi o avertizare timpurie a potențialelor probleme.
Important Ce face PHP cu aceste erori depinde de alte două directive [Link]. display_errors
controlează dacă eroarea este afișată ca parte a ieșirii scriptului. Acest lucru ar trebui să fie
întotdeauna dezactivat într-un mediu de producție, deoarece poate include informații confidențiale,
cum ar fi parolele bazei de date, dar este adesea util pentru activare în dezvoltare, deoarece asigură
raportarea imediată a problemelor.
Important Pe lângă afișarea erorilor, PHP poate înregistra erori atunci când directiva log_errors este
activată. Aceasta va înregistra orice erori în fișierul sau syslog definit de error_log. Acest lucru
poate fi extrem de util într-un mediu de producție, deoarece puteți înregistra erorile care apar și apoi
puteți genera rapoarte pe baza acestor erori.
Important Dacă gestionarea implicită a erorilor PHP este inadecvată, puteți, de asemenea, să
gestionați multe tipuri de erori cu propriul dvs. handler personalizat de erori, instalându-l cu
set_error_handler(). În timp ce unele tipuri de erori nu pot fi gestionate în acest fel, cele care pot fi
tratate pot fi apoi tratate în modul în care scriptul dvs. consideră potrivit: de exemplu, aceasta poate
fi folosită pentru a afișa utilizatorului o pagină de eroare personalizată și apoi pentru a raporta mai
direct decât printr-un jurnal, cum ar fi prin trimiterea unui e-mail.

30. Exceptii
Important PHP are un model de excepție similar cu cel al altor limbaje de programare. O excepție
poate fi aruncată și prinsă ("prinsă") în PHP. Codul poate fi înconjurat într-un bloc de încercare,
pentru a facilita identificarea potențialelor excepții. Fiecare încercare trebuie să aibă cel puțin o
captură corespunzătoare sau un bloc în final.
Important Dacă se aruncă o excepție și domeniul său de aplicare curent al funcției nu are nici un
bloc catch, excepția va „bulbota” stiva de apeluri către funcția de apelare până când va găsi un bloc
catch care se potrivește. Toate blocurile pe care le întâlnește în cele din urmă pe parcurs vor fi
executate. Dacă stiva de apeluri este derulată până la sfera globală fără a întâlni un bloc catch care
se potrivește, programul se va termina cu o eroare fatală, dacă nu a fost setat un handler global de
excepții.
Important Obiectul aruncat trebuie să fie o instanță a Throwable. Încercarea de a arunca un obiect
care nu este, va avea ca rezultat o eroare fatală PHP.
Important Începând cu PHP 8.0.0, cuvântul cheie throw este o expresie și poate fi folosit în orice
context de expresie. În versiunile anterioare, era o declarație și trebuia să fie pe propria linie.

Important Un bloc catch definește modul de răspuns la o excepție aruncată. Un bloc catch definește
unul sau mai multe tipuri de excepții sau erori pe care le poate gestiona și, opțional, o variabilă
căreia să îi atribuie excepția. (Variabila era necesară înainte de PHP 8.0.0.) Primul bloc de captură
pe care o întâlnește o excepție sau o eroare aruncată care se potrivește cu tipul obiectului aruncat se
va ocupa de obiect.
Important Mai multe blocuri de captură pot fi utilizate pentru a prinde diferite clase de excepții.
Execuția normală (când nu se aruncă nicio excepție în blocul try) va continua după ultimul bloc
catch definit în secvență. Excepțiile pot fi aruncate (sau re-aruncate) în cadrul unui bloc de captură.
Dacă nu, execuția va continua după blocul catch care a fost declanșat.

Important Când se aruncă o excepție, codul care urmează instrucțiunii nu va fi executat și PHP va
încerca să găsească primul bloc catch potrivit. Dacă o excepție nu este capturată, o eroare fatală
PHP va fi emisă cu un mesaj „Uncaught Exception...”, cu excepția cazului în care un handler a fost
definit cu set_exception_handler().
Important Începând cu PHP 7.1.0, un bloc catch poate specifica mai multe excepții folosind
caracterul pipe (|). Acest lucru este util atunci când diferite excepții din diferite ierarhii de clasă sunt
tratate la fel.
Important Începând cu PHP 8.0.0, numele variabilei pentru o excepție capturată este opțional. Dacă
nu este specificat, blocul catch se va executa în continuare, dar nu va avea acces la obiectul aruncat.
Important Un bloc final poate fi, de asemenea, specificat după sau în locul blocurilor catch. Codul
din blocul finally va fi întotdeauna executat după blocurile try and catch, indiferent dacă a fost
aruncată o excepție și înainte de reluarea execuției normale.
Important O interacțiune notabilă este între blocul final și o instrucțiune return. Dacă în interiorul
blocurilor try sau catch este întâlnită o instrucțiune return, blocul final va fi în continuare executat.
Mai mult, instrucțiunea return este evaluată atunci când este întâlnită, dar rezultatul va fi returnat
după executarea blocului final. În plus, dacă blocul finally conține și o instrucțiune return, valoarea
din blocul finally este returnată.

Important Dacă o excepție este permisă să ajungă la sfera globală, aceasta poate fi capturată de un
handler global de excepții dacă este setată. Funcția set_exception_handler() poate seta o funcție care
va fi apelată în locul unui bloc catch dacă nu este invocat niciun alt bloc. Efectul este în esență
același ca și cum întregul program ar fi înfășurat într-un bloc try-catch cu acea funcție ca catch.

<?php
function exceptions_error_handler($severity, $message, $filename, $lineno) {
throw new ErrorException($message, 0, $severity, $filename, $lineno);
}

set_error_handler('exceptions_error_handler');
?>

<?php
function inverse($x) {
if (!$x) {
throw new Exception('Division by zero.');
}
return 1/$x;
}

try {
echo inverse(5) . "\n";
echo inverse(0) . "\n";
} catch (Exception $e) {
echo 'Caught exception: ', $e->getMessage(), "\n";
}

// Continue execution
echo "Hello World\n";
?>

<?php
function inverse($x) {
if (!$x) {
throw new Exception('Division by zero.');
}
return 1/$x;
}

try {
echo inverse(5) . "\n";
} catch (Exception $e) {
echo 'Caught exception: ', $e->getMessage(), "\n";
} finally {
echo "First finally.\n";
}

try {
echo inverse(0) . "\n";
} catch (Exception $e) {
echo 'Caught exception: ', $e->getMessage(), "\n";
} finally {
echo "Second finally.\n";
}

// Continue execution
echo "Hello World\n";
?>

Important O clasă de excepție definită de utilizator poate fi definită prin extinderea clasei de
excepție încorporate. Membrii și proprietățile de mai jos arată ceea ce este accesibil în clasa copil
care derivă din clasa încorporată Exception.

<?php
class Exception implements Throwable
{
protected $message = 'Unknown exception'; // exception message
private $string; // __toString cache
protected $code = 0; // user defined exception code
protected $file; // source filename of exception
protected $line; // source line of exception
private $trace; // backtrace
private $previous; // previous exception if nested exception

public function __construct($message = '', $code = 0, Throwable $previous = null);

final private function __clone(); // Inhibits cloning of exceptions.

final public function getMessage(); // message of exception


final public function getCode(); // code of exception
final public function getFile(); // source filename
final public function getLine(); // source line
final public function getTrace(); // an array of the backtrace()
final public function getPrevious(); // previous exception
final public function getTraceAsString(); // formatted string of trace

// Overrideable
public function __toString(); // formatted string for display
}
?>
Important Dacă o clasă extinde clasa de excepție încorporată și redefinește constructorul, este foarte
recomandat să apeleze și parent::__construct() pentru a se asigura că toate datele disponibile au fost
alocate corect. Metoda __toString() poate fi suprascrisă pentru a oferi o ieșire personalizată atunci
când obiectul este prezentat ca șir.

<?php
/**
* Define a custom exception class
*/
class MyException extends Exception
{
// Redefine the exception so message isn't optional
public function __construct($message, $code = 0, Throwable $previous = null) {
// some code

// make sure everything is assigned properly


parent::__construct($message, $code, $previous);
}

// custom string representation of object


public function __toString() {
return __CLASS__ . ": [{$this->code}]: {$this->message}\n";
}

public function customFunction() {


echo "A custom function for this type of exception\n";
}
}

/**
* Create a class to test the exception
*/
class TestException
{
public $var;

const THROW_NONE = 0;
const THROW_CUSTOM = 1;
const THROW_DEFAULT = 2;

function __construct($avalue = self::THROW_NONE) {

switch ($avalue) {
case self::THROW_CUSTOM:
// throw custom exception
throw new MyException('1 is an invalid parameter', 5);
break;

case self::THROW_DEFAULT:
// throw default one.
throw new Exception('2 is not allowed as a parameter', 6);
break;

default:
// No exception, object will be created.
$this->var = $avalue;
break;
}
}
}

// Example 1
try {
$o = new TestException(TestException::THROW_CUSTOM);
} catch (MyException $e) { // Will be caught
echo "Caught my exception\n", $e;
$e->customFunction();
} catch (Exception $e) { // Skipped
echo "Caught Default Exception\n", $e;
}

// Continue execution
var_dump($o); // Null
echo "\n\n";

// Example 2
try {
$o = new TestException(TestException::THROW_DEFAULT);
} catch (MyException $e) { // Doesn't match this type
echo "Caught my exception\n", $e;
$e->customFunction();
} catch (Exception $e) { // Will be caught
echo "Caught Default Exception\n", $e;
}

// Continue execution
var_dump($o); // Null
echo "\n\n";

// Example 3
try {
$o = new TestException(TestException::THROW_CUSTOM);
} catch (Exception $e) { // Will be caught
echo "Default Exception caught\n", $e;
}

// Continue execution
var_dump($o); // Null
echo "\n\n";

// Example 4
try {
$o = new TestException();
} catch (Exception $e) { // Skipped, no exception
echo "Default Exception caught\n", $e;
}

// Continue execution
var_dump($o); // TestException
echo "\n\n";
?>

31. Fibrele
Important Fibrele reprezintă funcții full-stack, întreruptibile. Fibrele pot fi suspendate de oriunde în
stiva de apeluri, întrerupând execuția în interiorul fibrei până când fibra este reluată la un moment
ulterior. Fibrele pun în pauză întreaga stivă de execuție, astfel încât apelantul direct al funcției nu
trebuie să schimbe modul în care invocă funcția. Execuția poate fi întreruptă oriunde în stiva de
apeluri folosind Fiber::suspend() (adică apelul la Fiber::suspend() poate fi într-o funcție profund
imbricată sau chiar să nu existe deloc).
Important Spre deosebire de generatoarele fără stivă, fiecare fibră are propria sa stivă de apeluri,
permițându-le să fie întrerupte în apeluri de funcții imbricate profund. O funcție care declară un
punct de întrerupere (adică apelând Fiber::suspend()) nu trebuie să își schimbe tipul de returnare,
spre deosebire de o funcție care utilizează yield care trebuie să returneze o instanță Generator.
Important Fibrele pot fi suspendate în orice apel de funcție, inclusiv cele apelate din cadrul PHP
VM, cum ar fi funcțiile furnizate către array_map() sau metodele apelate de foreach pe un obiect
Iterator.
Important Odată suspendată, execuția fibrei poate fi reluată cu orice valoare folosind
Fiber::resume() sau prin aruncarea unei excepții în fibră folosind Fiber::throw(). Valoarea este
returnată (sau o excepție aruncată) din Fiber::suspend().

<?php
$fiber = new Fiber(function (): void {
$value = Fiber::suspend('fiber');
echo "Value used to resume fiber: ", $value, PHP_EOL;
});
$value = $fiber->start();

echo "Value from fiber suspending: ", $value, PHP_EOL;

$fiber->resume('test');
?>

31. Generatoarele
Important Generatoarele oferă o modalitate ușoară de implementare a iteratoarelor simple, fără
costul general sau complexitatea implementării unei clase care implementează interfața Iterator.
Important Un generator oferă o modalitate convenabilă de a furniza date pentru fiecare bucle fără a
fi nevoie să construiți o matrice în memorie înainte de timp, ceea ce poate face ca programul să
depășească o limită de memorie sau să necesite o cantitate considerabilă de timp de procesare
pentru a genera. În schimb, poate fi utilizată o funcție de generator, care este aceeași cu o funcție
normală, cu excepția faptului că, în loc să revină o dată, un generator poate produce de câte ori este
nevoie pentru a furniza valorile pe care să le iterați. Ca și în cazul iteratoarelor, accesul la date
aleatoriu nu este posibil.
Important Un exemplu simplu în acest sens este reimplementarea funcției range() ca generator.
Funcția standard range() trebuie să genereze o matrice cu fiecare valoare din ea și să o returneze,
ceea ce poate duce la matrice mari: de exemplu, apelarea range(0, 1000000) va avea ca rezultat
folosirea a peste 100 MB de memorie.
Important Ca alternativă, putem implementa un generator xrange(), care va avea nevoie doar de
suficientă memorie pentru a crea un obiect Iterator și a urmări starea curentă a generatorului în
interior, care se dovedește a fi mai mică de 1 kilobyte.

<?php
function xrange($start, $limit, $step = 1) {
if ($start <= $limit) {
if ($step <= 0) {
throw new LogicException('Step must be positive');
}

for ($i = $start; $i <= $limit; $i += $step) {


yield $i;
}
} else {
if ($step >= 0) {
throw new LogicException('Step must be negative');
}

for ($i = $start; $i >= $limit; $i += $step) {


yield $i;
}
}
}
/*
* Note that both range() and xrange() result in the same
* output below.
*/
echo 'Single digit odd numbers from range(): ';
foreach (range(1, 9, 2) as $number) {
echo "$number ";
}
echo "\n";

echo 'Single digit odd numbers from xrange(): ';


foreach (xrange(1, 9, 2) as $number) {
echo "$number ";
}
?>
Important Când este apelată o funcție generator, este returnat un nou obiect din clasa internă
Generator. Acest obiect implementează interfața Iterator în aproape același mod ca un obiect iterator
numai înainte și oferă metode care pot fi apelate pentru a manipula starea generatorului, inclusiv
trimiterea și returnarea valorilor de la acesta.

Important O funcție de generator arată exact ca o funcție normală, cu excepția faptului că, în loc să
returneze o valoare, un generator dă atâtea valori cât are nevoie. Orice funcție care conține
randament este o funcție generatoare.
Important Când o funcție generatoare este apelată, returnează un obiect care poate fi iterat. Când
iterați peste acel obiect (de exemplu, printr-o buclă foreach), PHP va apela metodele de iterație ale
obiectului de fiecare dată când are nevoie de o valoare, apoi salvează starea generatorului când
generatorul dă o valoare, astfel încât aceasta să poată fi reluată când este necesară următoarea
valoare.
Important Odată ce nu mai sunt valori care să fie date, atunci generatorul se poate întoarce pur și
simplu, iar codul de apel continuă exact ca și cum o matrice a rămas fără valori.
Important Inima unei funcții generatoare este cuvântul cheie yield. În forma sa cea mai simplă, o
instrucțiune yield seamănă mult cu o instrucțiune return, cu excepția faptului că, în loc să oprească
execuția funcției și să revină, yield oferă o valoare buclei codului peste generator și întrerupe
execuția funcției generatorului.

<?php
function gen_one_to_three() {
for ($i = 1; $i <= 3; $i++) {
// Note that $i is preserved between yields.
yield $i;
}
}

$generator = gen_one_to_three();
foreach ($generator as $value) {
echo "$value\n";
}
?>

Important PHP suportă, de asemenea, matrice asociative, iar generatoarele nu sunt diferite. Pe lângă
obținerea unor valori simple, așa cum se arată mai sus, puteți obține și o cheie în același timp.

<?php
/*
* The input is semi-colon separated fields, with the first
* field being an ID to use as a key.
*/

$input = <<<'EOF'
1;PHP;Likes dollar signs
2;Python;Likes whitespace
3;Ruby;Likes blocks
EOF;

function input_parser($input) {
foreach (explode("\n", $input) as $line) {
$fields = explode(';', $line);
$id = array_shift($fields);
yield $id => $fields;
}
}

foreach (input_parser($input) as $id => $fields) {


echo "$id:\n";
echo " $fields[0]\n";
echo " $fields[1]\n";
}
?>

Important Yield poate fi apelat fără un argument pentru a produce o valoare nulă cu o cheie
automată.

<?php
function gen_three_nulls() {
foreach (range(1, 3) as $i) {
yield;
}
}

var_dump(iterator_to_array(gen_three_nulls()));
?>

Important Funcțiile generatorului sunt capabile să furnizeze valori atât prin referință, cât și prin
valoare. Acest lucru se face în același mod ca și returnarea referințelor din funcții: prin adăugarea
unui ampersand la numele funcției.

<?php
function &gen_reference() {
$value = 3;

while ($value > 0) {


yield $value;
}
}

/*
* Note that we can change $number within the loop, and
* because the generator is yielding references, $value
* within gen_reference() changes.
*/
foreach (gen_reference() as &$number) {
echo (--$number).'... ';
}
?>

Important Delegarea generatorului vă permite să obțineți valori de la un alt generator, obiect


traversabil sau matrice utilizând cuvântul cheie yield from. Generatorul exterior va furniza apoi
toate valorile din generatorul interior, obiectul sau tabloul până când acesta nu mai este valabil,
după care execuția va continua în generatorul exterior. Dacă se folosește un generator cu yield from,
expresia yield from va returna, de asemenea, orice valoare returnată de generatorul interior.
Important yield from nu resetează cheile. Păstrează cheile returnate de obiectul Traversable sau
matrice. Astfel, unele valori pot împărtăși o cheie comună cu un alt randament sau randament de la,
care, la inserarea într-o matrice, va suprascrie valorile anterioare cu acea cheie.
Important Un caz obișnuit în care acest lucru contează este iterator_to_array() care returnează
implicit o matrice cu cheie, ceea ce duce la rezultate posibil neașteptate. iterator_to_array() are un al
doilea parametru preserve_keys care poate fi setat la false pentru a colecta toate valorile ignorând
cheile returnate de Generator.

<?php
function inner() {
yield 1; // key 0
yield 2; // key 1
yield 3; // key 2
}
function gen() {
yield 0; // key 0
yield from inner(); // keys 0-2
yield 4; // key 1
}
// pass false as second parameter to get an array [0, 1, 2, 3, 4]
var_dump(iterator_to_array(gen()));
?>

<?php
function count_to_ten() {
yield 1;
yield 2;
yield from [3, 4];
yield from new ArrayIterator([5, 6]);
yield from seven_eight();
yield 9;
yield 10;
}
function seven_eight() {
yield 7;
yield from eight();
}
function eight() {
yield 8;
}
foreach (count_to_ten() as $num) {
echo "$num ";
}
?>

Important Avantajul principal al generatoarelor este simplitatea lor. Trebuie scris mult mai puțin cod
standard în comparație cu implementarea unei clase Iterator, iar codul este în general mult mai
lizibil. De exemplu, următoarele funcție și clasă sunt echivalente:

<?php
function getLinesFromFile($fileName) {
if (!$fileHandle = fopen($fileName, 'r')) {
return;
}

while (false !== $line = fgets($fileHandle)) {


yield $line;
}

fclose($fileHandle);
}

// versus...

class LineIterator implements Iterator {


protected $fileHandle;
protected $line;
protected $i;

public function __construct($fileName) {


if (!$this->fileHandle = fopen($fileName, 'r')) {
throw new RuntimeException('Couldn\'t open file "' . $fileName . '"');
}
}

public function rewind() {


fseek($this->fileHandle, 0);
$this->line = fgets($this->fileHandle);
$this->i = 0;
}

public function valid() {


return false !== $this->line;
}

public function current() {


return $this->line;
}

public function key() {


return $this->i;
}

public function next() {


if (false !== $this->line) {
$this->line = fgets($this->fileHandle);
$this->i++;
}
}

public function __destruct() {


fclose($this->fileHandle);
}
}
?>

Important Cu toate acestea, această flexibilitate are un cost: generatoarele sunt iteratoare doar
înainte și nu pot fi rebobinate odată ce iterația a început. Aceasta înseamnă, de asemenea, că același
generator nu poate fi repetat de mai multe ori: generatorul va trebui reconstruit apelând din nou
funcția generator.

31. Atributele
Important Atributele oferă posibilitatea de a adăuga informații de metadate structurate, citibile de
mașină, despre declarațiile din cod: Clasele, metodele, funcțiile, parametrii, proprietățile și
constantele de clasă pot fi ținta unui atribut. Metadatele definite de atribute pot fi apoi inspectate în
timpul execuției folosind API-urile Reflection. Prin urmare, atributele ar putea fi gândite ca un
limbaj de configurare încorporat direct în cod.
Important Cu atribute, implementarea generică a unei caracteristici și utilizarea sa concretă într-o
aplicație pot fi decuplate. Într-un fel, este comparabil cu interfețele și implementările acestora. Dar
acolo unde interfețele și implementările sunt despre cod, atributele se referă la adnotarea
informațiilor suplimentare și a configurației. Interfețele pot fi implementate prin clase, dar atributele
pot fi declarate și pe metode, funcții, parametri, proprietăți și constante de clasă. Ca atare, ele sunt
mai flexibile decât interfețele.
Important Un exemplu simplu de utilizare a atributelor este convertirea unei interfețe care are
metode opționale de utilizare a atributelor. Să presupunem o interfață ActionHandler reprezentând o
operație într-o aplicație, unde unele implementări ale unui handler de acțiuni necesită setare, iar
altele nu. În loc să ceară tuturor claselor care implementează ActionHandler să implementeze o
metodă setUp(), poate fi folosit un atribut. Un avantaj al acestei abordări este că putem folosi
atributul de mai multe ori.

<?php
interface ActionHandler
{
public function execute();
}

#[Attribute]
class SetUp {}

class CopyFile implements ActionHandler


{
public string $fileName;
public string $targetDirectory;
#[SetUp]
public function fileExists()
{
if (!file_exists($this->fileName)) {
throw new RuntimeException("File does not exist");
}
}
#[SetUp]
public function targetDirectoryExists()
{
if (!file_exists($this->targetDirectory)) {
mkdir($this->targetDirectory);
} elseif (!is_dir($this->targetDirectory)) {
throw new RuntimeException("Target directory $this->targetDirectory is not
a directory");
}
}

public function execute()


{
copy($this->fileName, $this->targetDirectory . '/' . basename($this->fileName));
}
}

function executeAction(ActionHandler $actionHandler)


{
$reflection = new ReflectionObject($actionHandler);

foreach ($reflection->getMethods() as $method) {


$attributes = $method->getAttributes(SetUp::class);
if (count($attributes) > 0) {
$methodName = $method->getName();
$actionHandler->$methodName();
}
}

$actionHandler->execute();
}

$copyAction = new CopyFile();


$copyAction->fileName = "/tmp/[Link]";
$copyAction->targetDirectory = "/home/user";

executeAction($copyAction);

Important Există mai multe părți în sintaxa atributelor. În primul rând, o declarație de atribut este
întotdeauna inclusă cu un început #[ și o sfârșit corespunzătoare]. În interior, sunt listate unul sau
mai multe atribute, separate prin virgulă. Numele atributului este un nume necalificat, calificat sau
complet calificat, așa cum este descris în Noțiuni de bază despre utilizarea spațiilor de nume.
Argumentele pentru atribut sunt opționale, dar sunt incluse în parantezele obișnuite (). Argumentele
la atribute pot fi doar valori literale sau expresii constante. Pot fi utilizate atât sintaxa argumentelor
poziționale, cât și denumite.
Important Numele atributelor și argumentele lor sunt rezolvate într-o clasă, iar argumentele sunt
transmise constructorului acesteia, atunci când o instanță a atributului este solicitată prin API-ul
Reflection. Ca atare, ar trebui introdusă o clasă pentru fiecare atribut.

<?php
// [Link]
namespace MyExample;

use Attribute;

#[Attribute]
class MyAttribute
{
const VALUE = 'value';

private $value;

public function __construct($value = null)


{
$this->value = $value;
}
}

// [Link]

namespace Another;

use MyExample\MyAttribute;

#[MyAttribute]
#[\MyExample\MyAttribute]
#[MyAttribute(1234)]
#[MyAttribute(value: 1234)]
#[MyAttribute(MyAttribute::VALUE)]
#[MyAttribute(array("key" => "value"))]
#[MyAttribute(100 + 200)]
class Thing
{
}

#[MyAttribute(1234), MyAttribute(5678)]
class AnotherThing
{}

Important Pentru a accesa atribute din clase, metode, funcții, parametri, proprietăți și constante de
clasă, API-ul Reflection oferă metoda getAttributes() pentru fiecare dintre obiectele Reflection
corespunzătoare. Această metodă returnează o serie de instanțe ReflectionAttribute care pot fi
interogate pentru numele atributului, argumente și pentru a instanția o instanță a atributului
reprezentat.
Important Această separare a reprezentării atributelor reflectate de instanța reală mărește controlul
programatorului pentru a gestiona erorile privind clasele de atribute lipsă, argumentele greșite sau
lipsa. Numai după apelarea ReflectionAttribute::newInstance(), obiectele clasei de atribute sunt
instanțiate și potrivirea corectă a argumentelor este validată, nu mai devreme.

<?php

#[Attribute]
class MyAttribute
{
public $value;

public function __construct($value)


{
$this->value = $value;
}
}

#[MyAttribute(value: 1234)]
class Thing
{
}

function dumpAttributeData($reflection) {
$attributes = $reflection->getAttributes();

foreach ($attributes as $attribute) {


var_dump($attribute->getName());
var_dump($attribute->getArguments());
var_dump($attribute->newInstance());
}
}

dumpAttributeData(new ReflectionClass(Thing::class));
/*
string(11) "MyAttribute"
array(1) {
["value"]=>
int(1234)
}
object(MyAttribute)#3 (1) {
["value"]=>
int(1234)
}
*/
Important În loc să iterați toate atributele din instanța de reflectare, numai cele ale unei anumite
clase de atribute pot fi preluate prin trecerea numelui clasei de atribute căutate ca argument.
<?php
function dumpMyAttributeData($reflection) {
$attributes = $reflection->getAttributes(MyAttribute::class);
foreach ($attributes as $attribute) {
var_dump($attribute->getName());
var_dump($attribute->getArguments());
var_dump($attribute->newInstance());
}
}
dumpMyAttributeData(new ReflectionClass(Thing::class));

Important Deși nu este strict necesar, se recomandă crearea unei clase reale pentru fiecare atribut. În
cel mai simplu caz este necesară doar o clasă goală cu atributul #[Attribut] declarat, care poate fi
importat din spațiul de nume global cu o instrucțiune use
<?php

namespace Example;

use Attribute;

#[Attribute]
class MyAttribute
{
}

Important Pentru a restricționa tipul de declarație căruia i se poate atribui un atribut, o mască de biți
poate fi transmisă ca prim argument în declarația #[Atribut].

<?php

namespace Example;

use Attribute;

#[Attribute(Attribute::TARGET_METHOD | Attribute::TARGET_FUNCTION)]
class MyAttribute
{
}

Important Declararea MyAttribute pe alt tip va genera acum o excepție în timpul apelului la
ReflectionAttribute::newInstance()
Important Pot fi specificate următoarele obiective:
Attribute::TARGET_CLASS
• Attribute::TARGET_FUNCTION
• Attribute::TARGET_METHOD
• Attribute::TARGET_PROPERTY
• Attribute::TARGET_CLASS_CONSTANT
• Attribute::TARGET_PARAMETER
• Attribute::TARGET_ALL

Important În mod implicit, un atribut poate fi folosit o singură dată pe declarație. Dacă atributul ar
trebui să fie repetabil în declarații, acesta trebuie specificat ca parte a măștii de biți în declarația
#[Atribut].
<?php
namespace Example;
use Attribute;
#[Attribute(Attribute::TARGET_METHOD | Attribute::TARGET_FUNCTION |
Attribute::IS_REPEATABLE)]
class MyAttribute
{
}
33. Referintele

Important Referințele în PHP sunt un mijloc de a accesa același conținut variabil cu nume diferite.
Nu sunt ca pointerii C; de exemplu, nu puteți efectua aritmetica pointer folosindu-le, nu sunt adrese
de memorie reale și așa mai departe.

Important După cum s-a spus anterior, referințele nu sunt indicatoare. Aceasta înseamnă că
următorul construct nu va face ceea ce vă așteptați:

<?php

function foo(&$var)
{
$var =& $GLOBALS["baz"];
}

foo($bar);

?>

Important Ce se întâmplă este că $var în foo va fi legat cu $bar în apelant, dar apoi relegat cu
$GLOBALS["baz"]. Nu există nicio modalitate de a lega $bar în domeniul de apelare la altceva
folosind mecanismul de referință, deoarece $bar nu este disponibil în funcția foo (este reprezentat
de $var, dar $var are doar conținut variabil și nu nume-to- valoarea obligatorie în tabelul cu
simboluri de apelare). Puteți utiliza referințe returnate la variabilele de referință selectate de funcție.

Important Există trei operații de bază efectuate folosind referințe: atribuirea prin referință, trecerea
prin referință și returnarea prin referință.

Important Referințele PHP vă permit să faceți două variabile să se refere la același conținut. Adică
$a și $b indică același conținut daca:

<?php $a =& $b; ?>

Important Dacă atribuiți, transmiteți sau returnați o variabilă nedefinită prin referință, aceasta va fi
creată.

<?php

function foo(&$var) {}

foo($a); // $a is "created" and assigned to null

$b = array();
foo($b['b']);
var_dump(array_key_exists('b', $b)); // bool(true)

$c = new stdClass();
foo($c->d);
var_dump(property_exists($c, 'd')); // bool(true)

?>
Important Dacă atribuiți o referință unei variabile declarate globală în interiorul unei funcții,
referința va fi vizibilă numai în interiorul funcției. Puteți evita acest lucru folosind matricea
$GLOBALS.

<?php

$var1 = "Example variable";


$var2 = "";

function global_references($use_globals)
{
global $var1, $var2;

if (!$use_globals) {
$var2 =& $var1; // visible only inside the function
} else {
$GLOBALS["var2"] =& $var1; // visible also in global context
}
}

global_references(false);
echo "var2 is set to '$var2'\n"; // var2 is set to ''

global_references(true);
echo "var2 is set to '$var2'\n"; // var2 is set to 'Example variable'

?>

Important Dacă atribuiți o valoare unei variabile cu referințe într-o instrucțiune foreach, referințele
sunt și ele modificate.

<?php

$ref = 0;
$row =& $ref;

foreach (array(1, 2, 3) as $row) {


// Do something
}

echo $ref; // 3 - last element of the iterated array

?>

Important Deși nu sunt strict o atribuire prin referință, expresiile create cu limbajul construct array()
se pot comporta și ca atare prin prefixarea & la elementul de matrice de adăugat. Exemplu:

<?php

$a = 1;
$b = array(2, 3);
$arr = array(&$a, &$b[0], &$b[1]);
$arr[0]++;
$arr[1]++;
$arr[2]++;
/* $a == 2, $b == array(3, 4); */

?>

Important Rețineți, totuși, că referințele din interiorul matricelor sunt potențial periculoase.
Efectuarea unei asignari normale (nu prin referință) cu o referință în partea dreaptă nu transformă
partea stângă într-o referință, dar referințele din interiorul matricelor sunt păstrate în aceste atribuiri
normale.

<?php

/* Assignment of scalar variables */


$a = 1;
$b =& $a;
$c = $b;
$c = 7; // $c is not a reference; no change to $a or $b
/* Assignment of array variables */
$arr = array(1);
$a =& $arr[0]; // $a and $arr[0] are in the same reference set
$arr2 = $arr; // Not an assignment-by-reference!
$arr2[0]++;
/* $a == 2, $arr == array(2) */
/* The contents of $arr are changed even though it's not a reference! */

?>

Important Următoarele lucruri pot fi trecute prin referință:


• Variabile, adică foo($a)
• Referințe returnate de la funcții, adică:

<?php

function foo(&$var)
{
$var++;
}

function &bar()
{
$a = 5;
return $a;
}

foo(bar());

?>
Important Revenirea prin referință este utilă atunci când doriți să utilizați o funcție pentru a găsi la
ce variabilă trebuie legată o referință. Nu utilizați returnarea prin referință pentru a crește
performanța. Motorul va optimiza automat acest lucru singur. Returnați referințele numai atunci
când aveți un motiv tehnic valid pentru a face acest lucru. Pentru a returna referințe, utilizați această
sintaxă:

<?php

class Foo
{
public $value = 42;

public function &getValue()


{
return $this->value;
}
}

$obj = new Foo();


$myValue = &$obj->getValue(); // $myValue is a reference to $obj->value, which is 42
$obj->value = 2;
echo $myValue; // Prints the new value of $obj->value, i.e. 2

?>

Important În acest exemplu, proprietatea obiectului returnat de funcția getValue ar fi setată, nu


copia, așa cum ar fi fără a utiliza sintaxa de referință.

Important Spre deosebire de transmiterea parametrilor, aici trebuie să utilizați & în ambele locuri -
pentru a indica că doriți să returnați prin referință, nu o copie, și pentru a indica că legarea
referințelor, mai degrabă decât atribuirea obișnuită, ar trebui făcută pentru $myValue.

Important Dacă încercați să returnați o referință dintr-o funcție cu sintaxa: return ($this->value);
acest lucru nu va funcționa deoarece încercați să returnați rezultatul unei expresii, și nu o variabilă,
prin referință. Puteți returna variabile doar prin referință dintr-o funcție - nimic altceva.

Important Pentru a utiliza referința returnată, trebuie să utilizați atribuirea referințelor:

<?php

function &collector()
{
static $collection = array();
return $collection;
}

$collection = &collector();
$collection[] = 'foo';

?>
Important Pentru a transmite referința returnată unei alte funcții care așteaptă o referință, puteți
utiliza această sintaxă:
<?php

function &collector()
{
static $collection = array();
return $collection;
}

array_push(collector(), 'foo');

?>

Important Când anulați referința, doar întrerupeți legătura dintre numele variabilei și conținutul
variabilei. Acest lucru nu înseamnă că conținutul variabil va fi distrus. De exemplu, nu va anula $b,
doar $a.:
<?php

$a = 1;
$b =& $a;
unset($a);

?>

Important Multe construcții de sintaxă în PHP sunt implementate prin mecanisme de referință, așa
că tot ce este menționat aici despre legarea referințelor se aplică și acestor construcții. Unele
constructe, cum ar fi trecerea și întoarcerea prin referință, sunt menționate mai sus. Alte constructe
care folosesc referințe sunt:
<?php

$var =& $GLOBALS["var"];

?>

34. Variabile predefinite


Superglobals — Variabile încorporate care sunt întotdeauna disponibile în toate domeniile
$GLOBALS — Se referă la toate variabilele disponibile în domeniul global
$_SERVER — Informații despre server și mediul de execuție
$_GET — variabile HTTP GET
$_POST — variabile HTTP POST
$_FILES — Variabile de încărcare fișier HTTP
$_REQUEST — Variabile de solicitare HTTP
$_SESSION — Variabile de sesiune
$_ENV — Variabile de mediu
$_COOKIE — Cookie-uri HTTP
$php_errormsg — Mesajul de eroare anterior
$http_response_header — Anteturi de răspuns HTTP
$argc — Numărul de argumente transmise scriptului
$argv — Matrice de argumente transmise scriptului
34. Securitate

Important Folosirea PHP ca binar CGI este o opțiune pentru setările care, dintr-un motiv oarecare,
nu doresc să integreze PHP ca modul în software-ul server (cum ar fi Apache), sau vor folosi PHP
cu diferite tipuri de wrapper CGI pentru a crea medii sigure pentru chroot și setuid. scenarii.
Această configurare implică de obicei instalarea binarului php executabil în directorul serverului
web cgi-bin. Aviz CERT » CA-96.11 nu recomandă plasarea oricăror interpreți în cgi-bin. Chiar
dacă binarul php poate fi folosit ca interpret independent, PHP este conceput pentru a preveni
atacurile pe care această configurare le face posibile:
• Accesarea fișierelor de sistem: [Link] Informațiile de
interogare dintr-un URL după semnul întrebării (?) sunt transmise interpretului ca argumente
de linie de comandă de către interfața CGI. De obicei, interpreții deschid și execută fișierul
specificat ca prim argument pe linia de comandă. Când este invocat ca binar CGI, php
refuză să interpreteze argumentele liniei de comandă.
• Accesarea oricărui document web de pe server: [Link]
Partea cu informații despre cale a adresei URL după numele binar PHP, /secret/[Link] este
utilizată în mod convențional pentru a specifica numele fișierului care urmează să fie
deschis și interpretat de programul CGI. De obicei, unele directive de configurare a
serverului web (Apache: Action) sunt folosite pentru a redirecționa cererile către documente
precum [Link] către interpretul PHP. Cu această configurare,
serverul web verifică mai întâi permisiunile de acces la directorul /secret, iar după aceea
creează cererea redirecționată [Link] Din păcate, dacă
cererea este dată inițial în acest formular, serverul web nu face verificări de acces pentru
fișierul /secret/[Link], ci doar pentru fișierul /cgi-bin/php. În acest fel, orice utilizator
care poate accesa /cgi-bin/php poate accesa orice document protejat de pe serverul web. În
PHP, directivele de configurare a runtimei cgi.force_redirect, doc_root și user_dir pot fi
folosite pentru a preveni acest atac, dacă arborele documentului serverului are directoare cu
restricții de acces. Vezi mai jos explicația completă a diferitelor combinații.

Important Dacă serverul dvs. nu are niciun conținut care nu este restricționat de parolă sau de
controlul accesului bazat pe IP, nu este nevoie de aceste opțiuni de configurare. Dacă serverul dvs.
web nu vă permite să faceți redirecționări sau serverul nu are o modalitate de a comunica binarului
PHP că cererea este o solicitare redirecționată în siguranță, puteți activa directiva ini
cgi.force_redirect. Încă trebuie să vă asigurați că scripturile dvs. PHP nu se bazează pe una sau alta
modalitate de a apela scriptul, nici prin [Link] nici prin
redirecționarea http:/ /[Link]/dir/[Link].

Important Directiva de configurare cgi.force_redirect împiedică pe oricine să apeleze php direct cu


o adresă URL precum [Link] În schimb, PHP va analiza în
acest mod numai dacă a trecut printr-o regulă de redirecționare a serverului web.
Important De obicei, redirecționarea în configurația Apache se face cu următoarele directive:
Acțiune php-script /cgi-bin/php
AddHandler php-script .php
Important Această opțiune a fost testată doar cu serverul web Apache și se bazează pe Apache
pentru a seta variabila de mediu CGI non-standard REDIRECT_STATUS pentru cererile
redirecționate. Dacă serverul dvs. web nu acceptă nicio modalitate de a spune dacă cererea este
directă sau redirecționată, nu puteți utiliza această opțiune și trebuie să utilizați una dintre celelalte
moduri de a rula versiunea CGI documentată aici.

Important Includerea conținutului activ, cum ar fi scripturi și executabile, în directoarele de


documente ale serverului web este uneori considerată o practică nesigură. Dacă, din cauza unei erori
de configurare, scripturile nu sunt executate, ci afișate ca documente HTML obișnuite, acest lucru
poate duce la scurgerea de informații de proprietate intelectuală sau de securitate, cum ar fi parolele.
Prin urmare, mulți administratori de sistem vor prefera să creeze o altă structură de directoare
pentru scripturi care sunt accesibile numai prin PHP CGI și, prin urmare, întotdeauna interpretate și
nu afișate ca atare.

Important Puteți seta rădăcina documentului de script PHP prin directiva de configurare doc_root
din fișierul de configurare sau puteți seta variabila de mediu PHP_DOCUMENT_ROOT. Dacă este
setată, versiunea CGI a PHP va construi întotdeauna numele fișierului de deschis cu acest doc_root
și informațiile de cale din cerere, astfel încât să puteți fi sigur că nu este executat niciun script în
afara acestui director (cu excepția user_dir de mai jos).
Important O altă opțiune utilizabilă aici este user_dir. Când user_dir este nesetat, singurul lucru care
controlează numele fișierului deschis este doc_root. Deschiderea unei adrese URL precum
[Link] nu are ca rezultat deschiderea unui fișier în directorul principal al
utilizatorilor, ci a unui fișier numit ~user/[Link] sub doc_root (da, un nume de director care începe
cu o tildă [~]).
Important Dacă user_dir este setat, de exemplu, la public_php, o solicitare precum
[Link] va deschide un fișier numit [Link] în directorul denumit public_php
din directorul principal al utilizatorului. Dacă domiciliul utilizatorului este /home/user, fișierul
executat este /home/user/public_php/[Link].
Important Extinderea user_dir are loc indiferent de setarea doc_root, astfel încât puteți controla
separat accesul la rădăcina documentului și la directorul utilizatorului.

Important O opțiune foarte sigură este să puneți binarul parser PHP undeva în afara arborelui web al
fișierelor. În /usr/local/bin, de exemplu. Singurul dezavantaj real al acestei opțiuni este că acum va
trebui să puneți o linie similară cu: #!/usr/local/bin/php ca prima linie a oricărui fișier care conține
etichete PHP. De asemenea, va trebui să faceți fișierul executabil. Adică, tratați-l exact așa cum ați
trata orice alt script CGI scris în Perl sau sh sau orice alt limbaj de scripting comun care utilizează
#! mecanism de evacuare a carcasei pentru lansare.
Important Pentru ca PHP să gestioneze corect informațiile PATH_INFO și PATH_TRANSLATED
cu această setare, directiva ini cgi.discard_path trebuie să fie activată.

Important Deoarece PHP a fost conceput pentru a permite accesul la nivel de utilizator la sistemul
de fișiere, este complet posibil să scrieți un script PHP care vă va permite să citiți fișiere de sistem,
cum ar fi /etc/passwd, să vă modificați conexiunile Ethernet, să trimiteți lucrări masive de
imprimantă etc. are unele implicații evidente, prin aceea că trebuie să vă asigurați că fișierele din
care citiți și în care scrieți sunt cele adecvate.

<?php

// Remove a file from the user's home directory


$username = $_POST['user_submitted_name'];
$userfile = $_POST['user_submitted_filename'];
$homedir = "/home/$username";

unlink("$homedir/$userfile");

echo "The file has been deleted!";

?>
Important Deoarece numele de utilizator și numele fișierului pot fi postate dintr-un formular de
utilizator, aceștia pot trimite un nume de utilizator și un nume de fișier aparținând altcuiva și le pot
șterge chiar dacă nu ar trebui să li se permită să facă acest lucru. În acest caz, ați dori să utilizați o
altă formă de autentificare. Luați în considerare ce s-ar putea întâmpla dacă variabilele trimise ar fi
„../etc/” și „passwd”. Codul ar citi în mod efectiv:

<?php

// Removes a file from anywhere on the hard drive that


// the PHP user has access to. If PHP has root access:
$username = $_POST['user_submitted_name']; // "../etc"
$userfile = $_POST['user_submitted_filename']; // "passwd"
$homedir = "/home/$username"; // "/home/../etc"

unlink("$homedir/$userfile"); // "/home/../etc/passwd"

echo "The file has been deleted!";

?>

Important Există două măsuri importante pe care ar trebui să le luați pentru a preveni aceste
probleme.
• Permiteți numai permisiuni limitate pentru binarul utilizatorului web PHP.
• Verificați toate variabilele care sunt trimise.

<?php

// Removes a file from the hard drive that


// the PHP user has access to.
$username = $_SERVER['REMOTE_USER']; // using an authentication mechanism
$userfile = basename($_POST['user_submitted_filename']);
$homedir = "/home/$username";

$filepath = "$homedir/$userfile";

if (file_exists($filepath) && unlink($filepath)) {


$logstring = "Deleted $filepath\n";
} else {
$logstring = "Failed to delete $filepath\n";
}

$fp = fopen("/home/logging/[Link]", "a");


fwrite($fp, $logstring);
fclose($fp);

echo htmlentities($logstring, ENT_QUOTES);

?>
Important Cu toate acestea, chiar și acest lucru nu este lipsit de defecte. Dacă sistemul dvs. de
autentificare a permis utilizatorilor să-și creeze propriile autentificări de utilizator și un utilizator a
ales autentificarea „../etc/”, sistemul este din nou expus. Din acest motiv, este posibil să preferați să
scrieți un cec mai personalizat:

<?php

$username = $_SERVER['REMOTE_USER']; // using an authentication mechanisim


$userfile = $_POST['user_submitted_filename'];
$homedir = "/home/$username";

$filepath = "$homedir/$userfile";

if (!ctype_alnum($username) || !preg_match('/^(?:[a-z0-9_-]|\.(?!\.))+$/iD', $userfile)) {


die("Bad username/filename");
}

// etc.

?>

Important În funcție de sistemul dvs. de operare, există o mare varietate de fișiere de care ar trebui
să vă îngrijorați, inclusiv intrările dispozitivului (/dev/ sau COM1), fișierele de configurare
(fișiere /etc/ și fișierele .ini), zone de stocare a fișierelor bine cunoscute. (/home/, Documentele
mele), etc. Din acest motiv, este de obicei mai ușor să creați o politică în care interziceți totul, cu
excepția a ceea ce permiteți în mod explicit.

Important Primul pas este întotdeauna să creați baza de date, cu excepția cazului în care doriți să
utilizați una de la o terță parte. Atunci când o bază de date este creată, aceasta este atribuită unui
proprietar, care a executat instrucțiunea de creare. De obicei, doar proprietarul (sau un
superutilizator) poate face orice cu obiectele din acea bază de date, iar pentru a permite altor
utilizatori să o folosească, trebuie acordate privilegii.
Important Aplicațiile nu ar trebui să se conecteze niciodată la baza de date ca proprietar sau
superutilizator, deoarece acești utilizatori pot executa orice interogare după bunul plac, de exemplu,
modificând schema (de exemplu, eliminarea tabelelor) sau ștergerea întregului conținut.

Important SSL/SSH protejează datele care călătoresc de la client la server: SSL/SSH nu protejează
datele persistente stocate într-o bază de date. SSL este un protocol on-the-wire.
Important Odată ce un atacator obține acces direct la baza ta de date (ocolind serverul web), datele
sensibile stocate pot fi expuse sau utilizate greșit, cu excepția cazului în care informațiile sunt
protejate de baza de date în sine. Criptarea datelor este o modalitate bună de a atenua această
amenințare, dar foarte puține baze de date oferă acest tip de criptare a datelor.

Important În cazul datelor cu adevărat ascunse, dacă reprezentarea lor brută nu este necesară (adică
nu va fi afișată), ar trebui să se ia în considerare hashingul. Exemplul binecunoscut de hashing este
stocarea hash-ului criptografic al unei parole într-o bază de date, în locul parolei în sine.
Important Funcțiile de parolă oferă o modalitate convenabilă de hashare a datelor sensibile și de a
lucra cu aceste hashuri.
Important password_hash() este folosită pentru a distribui un anumit șir folosind cel mai puternic
algoritm disponibil în prezent și password_verify() verifică dacă parola dată se potrivește cu hash-ul
stocat în baza de date.
<?php

// storing password hash


$query = sprintf("INSERT INTO users(name,pwd) VALUES('%s','%s');",
pg_escape_string($username),
password_hash($password, PASSWORD_DEFAULT));
$result = pg_query($connection, $query);

// querying if user submitted the right password


$query = sprintf("SELECT pwd FROM users WHERE name='%s';",
pg_escape_string($username));
$row = pg_fetch_assoc(pg_query($connection, $query));

if ($row && password_verify($password, $row['pwd'])) {


echo 'Welcome, ' . htmlspecialchars($username) . '!';
} else {
echo 'Authentication failed for ' . htmlspecialchars($username) . '.';
}

?>

Important Injecția SQL este o tehnică în care un atacator exploatează defecte în codul aplicației
responsabil pentru construirea de interogări SQL dinamice. Atacatorul poate obține acces la
secțiunile privilegiate ale aplicației, poate prelua toate informațiile din baza de date, poate modifica
datele existente sau chiar poate executa comenzi periculoase la nivel de sistem pe gazda bazei de
date. Vulnerabilitatea apare atunci când dezvoltatorii concatenează sau interpolează intrări arbitrare
în instrucțiunile lor SQL.

<?php

$offset = $_GET['offset']; // beware, no input validation!


$query = "SELECT id, name FROM products ORDER BY name LIMIT 20 OFFSET $offset;";
$result = pg_query($conn, $query);

?>

Important Utilizatorii obișnuiți dau clic pe linkurile „următorul”, „prev” unde $offset-ul este
codificat în adresa URL. Scriptul se așteaptă ca $offset-ul primit să fie un număr. Cu toate acestea,
ce se întâmplă dacă cineva încearcă să intre adăugând următoarele la adresa URL.

Important O modalitate fezabilă de a obține parole este să ocoliți paginile cu rezultatele căutării.
Singurul lucru pe care trebuie să-l facă atacatorul este să vadă dacă există variabile trimise utilizate
în instrucțiunile SQL care nu sunt gestionate corect. Aceste filtre pot fi setate în mod obișnuit într-o
formă anterioară pentru a personaliza clauzele WHERE, ORDER BY, LIMIT și OFFSET în
instrucțiunile SELECT. Dacă baza de date acceptă construcția UNION, atacatorul poate încerca să
atașeze o interogare întreagă la cea originală pentru a lista parolele dintr-un tabel arbitrar. Se
recomandă insistent să stocați numai coduri hash securizate ale parolelor în loc de parolele în sine.
<?php
$query = "SELECT id, name, inserted, size FROM products
WHERE size = '$size'";
$result = odbc_exec($conn, $query);
?>
Important Dacă un utilizator rău intenționat trimite valoarea „sau uid like”%admin% la $uid pentru
a schimba parola administratorului sau pur și simplu setează $pwd la hehehe', trusted=100,
admin='yes pentru a obține mai multe privilegii, atunci interogarea va fi fi răsucit:

<?php

// $uid: ' or uid like '%admin%


$query = "UPDATE usertable SET pwd='...' WHERE uid='' or uid like '%admin%';";

// $pwd: hehehe', trusted=100, admin='yes


$query = "UPDATE usertable SET pwd='hehehe', trusted=100, admin='yes' WHERE
...;";

?>

Important Deși rămâne evident că un atacator trebuie să posede cel puțin cunoștințe despre
arhitectura bazei de date pentru a efectua un atac cu succes, obținerea acestor informații este adesea
foarte simplă. De exemplu, codul poate face parte dintr-un software open-source și poate fi
disponibil public. Aceste informații pot fi, de asemenea, divulgate prin cod sursă închisă - chiar
dacă sunt codificate, ofucate sau compilate - și chiar prin propriul cod prin afișarea mesajelor de
eroare. Alte metode includ utilizarea numelor tipice de tabele și coloane. De exemplu, un formular
de conectare care utilizează un tabel „utilizatori” cu nume de coloană „id”, „nume utilizator” și
„parolă”.

<?php

$query = "SELECT * FROM products WHERE id LIKE '%$prod%'";


$result = mssql_query($query);

?>

Important Dacă atacatorul trimite valoarea a%' exec master..xp_cmdshell 'net user test testpass
/ADD' -- la $prod, atunci $query va fi:

<?php

$query = "SELECT * FROM products


WHERE id LIKE '%a%'
exec master..xp_cmdshell 'net user test testpass /ADD' --%'";
$result = mssql_query($query);

?>

Important MSSQL Server execută instrucțiunile SQL în lot, inclusiv o comandă pentru a adăuga un
nou utilizator la baza de date locală de conturi. Dacă această aplicație rula ca sa și serviciul
MSSQLSERVER rula cu suficiente privilegii, atacatorul ar avea acum un cont cu care să acceseze
această mașină.

Important Modul recomandat de a evita injectarea SQL este legarea tuturor datelor prin instrucțiuni
pregătite. Utilizarea interogărilor parametrizate nu este suficientă pentru a evita complet injecția
SQL, dar este cea mai ușoară și mai sigură modalitate de a furniza instrucțiuni SQL. Toate literalele
de date dinamice din clauzele WHERE, SET și VALUES trebuie înlocuite cu substituenți. Datele
reale vor fi legate în timpul execuției și trimise separat de comanda SQL.
Important Legarea parametrilor poate fi utilizată numai pentru date. Alte părți dinamice ale
interogării SQL trebuie filtrate în funcție de o listă cunoscută de valori permise.

<?php

// The dynamic SQL part is validated against expected values


$sortingOrder = $_GET['sortingOrder'] === 'DESC' ? 'DESC' : 'ASC';
$productId = $_GET['productId'];
// The SQL is prepared with a placeholder
$stmt = $pdo->prepare("SELECT * FROM products WHERE id LIKE ? ORDER BY price
{$sortingOrder}");
// The value is provided with LIKE wildcards
$stmt->execute(["%{$productId}%"]);

?>

Important Atacurile cu injecție SQL se bazează în principal pe exploatarea codului, care nu este
scris cu minte securitate. Nu aveți încredere niciodată în nicio intrare, în special din partea
clientului, chiar dacă aceasta provine dintr-o casetă de selectare, un câmp de intrare ascuns sau un
cookie. Primul exemplu arată că o interogare atât de simplă poate provoca dezastre.
Important O strategie de apărare în profunzime implică câteva bune practici de codificare:
• Nu vă conectați niciodată la baza de date ca superutilizator sau ca proprietar al bazei de date.
Utilizați întotdeauna utilizatori personalizați cu privilegii minime.
• Verificați dacă intrarea dată are tipul de date așteptat. PHP are o gamă largă de funcții de
validare a intrărilor, de la cele mai simple găsite în Funcțiile variabile și în Funcțiile tip
caracter (de exemplu, is_numeric(), respectiv ctype_digit()) și până la suportul pentru
expresii regulate compatibile cu Perl.
• Dacă aplicația așteaptă intrare numerică, luați în considerare verificarea datelor cu
ctype_digit(), schimbați tipul în tăcere folosind settype() sau folosiți reprezentarea numerică
prin sprintf().
• Dacă stratul bazei de date nu acceptă variabile de legare, atunci citați fiecare valoare
nenumerică furnizată de utilizator care este transmisă bazei de date cu funcția de evadare a
șirurilor specifice bazei de date (de exemplu, mysql_real_escape_string(),
sqlite_escape_string(), etc.). Funcțiile generice precum addslashes() sunt utile doar într-un
mediu foarte specific (de exemplu, MySQL într-un set de caractere pe un singur octet cu
NO_BACKSLASH_ESCAPES dezactivat), așa că este mai bine să le evitați.
• Nu tipăriți informații specifice bazei de date, în special despre schemă, prin mijloace corecte
sau greșite. Consultați și Funcțiile de raportare a erorilor și de tratare și înregistrare a
erorilor.
Important Pe lângă acestea, beneficiezi de interogări de jurnalizare fie în cadrul scriptului tău, fie
prin baza de date în sine, dacă acceptă înregistrarea în jurnal. Evident, înregistrarea nu poate preveni
orice încercare dăunătoare, dar poate fi util să urmăriți ce aplicație a fost ocolită. Jurnalul nu este
util în sine, ci prin informațiile pe care le conține. Mai multe detalii sunt în general mai bune decât
mai puține.

Important O tactică standard de atac implică profilarea unui sistem prin furnizarea de date
necorespunzătoare și verificarea tipurilor și contextelor erorilor care sunt returnate. Acest lucru
permite cracker-ului sistemului să caute informații despre server, pentru a determina posibilele
puncte slabe. De exemplu, dacă un atacator a adunat informații despre o pagină pe baza unei
trimiteri anterioare a unui formular, poate încerca să înlocuiască variabilele sau să le modifice:
<form method="post" action="attacktarget?username=badfoo&amp;password=badfoo">
<input type="hidden" name="username" value="badfoo" />
<input type="hidden" name="password" value="badfoo" />
</form>

Important Erorile PHP care sunt returnate în mod normal pot fi de mare ajutor pentru un dezvoltator
care încearcă să depaneze un script, indicând lucruri precum funcția sau fișierul care a eșuat, fișierul
PHP în care a eșuat și numărul liniei în care a avut loc eșecul. Acestea sunt toate informațiile care
pot fi exploatate. Nu este neobișnuit ca un dezvoltator php să folosească show_source(),
highlight_string() sau highlight_file() ca măsură de depanare, dar într-un site live, acest lucru poate
expune variabile ascunse, sintaxa neverificată și alte informații periculoase. Mai ales periculoasă
este rularea codului din surse cunoscute cu handlere de depanare încorporate sau utilizarea
tehnicilor obișnuite de depanare. Dacă atacatorul poate determina ce tehnică generală utilizați,
acesta poate încerca să forțeze brute o pagină, trimițând diverse șiruri comune de depanare:

<form method="post" action="attacktarget?errors=Y&amp;showerrors=1&amp;debug=1">


<input type="hidden" name="errors" value="Y" />
<input type="hidden" name="showerrors" value="1" />
<input type="hidden" name="debug" value="1" />
</form>

Important O eroare de funcție poate indica dacă un sistem poate rula un anumit motor de bază de
date sau poate oferi indicii despre modul în care o pagină web a fost programată sau proiectată.
Acest lucru permite investigarea mai profundă a porturilor de baze de date deschise sau căutarea
unor erori sau slăbiciuni specifice într-o pagină web. Prin furnizarea diferitelor date proaste, de
exemplu, un atacator poate determina ordinea de autentificare într-un script (din erorile de număr de
linie), precum și să cerceteze exploit-urile care pot fi exploatate în diferite locații din script.
Important O eroare de sistem de fișiere sau generală PHP poate indica ce permisiuni are serverul
web, precum și structura și organizarea fișierelor de pe serverul web. Codul de eroare scris de
dezvoltator poate agrava această problemă, ducând la exploatarea ușoară a informațiilor „ascunse”
anterior.

Important Există trei soluții majore la această problemă. Primul este de a examina toate funcțiile și
de a încerca să compensezi cea mai mare parte a erorilor. Al doilea este de a dezactiva complet
raportarea erorilor pe codul de rulare. Al treilea este să utilizați funcțiile personalizate de gestionare
a erorilor PHP pentru a vă crea propriul handler de erori. În funcție de politica dvs. de securitate,
este posibil să găsiți că toate trei sunt aplicabile situației dvs.
Important O modalitate de a rezolva această problemă din timp este să utilizați propriul
error_reporting() al PHP, pentru a vă ajuta să vă asigurați codul și să găsiți utilizarea variabilelor
care ar putea fi periculoase. Testând codul dvs., înainte de implementare, cu E_ALL, puteți găsi
rapid zone în care variabilele dvs. pot fi deschise otrăvirii sau modificării în alte moduri. Odată ce
sunteți pregătit pentru implementare, ar trebui fie să dezactivați complet raportarea erorilor setând
error_reporting() la 0, fie să dezactivați afișarea erorilor folosind opțiunea [Link] display_errors,
pentru a izola codul de sondare. Dacă alegeți să faceți aceasta din urmă, ar trebui să definiți și calea
către fișierul jurnal folosind directiva error_log ini și să activați log_errors.
<?php
if ($username) { // Not initialized or checked before usage
$good_login = 1;
}
if ($good_login == 1) { // If above test fails, not initialized or checked before usage
readfile ("/highly/sensitive/data/[Link]");
}
?>
<?php
// remove a file from the user's home directory... or maybe
// somebody else's?
unlink ($evil_var);

// Write logging of their access... or maybe an /etc/passwd entry?


fwrite ($fp, $evil_var);

// Execute something trivial.. or rm -rf *?


system ($evil_var);
exec ($evil_var);

?>

Important Ar trebui să vă examinați întotdeauna cu atenție codul pentru a vă asigura că toate


variabilele trimise dintr-un browser web sunt verificate corect și să vă puneți următoarele întrebări:
• Va afecta acest script numai fișierele dorite?
• Se poate lua măsuri asupra datelor neobișnuite sau nedorite?
• Poate fi folosit acest script în moduri neintenționate?
• Poate fi folosit în combinație cu alte scripturi într-un mod negativ?
• Vor fi înregistrate în mod adecvat tranzacțiile?

Important În general, securitatea prin obscuritate este una dintre cele mai slabe forme de securitate.
Dar, în unele cazuri, fiecare pic de securitate suplimentară este de dorit.
Important Câteva tehnici simple pot ajuta la ascunderea PHP-ului, posibil încetinind un atacator
care încearcă să descopere punctele slabe ale sistemului dumneavoastră. Setând expose_php la off
în fișierul [Link], reduceți cantitatea de informații disponibile pentru ei.
Important O altă tactică este să configurați servere web precum apache pentru a analiza diferite
tipuri de fișiere prin PHP, fie cu o directivă .htaccess, fie în fișierul de configurare apache însuși.
Apoi puteți utiliza extensii de fișiere înșelătoare:

# Make PHP code look like other code types


AddType application/x-httpd-php .asp .py .pl

# Make PHP code look like unknown types


AddType application/x-httpd-php .bop .foo .133t

# Make all PHP code look like HTML


AddType application/x-httpd-php .htm .html

34. Caracteristici

Important Este posibil să utilizați funcția header() pentru a trimite un mesaj „Autentificare
necesară” către browser-ul clientului, determinând o fereastră de introducere a numelui de
utilizator/parolă. Odată ce utilizatorul a completat un nume de utilizator și o parolă, URL-ul care
conține scriptul PHP va fi apelat din nou cu variabilele predefinite PHP_AUTH_USER,
PHP_AUTH_PW și AUTH_TYPE setate la numele de utilizator, parola și respectiv tipul de
autentificare. Aceste variabile predefinite se găsesc în tabloul $_SERVER. Numai metoda de
autentificare „de bază” este acceptată.
<?php
if (!isset($_SERVER['PHP_AUTH_USER'])) {
header('WWW-Authenticate: Basic realm="My Realm"');
header('HTTP/1.0 401 Unauthorized');
echo 'Text to send if user hits Cancel button';
exit;
} else {
echo "<p>Hello {$_SERVER['PHP_AUTH_USER']}.</p>";
echo "<p>You entered {$_SERVER['PHP_AUTH_PW']} as your password.</p>";
}
?>

Important În loc să imprimați pur și simplu PHP_AUTH_USER și PHP_AUTH_PW, așa cum s-a
făcut în exemplul de mai sus, poate doriți să verificați validitatea numelui de utilizator și a parolei.
Poate trimițând o interogare la o bază de date sau căutând utilizatorul într-un fișier dbm.
Important Atenție la browserele Internet Explorer cu erori. Par foarte pretențioși în ceea ce privește
ordinea antetelor. Trimiterea antetului WWW-Authenticate înainte de antetul HTTP/1.0 401 pare să
facă truc pentru moment.

<?php
function authenticate() {
header('WWW-Authenticate: Basic realm="Test Authentication System"');
header('HTTP/1.0 401 Unauthorized');
echo "You must enter a valid login ID and password to access this resource\n";
exit;
}

if (!isset($_SERVER['PHP_AUTH_USER']) ||
($_POST['SeenBefore'] == 1 && $_POST['OldAuth'] == $_SERVER['PHP_AUTH_USER'])) {
authenticate();
} else {
echo "<p>Welcome: " . htmlspecialchars($_SERVER['PHP_AUTH_USER']) . "<br />";
echo "Old: " . htmlspecialchars($_REQUEST['OldAuth']);
echo "<form action='' method='post'>\n";
echo "<input type='hidden' name='SeenBefore' value='1' />\n";
echo "<input type='hidden' name='OldAuth' value=\"" .
htmlspecialchars($_SERVER['PHP_AUTH_USER']) . "\" />\n";
echo "<input type='submit' value='Re Authenticate' />\n";
echo "</form></p>\n";
}
?>

Important Acest comportament nu este cerut de standardul de autentificare HTTP Basic, așa că nu
ar trebui să depindeți niciodată de acest lucru. Testarea cu Lynx a arătat că Lynx nu șterge
acreditările de autentificare cu un răspuns de server 401, așa că apăsând înapoi și apoi înainte din
nou va deschide resursa atâta timp cât cerințele de autentificare nu s-au schimbat. Cu toate acestea,
utilizatorul poate apăsa tasta „_” pentru a-și șterge informațiile de autentificare.
Important Pentru ca autentificarea HTTP să funcționeze folosind serverul IIS cu versiunea CGI a
PHP, trebuie să editați configurația IIS „Securitate director”. Faceți clic pe „Editare” și bifați doar
„Acces anonim”, toate celelalte câmpuri ar trebui lăsate nebifate.
Important PHP acceptă în mod transparent cookie-urile HTTP. Cookie-urile sunt un mecanism de
stocare a datelor în browserul de la distanță și, astfel, de urmărire sau de identificare a utilizatorilor
reveniți. Puteți seta cookie-uri folosind funcția setcookie() sau setrawcookie(). Cookie-urile fac
parte din antetul HTTP, așa că setcookie() trebuie apelat înainte ca orice rezultat să fie trimis către
browser. Aceasta este aceeași limitare pe care o are header(). Puteți utiliza funcțiile de buffering de
ieșire pentru a întârzia ieșirea scriptului până când ați decis dacă setați sau nu cookie-uri sau
trimiteți orice antet.
Important Orice cookie-uri trimise către server de la client vor fi incluse automat într-o matrice
auto-globală $_COOKIE dacă variables_order conține „C”. Dacă doriți să atribuiți mai multe valori
unui singur cookie, trebuie doar să adăugați [] la numele cookie-ului.

Important Suportul pentru sesiuni în PHP constă într-o modalitate de a păstra anumite date în
accesările ulterioare. Acest lucru vă permite să creați aplicații mai personalizate și să creșteți
atractivitatea site-ului dvs. web. Toate informațiile sunt în secțiunea Referință sesiune.

<!-- The data encoding type, enctype, MUST be specified as below -->
<form enctype="multipart/form-data" action="__URL__" method="POST">
<!-- MAX_FILE_SIZE must precede the file input field -->
<input type="hidden" name="MAX_FILE_SIZE" value="30000" />
<!-- Name of input element determines name in $_FILES array -->
Send this file: <input name="userfile" type="file" />
<input type="submit" value="Send File" />
</form>

Important Câmpul ascuns MAX_FILE_SIZE (măsurat în octeți) trebuie să precedă câmpul de


introducere a fișierului, iar valoarea acestuia este dimensiunea maximă a fișierelor acceptată de
PHP. Acest element de formular ar trebui să fie întotdeauna utilizat, deoarece scutește utilizatorii de
problemele de a aștepta transferul unui fișier mare, doar pentru a constata că acesta a fost prea mare
și că transferul a eșuat. Rețineți: păcălirea acestei setări din partea browserului este destul de ușoară,
așa că nu vă bazați niciodată pe fișierele cu o dimensiune mai mare care sunt blocate de această
funcție. Este doar o caracteristică de confort pentru utilizatorii din partea client a aplicației. Cu toate
acestea, setările PHP (pe partea de server) pentru dimensiunea maximă nu pot fi păcălite.
Important $_FILES global va conține toate informațiile despre fișierul încărcat. Conținutul său din
formularul exemplu este după cum urmează. Rețineți că aceasta presupune utilizarea numelui de
încărcare a fișierului userfile, așa cum este folosit în exemplul de script de mai sus. Acesta poate fi
orice nume.
$_FILES['userfile']['name'] - Numele original al fișierului de pe computerul client.
$_FILES['userfile']['type'] - Tipul mime al fișierului, dacă browser-ul a furnizat aceste informații.
Un exemplu ar fi „imagine/gif”. Acest tip de mime nu este totuși verificat din partea PHP și, prin
urmare, nu ia valoarea lui de bună.
$_FILES['userfile']['size'] - Dimensiunea, în octeți, a fișierului încărcat.
$_FILES['userfile']['tmp_name'] - Numele de fișier temporar al fișierului în care fișierul încărcat a
fost stocat pe server.
$_FILES['userfile']['eroare'] - Codul de eroare asociat cu încărcarea acestui fișier.
$_FILES['userfile']['full_path'] - Calea completă, așa cum este trimisă de browser. Această valoare
nu conține întotdeauna o structură de directoare reală și nu poate fi de încredere. Disponibil
începând cu PHP 8.1.0.
<form action="" method="post" enctype="multipart/form-data">
<p>Pictures:
<input type="file" name="pictures[]" />
<input type="file" name="pictures[]" />
<input type="file" name="pictures[]" />
<input type="submit" value="Send" />
</p>
</form>
Important PHP returnează un cod de eroare adecvat împreună cu matricea de fișiere. Codul de
eroare poate fi găsit în segmentul de eroare al matricei de fișiere care este creat în timpul încărcării
fișierului de către PHP. Cu alte cuvinte, eroarea poate fi găsită în $_FILES['userfile']['error'].
Valoarea acestui cod de eroare este una dintre constantele UPLOAD_ERR_*.

Important Elementul MAX_FILE_SIZE nu poate specifica o dimensiune a fișierului mai mare decât
dimensiunea fișierului care a fost setată în upload_max_filesize din fișierul [Link]. Valoarea
implicită este de 2 megaocteți. Dacă este activată o limită de memorie, poate fi necesară o limită de
memorie mai mare. Asigurați-vă că setați memory_limit suficient de mare. Dacă
max_execution_time este setat prea mic, execuția scriptului poate fi depășită cu valoarea. Asigurați-
vă că setați max_execution_time suficient de mare.

Important Dacă post_max_size este setat prea mic, fișierele mari nu pot fi încărcate. Asigurați-vă că
setați post_max_size suficient de mare. Setarea de configurare max_file_uploads controlează
numărul maxim de fișiere care pot fi încărcate într-o singură solicitare. Dacă sunt încărcate mai
multe fișiere decât limita, atunci $_FILES va opri procesarea fișierelor odată ce limita este atinsă.
De exemplu, dacă max_file_uploads este setat la 10, atunci $_FILES nu va conține niciodată mai
mult de 10 elemente.

Important De asemenea, este posibil să încărcați mai multe fișiere simultan și să aveți informațiile
organizate automat în matrice pentru dvs. Pentru a face acest lucru, trebuie să utilizați aceeași
sintaxă de trimitere a matricei în formularul HTML ca și cu mai multe selectări și casete de
selectare:

<form action="[Link]" method="post" enctype="multipart/form-data">


Send these files:<br />
<input name="userfile[]" type="file" /><br />
<input name="userfile[]" type="file" /><br />
<input type="submit" value="Send files" />
</form>

Important Când este trimis formularul de mai sus, matricele $_FILES['userfile'], $_FILES['userfile']
['nume'] și $_FILES['userfile']['size'] vor fi inițializate. De exemplu, să presupunem că numele de
fișiere /home/test/[Link] și /home/test/[Link] sunt trimise. În acest caz, $_FILES['userfile']
['name'][0] va conține valoarea [Link], iar $_FILES['userfile']['name'][1] va conține valoarea
[Link] . În mod similar, $_FILES['userfile']['size'][0] ar conține dimensiunea fișierului
[Link] și așa mai departe. $_FILES['userfile']['name'][0], $_FILES['userfile']['tmp_name'][0],
$_FILES['userfile']['size'][0] și $ _FILES['userfile']['type'][0] sunt de asemenea setate.

Important PHP oferă suport pentru metoda HTTP PUT folosită de unii clienți pentru a stoca fișiere
pe un server. Solicitările PUT sunt mult mai simple decât încărcarea unui fișier folosind solicitări
POST și arată cam așa:
PUT /path/[Link] HTTP/1.1

Important Acest lucru ar însemna în mod normal că clientul de la distanță ar dori să salveze
conținutul care urmează ca: /cale/numefiș[Link] în arborele dvs. web. În mod evident, nu este o
idee bună ca Apache sau PHP să permită tuturor să suprascrie automat orice fișier din arborele web.
Deci, pentru a gestiona o astfel de solicitare, trebuie mai întâi să spuneți serverului dvs. web că
doriți ca un anumit script PHP să gestioneze cererea. În Apache faci asta cu directiva Script. Poate fi
plasat aproape oriunde în fișierul dvs. de configurare Apache. Un loc obișnuit este în interiorul unui
bloc <Directory> sau poate într-un bloc <VirtualHost>. O linie ca aceasta ar face treaba:

Script PUT /[Link]


<?php
/* PUT data comes in on the stdin stream */
$putdata = fopen("php://input", "r");

/* Open a file for writing */


$fp = fopen("[Link]", "w");

/* Read the data 1 KB at a time


and write to the file */
while ($data = fread($putdata, 1024))
fwrite($fp, $data);

/* Close the streams */


fclose($fp);
fclose($putdata);
?>

Important Atâta timp cât allow_url_fopen este activat în [Link], puteți utiliza URL-uri HTTP și
FTP cu majoritatea funcțiilor care iau un nume de fișier ca parametru. În plus, adresele URL pot fi
utilizate cu instrucțiunile include, include_once, require și require_once (allow_url_include trebuie
să fie activat pentru acestea). Consultați Protocoale și Wrapper-uri acceptate pentru mai multe
informații despre protocoalele acceptate de PHP.
Important De exemplu, puteți utiliza acest lucru pentru a deschide un fișier pe un server web la
distanță, a analiza rezultatul pentru datele dorite și apoi a utiliza acele date într-o interogare de bază
de date sau pur și simplu pentru a-l scoate într-un stil care se potrivește cu restul site-ului dvs. .

<?php
$file = fopen ("[Link] "r");
if (!$file) {
echo "<p>Unable to open remote file.\n";
exit;
}
while (!feof ($file)) {
$line = fgets ($file, 1024);
/* This only works if the title and its tags are on one line */
if (preg_match ("@\<title\>(.*)\</title\>@i", $line, $out)) {
$title = $out[1];
break;
}
}
fclose($file);
?>

Important De asemenea, puteți scrie în fișiere de pe un server FTP (cu condiția să fiți conectat ca
utilizator cu drepturi de acces corecte). Puteți crea fișiere noi numai folosind această metodă; dacă
încercați să suprascrieți un fișier care există deja, apelul fopen() va eșua.
Important Pentru a vă conecta ca alt utilizator decât „anonim”, trebuie să specificați numele de
utilizator (și eventual parola) în adresa URL, cum ar fi
„[Link] (Puteți folosi același tip de sintaxă pentru a
accesa fișierele prin HTTP atunci când necesită autentificare de bază.)
<?php
$file = fopen ("[Link] "w");
if (!$file) {
echo "<p>Unable to open remote file for writing.\n";
exit;
}
/* Write the data here. */
fwrite ($file, $_SERVER['HTTP_USER_AGENT'] . "\n");
fclose ($file);
?>

Important PHP menține o stare de conexiune cu 4 stări posibile: NORMAL, ABORTED


(deconectare utilizator), TIMEOUT (depășirea timpului de execuție) și o combinație a acestora
(ABORTED + TIMEOUT). Implicit, scripturile PHP se încheie dacă clientul se deconectează, dar
acest comportament poate fi modificat cu directiva ignore_user_abort. Funcțiile
register_shutdown_function() și connection_aborted() permit gestionarea acțiunilor la încheierea
scriptului, inclusiv în cazul deconectărilor sau a timeout-urilor. Limita de timp implicită pentru
execuția unui script este de 30 de secunde, ajustabilă cu set_time_limit() sau prin configurările din
[Link]. Funcția connection_status() poate indica motivele întreruperii unui script (2 pentru timeout,
3 pentru combinație).

Important Conexiunile persistente în PHP rămân deschise după finalizarea unui script, fiind
reutilizate pentru cereri ulterioare dacă se potrivesc cu aceleași credențiale (gazdă, utilizator,
parolă). Ele sunt utile pentru eficiență, reducând costurile de conectare repetată la un server SQL,
dar nu adaugă funcționalitate nouă față de conexiunile nepersistente.
Important Acestea pot avea dezavantaje, cum ar fi:
• Depășirea limitelor de conexiuni simultane ale bazei de date.
• Probleme cauzate de blocări de tabele sau tranzacții nefinalizate, ce pot afecta scripturile
ulterioare.
Important Este recomandat să evitați utilizarea lor în scenarii cu tranzacții sau blocări frecvente și
să implementați funcții de curățare cu register_shutdown_function(). Conexiunile persistente
îmbunătățesc eficiența, dar trebuie utilizate cu prudență pentru a evita blocajele și suprasolicitarea
serverului SQL.

Important CLI SAPI este utilizat pentru dezvoltarea aplicațiilor shell cu PHP și este diferit de alte
SAPI-uri, cum ar fi CGI, deși împărtășesc unele comportamente. Este activat implicit cu --enable-
cli (poate fi dezactivat cu --disable-cli).
Instalare și configurare:
• Binarele CLI și CGI sunt generate implicit la compilare, fiind plasate în directoarele
sapi/cli/php și sapi/cgi/php-cgi.
• În timpul instalării, binarul copiat depinde de configurația aleasă. De exemplu:
• Cu --with-apxs, CLI este copiat ca {PREFIX}/bin/php.
• Pentru a instala doar CLI, folosiți make install-cli după make install.
• Utilizați --disable-cgi pentru a exclude CGI.
Platforma Windows:
• CLI este distribuit ca [Link], CGI ca [Link], iar [Link] este o variantă CLI fără
consolă, activată cu --enable-cli-win32.
Determinarea SAPI-ului:
• Comanda php -v indică dacă PHP rulează ca CLI sau CGI.
• Puteți verifica și cu funcția php_sapi_name() sau constanta PHP_SAPI.
Alte resurse:
Pe Unix, comanda man php oferă documentație pentru CLI.

Important Diferențe remarcabile ale CLI SAPI în comparație cu alte SAPI:


• Spre deosebire de CGI SAPI, niciun antet nu este scris în ieșire.
• Deși CGI SAPI oferă o modalitate de a suprima antetele HTTP, nu există un comutator
echivalent pentru a le activa în CLI SAPI.
• CLI este pornit în mod implicit în mod silențios, deși comutatoarele -q și --no-header sunt
păstrate pentru compatibilitate, astfel încât să fie posibilă utilizarea scripturilor CGI mai
vechi.
• Nu schimbă directorul de lucru cu cel al scriptului. (Comutatoarele -C și --no-chdir păstrate
pentru compatibilitate)
• Mesaje de eroare text simplu (fără formatare HTML).
• Există anumite directive [Link] care sunt suprascrise de CLI SAPI deoarece nu au sens în
mediile shell:

default
Directive Comment
value
Valoarea implicită la false, deoarece poate fi destul de greu să
html_errors false citiți mesajele de eroare în mediul shell atunci când sunt
aglomerate cu etichete neinterpretate.
Într-un mediu shell, este de obicei de dorit ca rezultatul, cum ar
fi de tipărire, ecou și prieteni, să fie afișat imediat și să nu fie
implicit_flush true păstrat într-un buffer. Cu toate acestea, este încă posibil să
utilizați tamponarea de ieșire pentru a amâna sau manipula
ieșirea standard.
PHP într-un mediu shell tinde să fie folosit pentru o gamă mult
0 mai diversificată de scopuri decât scripturile tipice bazate pe
max_execution_time
(unlimited) Web și, deoarece acestea pot fi de lungă durată, timpul maxim
de execuție este setat la nelimitat.
register_argc_argv true Setarea la true înseamnă că scripturile executate prin intermediul
au întotdeauna acces la argc (numărul de argumente transmise
aplicației) și argv (matricea argumentelor reale).

Variabilele PHP $argc și $argv sunt setate automat la valorile


corespunzătoare atunci când se utilizează . Aceste valori pot fi
găsite și în matricea $_SERVER, de exemplu:
$_SERVER['argv'].

Warning
default
Directive Comment
value
Prezența $argv sau $_SERVER['argv'] nu este o indicație de
încredere că un script este rulat din linia de comandă, deoarece
acestea pot fi setate în alte contexte când register_argc_argv este
activat. Valoarea returnată de php_sapi_name() ar trebui
verificată în schimb.

<?php

if (php_sapi_name() === 'cli') {


echo "This is being run from the command line!\n";
}

Deși setarea [Link] este codificată la fals, funcțiile de buffering de ieșire


output_buffering false sunt disponibile.

PHP nu acceptă GET, POST sau încărcări de fișiere.


max_input_time false

<?php
// Our simple test application named [Link]
echo getcwd(), "\n";
?>

Când utilizați versiunea CGI, rezultatul este:


$ pwd
/tmp

$ php -q another_directory/[Link]
/tmp/another_directory

Folosind CLI SAPI rezultă:


$ pwd
/tmp

$ php -f another_directory/[Link]
/tmp

Important Există trei moduri diferite de a furniza CLI SAPI cu cod PHP pentru a fi executat:
1. Spuneți PHP să execute un anumit fișier.
$ php my_script.php
$ php -f my_script.php

2. Transmite codul PHP pentru a-l executa direct pe linia de comandă.


$ php -r 'print_r(get_defined_constants());'

3. Furnizați codul PHP pentru a fi executat prin intrarea standard (stdin).


$ some_application | some_filter | php | sort -u > final_output.txt
Constant Description
An already opened stream to stdin. This saves opening it with

<?php
$stdin = fopen('php://stdin', 'r');
?>
STDIN
If you want to read single line from stdin, you can use
<?php
$line = trim(fgets(STDIN)); // reads one line from STDIN
fscanf(STDIN, "%d\n", $number); // reads number from STDIN
?>
An already opened stream to stdout. This saves opening it with

STDOUT <?php
$stdout = fopen('php://stdout', 'w');
?>
An already opened stream to stderr. This saves opening it with

STDERR <?php
$stderr = fopen('php://stderr', 'w');
?>

Important CLI SAPI oferă un shell interactiv folosind opțiunea -a dacă PHP este compilat cu
opțiunea --with-readline. Începând cu PHP 7.1.0, shell-ul interactiv este disponibil și pe Windows,
dacă extensia readline este activată. Folosind shell-ul interactiv, puteți să tastați cod PHP și să îl
executați direct.

$ php -a
Interactive shell

php > echo 5+8;


13
php > function addTwo($n)
php > {
php { return $n + 2;
php { }
php > var_dump(addtwo(2));
int(4)
php >

Important Shell-ul interactiv oferă, de asemenea, completarea filelor pentru funcții, constante, nume
de clase, variabile, apeluri de metode statice și constante de clasă.

php > strp[TAB][TAB]


strpbrk strpos strptime
php > strp

Important Când există o singură finalizare posibilă, apăsând Tab o dată va finaliza restul pe aceeași
linie:
php > strpt[TAB]ime(
Important Completarea va funcționa și pentru numele care au fost definite în timpul sesiunii
interactive shell curente:

php > $fooThisIsAReallyLongVariableName = 42;


php > $foo[TAB]ThisIsAReallyLongVariableName

Important Shell-ul interactiv stochează istoricul dvs., care poate fi accesat folosind tastele sus și jos.
Istoricul este salvat în fișierul ~/.php_history. Începând cu PHP 8.4.0, calea către fișierul istoric
poate fi setată folosind variabila de mediu PHP_HISTFILE.
Important CLI SAPI oferă setările [Link] [Link] și [Link]. Setarea [Link] permite unui
program extern (cum ar fi less) să acționeze ca un pager pentru ieșire în loc să fie afișat direct pe
ecran. Setarea [Link] face posibilă schimbarea promptului php >.

php > #[Link]=hello world :>


hello world :>

php > #[Link]=`echo date('H:i:s');` php >


15:49:35 php > echo 'hi';
hi
15:49:43 php > sleep(2);
15:49:45 php >

php > #[Link]=less


php > phpinfo();
(output displayed in less)
php >

Sequence Description
\e Folosit pentru adăugarea de culori la prompt. Un exemplu ar putea fi \e[032m\v \
e[031m\b \e[34m\> \e[0m
\v Versiunea PHP.
\b Indică în ce bloc se află PHP. De exemplu /* pentru a indica faptul că se află într-un
comentariu cu mai multe rânduri. Domeniul exterior este notat cu php.
Indică caracterul prompt. În mod implicit, acesta este >, dar se schimbă atunci când
\> shell-ul se află în interiorul unui bloc sau șir neterminat. Caracterele posibile sunt: ' " { (
>

Important Dacă extensia readline nu este disponibilă, înainte de PHP 8.1.0, invocarea CLI SAPI cu
opțiunea -a a furnizat modul interactiv. În acest mod, se presupune că va fi dat un script PHP
complet prin STDIN, iar după terminarea cu CTRL +D (POSIX) sau CTRL +Z urmat de +ENTER
(Windows), acest script este evaluat. Acest lucru este practic același cu invocarea CLI SAPI fără
opțiunea -a.

Important Serverul web integrat în CLI SAPI este conceput pentru dezvoltare, testare și
demonstrații în medii controlate, dar nu este potrivit pentru utilizare în rețele publice.
Caracteristici principale:
• Rulează un singur proces și un singur thread (blocarea unei solicitări blochează întregul
server).
• Servirea fișierelor:
• Utilizează directorul de lucru curent sau poate fi configurat cu -t pentru o rădăcină
specifică a documentelor.
• Caută și returnează fișierele [Link] sau [Link]. Dacă nu sunt găsite,
returnează codul 404.
• Suport pentru scripturi router:
• Un fișier PHP specificat la pornire este executat pentru fiecare solicitare. Dacă
scriptul returnează false, serverul servește resursa solicitată; altfel, răspunsul
scriptului este trimis în browser.
• Include suport pentru tipuri MIME standard (ex. .html, .css, .png, .mp4).
Funcționalități suplimentare:
• Din PHP 7.4.0, serverul poate forka mai mulți lucrători pentru testarea solicitărilor
simultane. Configurați variabila de mediu PHP_CLI_SERVER_WORKERS înainte de
pornire.
$ cd ~/public_html
$ php -S localhost:8000
Output:
PHP 5.4.0 Development Server started at Thu Jul 21 10:43:28 2011
Listening on localhost:8000
Document root is /home/me/public_html
Press Ctrl-C to quit

După solicitările URI pentru [Link] și [Link] terminalul


va afișa ceva similar cu:
PHP 5.4.0 Development Server started at Thu Jul 21 10:43:28 2011
Listening on localhost:8000
Document root is /home/me/public_html
Press Ctrl-C to quit.
[Thu Jul 21 10:48:48 2011] ::1:39144 GET /[Link] - Request read
[Thu Jul 21 10:48:50 2011] ::1:39146 GET / - Request read
[Thu Jul 21 10:48:50 2011] ::1:39147 GET /[Link] - Request read
[Thu Jul 21 10:48:52 2011] ::1:39148 GET /[Link] - Request read
[Thu Jul 21 10:48:52 2011] ::1:39149 GET /[Link] - Request read

$ cd ~/public_html
$ php -S localhost:8000 -t foo/
Output:
PHP 5.4.0 Development Server started at Thu Jul 21 10:50:26 2011
Listening on localhost:8000
Document root is /home/me/public_html/foo
Press Ctrl-C to quit

Important O variabilă PHP este stocată într-un container numit „zval”. Un container zval conține, pe
lângă tipul și valoarea variabilei, doi biți suplimentari de informații. Prima se numește „is_ref” și
este o valoare booleană care indică dacă variabila face sau nu parte dintr-un „mult de referință”. Cu
acest bit, motorul PHP știe să facă diferența între variabilele normale și referințe. Deoarece PHP
permite referințe utilizator-teren, așa cum sunt create de operatorul &, un container zval are și un
mecanism intern de numărare a referințelor pentru a optimiza utilizarea memoriei. Această a doua
informație suplimentară, numită „refcount”, conține câte nume de variabile (numite și simboluri)
indică acest container zval. Toate simbolurile sunt stocate într-un tabel de simboluri, dintre care
există unul pentru fiecare domeniu. Există un domeniu de aplicare pentru scriptul principal (adică
cel solicitat prin browser), precum și unul pentru fiecare funcție sau metodă.
<?php
$a = "new string";
?>

Important În acest caz, noul nume de simbol, a, este creat în domeniul curent și este creat un nou
container de variabile cu tipul șir și valoarea șir nou. Bitul „is_ref” este setat în mod implicit la false
deoarece nu a fost creată nicio referință utilizator-teren. „Refcount” este setat la 1 deoarece există
un singur simbol care folosește acest container variabil. Rețineți că referințele (adică „is_ref” este
adevărat) cu „refcount” 1, sunt tratate ca și cum nu ar fi referințe (adică, deoarece „is_ref” a fost
fals). Dacă aveți » Xdebug instalat, puteți afișa aceste informații apelând xdebug_debug_zval().

<?php
$a = "new string";
xdebug_debug_zval('a');
?>
Output: a: (refcount=1, is_ref=0)='new string'

<?php
$a = "new string";
$b = $a;
xdebug_debug_zval( 'a' );
?>
Output: a: (refcount=2, is_ref=0)='new string'

Important Refcount este 2 aici, deoarece același container variabil este legat atât cu a cât și cu b.
PHP este suficient de inteligent pentru a nu copia containerul variabil real atunci când nu este
necesar. Containerele variabile sunt distruse atunci când „refcount” ajunge la zero. „Refcount”
scade cu unu atunci când orice simbol legat de containerul variabil părăsește domeniul de aplicare
(de exemplu, când funcția se termină) sau când un simbol este nealocat (de exemplu, prin apelarea
unset()). Următorul exemplu arată acest lucru:

<?php
$a = "new string";
$c = $b = $a;
xdebug_debug_zval( 'a' );
$b = 42;
xdebug_debug_zval( 'a' );
unset( $c );
xdebug_debug_zval( 'a' );
?>
Output:
a: (refcount=3, is_ref=0)='new string'
a: (refcount=2, is_ref=0)='new string'
a: (refcount=1, is_ref=0)='new string'

Important DTrace este un cadru de urmărire cu suprasolicitare redusă, disponibil pe platforme


precum Solaris, macOS, Oracle Linux și BSD, care permite monitorizarea execuției aplicațiilor și a
sistemului de operare.
Caracteristici principale:
• Poate analiza argumentele și deduce statistici de performanță prin scripturi DTrace D scrise
de utilizator.
• Monitorizarea inactivă a sondelor PHP nu degradează performanța aplicației, iar
suprasarcina pentru sondele active este suficient de mică pentru utilizare pe sisteme de
producție.
• PHP utilizează sonde USDT (Urmărire definită static la nivel de utilizator) care declanșează
evenimente în timpul execuției, de exemplu, la apelurile funcțiilor PHP. Aceste evenimente
pot colecta date precum locația fișierelor sau numărul de apeluri.
Alte informații:
• DTrace permite urmărirea punctelor de date definite de utilizator și a funcțiilor arbitrare.
• Caracteristicile și implementarea pot varia între platforme.
• Pe unele distribuții Linux, sondele DTrace PHP pot fi utilizate alternativ cu SystemTap.

Probe Name Probe Description Probe Arguments


Se declanșează când începe o char *file, char *request_uri, char
request-startup
solicitare. *request_method
Se declanșează la închiderea unei char *file, char *request_uri, char
request-shutdown
cereri. *request_method
Se declanșează când începe char *compile_file, char
compile-file-entry
compilarea unui script. *compile_file_translated
Se declanșează când se termină char *compile_file, char
compile-file-return
compilarea unui script. *compile_file_translated
Se declanșează atunci când
urmează să fie executată o
execute-entry matrice opcode. De exemplu, se char *request_file, int lineno
declanșează la apeluri de funcții,
include și reluează generatorul.
Se declanșează după executarea
execute-return char *request_file, int lineno
unui tablou de cod operațional.
char *function_name, char
Se declanșează după executarea
function-entry *request_file, int lineno, char
unui tablou de cod operațional.
*classname, char *scope
Se declanșează atunci când char *function_name, char
function-return motorul PHP revine dintr-o *request_file, int lineno, char
funcție PHP sau apel de metodă. *classname, char *scope
Se declanșează când se aruncă o
exception-thrown char *classname
excepție.
Se declanșează atunci când este
exception-caught char *classname
prinsă o excepție.
Se declanșează atunci când apare
char *errormsg, char *request_file,
error o eroare, indiferent de nivelul
int lineno
error_reporting.

35. PDO (PHP Data Object)


Important Extensia PHP Data Objects (PDO) definește o interfață ușoară și consistentă pentru
accesarea bazelor de date în PHP. Fiecare driver de bază de date care implementează interfața PDO
poate expune caracteristici specifice bazei de date ca funcții de extensie obișnuite. Rețineți că nu
puteți efectua nicio funcție de bază de date folosind extensia PDO de la sine; trebuie să utilizați un
driver PDO specific bazei de date pentru a accesa un server de baze de date.
Important Instalarea PDO pe sisteme Unix:
• PDO și driverul PDO_SQLITE sunt activate implicit. Poate fi necesar să activați driverul
PDO pentru baza de date pe care o alegeți; consultați documentația pentru driverele PDO
specifice bazei de date pentru a afla mai multe despre asta.
• Când construiți PDO ca extensie partajată (nu este recomandat), atunci toate driverele PDO
trebuie încărcate după PDO în sine.
• Când instalați PDO ca modul partajat, fișierul [Link] trebuie să fie actualizat, astfel încât
extensia PDO să fie încărcată automat când PHP rulează. De asemenea, va trebui să activați
orice driver specific pentru baze de date și acolo; asigurați-vă că acestea sunt listate după
linia [Link], deoarece PDO trebuie inițializat înainte ca extensiile specifice bazei de date să
poată fi încărcate. Dacă ați creat PDO și extensiile specifice bazei de date în mod static,
puteți sări peste acest pas.
• extension=[Link]

Important Utilizatorii de Windows


• Alegeți celelalte fișiere DLL specifice bazei de date și fie utilizați dl() pentru a le încărca în
timpul rulării, fie activați-le în [Link] de sub php_pdo.dll. De exemplu:
extensie=php_pdo.dll
• extensie=php_pdo_firebird.dll
• extensie=php_pdo_informix.dll
• extensie=php_pdo_mssql.dll
• extensie=php_pdo_mysql.dll
• extensie=php_pdo_oci.dll
• extensie=php_pdo_oci8.dll
• extensie=php_pdo_odbc.dll
• extensie=php_pdo_pgsql.dll
• extensie=php_pdo_sqlite.dll

Important Conexiunile sunt stabilite prin crearea de instanțe ale clasei de bază PDO. Nu contează ce
driver vrei să folosești; folosești întotdeauna numele clasei PDO. Constructorul acceptă parametri
pentru specificarea sursei bazei de date (cunoscută ca DSN) și opțional pentru numele de utilizator
și parola (dacă există).

<?php
$dbh = new PDO('mysql:host=localhost;dbname=test', $user, $pass);
?>

Important Dacă există erori de conexiune, va fi aruncat un obiect PDOException. Puteți prinde
excepția dacă doriți să gestionați condiția de eroare sau puteți opta să o lăsați pentru un handler
global de excepție al aplicației pe care l-ați configurat prin set_exception_handler().

<?php
try {
$dbh = new PDO('mysql:host=localhost;dbname=test', $user, $pass);
} catch (PDOException $e) {
// attempt to retry the connection after some timeout for example
}
Important După conectarea cu succes la baza de date, o instanță a clasei PDO este returnată la
scriptul dumneavoastră. Conexiunea rămâne activă pe toată durata de viață a acelui obiect PDO.
Pentru a închide conexiunea, trebuie să distrugeți obiectul, asigurându-vă că toate referințele rămase
la acesta sunt șterse - faceți acest lucru atribuind null variabilei care deține obiectul. Dacă nu faceți
acest lucru în mod explicit, PHP va închide automat conexiunea când scriptul dvs. se termină.

<?php
$dbh = new PDO('mysql:host=localhost;dbname=test', $user, $pass);
// use the connection here
$sth = $dbh->query('SELECT * FROM foo');

// and now we're done; close it


$sth = null;
$dbh = null;
?>

Important Tranzacțiile în PDO oferă caracteristici ACID (Atomicitate, Consistență, Izolare,


Durabilitate), garantând modificări sigure și fără interferențe, cu posibilitatea de anulare în caz de
erori. Ele îmbunătățesc eficiența actualizărilor și robusteză scripturile dacă sunt utilizate corect. În
modul „auto-commit”, fiecare interogare rulează implicit în propria tranzacție (dacă baza de date o
suportă). Pentru tranzacții explicite, se folosește PDO::beginTransaction(), urmat de PDO::commit()
sau PDO::rollBack() pentru finalizare.
Important Dacă driverul bazei de date nu suportă tranzacții, este aruncată o PDOException. Atenție,
PDO verifică tranzacțiile doar la nivel de driver, iar rollback-ul automat are loc doar dacă tranzacția
este inițiată prin PDO::beginTransaction(). Încheierea unui script cu tranzacții restante determină un
rollback automat pentru a preveni inconsistențele, dar acest lucru nu se aplică tranzacțiilor începute
manual.

<?php
try {
$dbh = new PDO('odbc:SAMPLE', 'db2inst1', 'ibmdb2',
array(PDO::ATTR_PERSISTENT => true));
echo "Connected\n";
} catch (Exception $e) {
die("Unable to connect: " . $e->getMessage());
}
try {
$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$dbh->beginTransaction();
$dbh->exec("insert into staff (id, first, last) values (23, 'Joe', 'Bloggs')");
$dbh->exec("insert into salarychange (id, amount, changedate)
values (23, 50000, NOW())");
$dbh->commit();
} catch (Exception $e) {
$dbh->rollBack();
echo "Failed: " . $e->getMessage();}
?>
Important Declarațiile pregătite sunt șabloane SQL compilate care pot fi reutilizate cu parametri
diferiți, oferind două avantaje principale:
1. Analiza, compilarea și optimizarea interogării se face o singură dată, economisind resurse și
accelerând execuția, mai ales pentru interogări complexe repetate.
2. Parametrii sunt automat securizați împotriva injecției SQL, deoarece șoferul bazei de date
gestionează citarea acestora.
PDO emulează declarațiile pregătite pentru driverele care nu le suportă, permițând o paradigmă
unificată de acces la date indiferent de baza de date utilizată.

<?php
$stmt = $dbh->prepare("INSERT INTO REGISTRY (name, value) VALUES (:name, :value)");
$stmt->bindParam(':name', $name);
$stmt->bindParam(':value', $value);

// insert one row


$name = 'one';
$value = 1;
$stmt->execute();

// insert another row with different values


$name = 'two';
$value = 2;
$stmt->execute();
?>

Important Acest exemplu preia date pe baza unei valori cheie furnizate de un formular. Intrarea
utilizatorului este cotată automat, deci nu există riscul unui atac de injecție SQL.

<?php
$stmt = $dbh->prepare("SELECT * FROM REGISTRY where name = ?");
$stmt->execute([$_GET['name']]);
foreach ($stmt as $row) {
print_r($row);
}
?>

Important Dacă driverul bazei de date îl acceptă, o aplicație poate lega și parametrii pentru ieșire,
precum și pentru intrare. Parametrii de ieșire sunt utilizați de obicei pentru a prelua valori din
procedurile stocate. Parametrii de ieșire sunt puțin mai complex de utilizat decât parametrii de
intrare, deoarece un dezvoltator trebuie să știe cât de mare ar putea fi un anumit parametru atunci
când îl leagă. Dacă valoarea se dovedește a fi mai mare decât dimensiunea sugerată de ei, apare o
eroare.

<?php
$stmt = $dbh->prepare("CALL sp_returns_string(?)");
$stmt->bindParam(1, $return_value, PDO::PARAM_STR, 4000);
// call the stored procedure
$stmt->execute();

print "procedure returned $return_value\n";


?>
PDO oferă trei moduri de tratare a erorilor:
1. PDO::ERRMODE_SILENT: Modul silențios (implicit înainte de PHP 8.0.0) înregistrează
codul de eroare, accesibil prin PDO::errorCode() sau PDO::errorInfo(), fără a
emite mesaje sau întrerupe scriptul.
2. PDO::ERRMODE_WARNING: Emite mesaje E_WARNING în plus față de înregistrarea
erorilor, util pentru depanare fără a opri aplicația.
3. PDO::ERRMODE_EXCEPTION: Modul implicit începând cu PHP 8.0.0, generează
excepții PDOException la erori, facilitând identificarea rapidă a problemelor și permițând
gestionarea mai clară a erorilor, inclusiv anularea automată a tranzacțiilor dacă scriptul se
întrerupe.
PDO folosește coduri de eroare standard SQLSTATE, iar informațiile detaliate despre erori sunt
disponibile prin PDO::errorInfo().

<?php
$dsn = 'mysql:dbname=testdb;host=[Link]';
$user = 'dbuser';
$password = 'dbpass';

$dbh = new PDO($dsn, $user, $password);


$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

// This will cause PDO to throw a PDOException (when the table doesn't exist)
$dbh->query("SELECT wrongcolumn FROM wrongtable");

Output: Fatal error: Uncaught PDOException: SQLSTATE[42S02]: Base table or view not found:
1146

<?php
$dsn = 'mysql:dbname=test;host=[Link]';
$user = 'googleguy';
$password = 'googleguy';

$dbh = new PDO($dsn, $user, $password, array(PDO::ATTR_ERRMODE =>


PDO::ERRMODE_WARNING));

// This will cause PDO to throw an error of level E_WARNING instead of an exception (when the
table doesn't exist)
$dbh->query("SELECT wrongcolumn FROM wrongtable");

Ouptut: PDO::query(): SQLSTATE[42S02]: Base table or view not found: 1146

Important La un moment dat în aplicație, s-ar putea să descoperiți că trebuie să stocați date „mari”
în baza de date. Mare înseamnă de obicei „aproximativ 4 kb sau mai mult”, deși unele baze de date
pot gestiona cu plăcere până la 32 kb înainte ca datele să devină „mari”. Obiectele mari pot fi de
natură textuală sau binară. PDO vă permite să lucrați cu acest tip mare de date utilizând codul de tip
PDO::PARAM_LOB în apelurile dvs. PDOStatement::bindParam() sau
PDOStatement::bindColumn(). PDO::PARAM_LOB îi spune lui PDO să mapeze datele ca flux,
astfel încât să le puteți manipula folosind API-ul PHP Streams.
Important Acest exemplu leagă LOB-ul în variabila numită $lob și apoi îl trimite la browser
folosind fpassthru(). Deoarece LOB este reprezentat ca un flux, funcții precum fgets(), fread() și
stream_get_contents() pot fi utilizate pe acesta.

<?php
$db = new PDO('odbc:SAMPLE', 'db2inst1', 'ibmdb2');
$stmt = $db->prepare("select contenttype, imagedata from images where id=?");
$stmt->execute(array($_GET['id']));
$stmt->bindColumn(1, $type, PDO::PARAM_STR, 256);
$stmt->bindColumn(2, $lob, PDO::PARAM_LOB);
$stmt->fetch(PDO::FETCH_BOUND);

header("Content-Type: $type");
fpassthru($lob);
?>

Important Acest exemplu deschide un fișier și transmite mânerul fișierului către PDO pentru a-l
insera ca LOB. PDO va face tot posibilul pentru a aduce conținutul fișierului în baza de date în cel
mai eficient mod posibil.

<?php
$db = new PDO('odbc:SAMPLE', 'db2inst1', 'ibmdb2');
$stmt = $db->prepare("insert into images (id, contenttype, imagedata) values (?, ?, ?)");
$id = get_new_id(); // some function to allocate a new ID

// assume that we are running as part of a file upload form


// You can find more information in the PHP documentation

$fp = fopen($_FILES['file']['tmp_name'], 'rb');

$stmt->bindParam(1, $id);
$stmt->bindParam(2, $_FILES['file']['type']);
$stmt->bindParam(3, $fp, PDO::PARAM_LOB);

$db->beginTransaction();
$stmt->execute();
$db->commit();
?>

class PDO {
/* Constants */
public const int PARAM_NULL;
public const int PARAM_BOOL = 5;
public const int PARAM_INT = 1;
public const int PARAM_STR = 2;
public const int PARAM_LOB = 3;
public const int PARAM_STMT = 4;
public const int PARAM_INPUT_OUTPUT;
public const int PARAM_STR_NATL;
public const int PARAM_STR_CHAR;
public const int PARAM_EVT_ALLOC;
public const int PARAM_EVT_FREE;
public const int PARAM_EVT_EXEC_PRE;
public const int PARAM_EVT_EXEC_POST;
public const int PARAM_EVT_FETCH_PRE;
public const int PARAM_EVT_FETCH_POST;
public const int PARAM_EVT_NORMALIZE;
public const int FETCH_DEFAULT;
public const int FETCH_LAZY;
public const int FETCH_ASSOC;
public const int FETCH_NUM;
public const int FETCH_BOTH;
public const int FETCH_OBJ;
public const int FETCH_BOUND;
public const int FETCH_COLUMN;
public const int FETCH_CLASS;
public const int FETCH_INTO;
public const int FETCH_FUNC;
public const int FETCH_GROUP;
public const int FETCH_UNIQUE;
public const int FETCH_KEY_PAIR;
public const int FETCH_CLASSTYPE;
public const int FETCH_SERIALIZE;
public const int FETCH_PROPS_LATE;
public const int FETCH_NAMED;
public const int ATTR_AUTOCOMMIT;
public const int ATTR_PREFETCH;
public const int ATTR_TIMEOUT;
public const int ATTR_ERRMODE;
public const int ATTR_SERVER_VERSION;
public const int ATTR_CLIENT_VERSION;
public const int ATTR_SERVER_INFO;
public const int ATTR_CONNECTION_STATUS;
public const int ATTR_CASE;
public const int ATTR_CURSOR_NAME;
public const int ATTR_CURSOR;
public const int ATTR_ORACLE_NULLS;
public const int ATTR_PERSISTENT;
public const int ATTR_STATEMENT_CLASS;
public const int ATTR_FETCH_TABLE_NAMES;
public const int ATTR_FETCH_CATALOG_NAMES;
public const int ATTR_DRIVER_NAME;
public const int ATTR_STRINGIFY_FETCHES;
public const int ATTR_MAX_COLUMN_LEN;
public const int ATTR_EMULATE_PREPARES;
public const int ATTR_DEFAULT_FETCH_MODE;
public const int ATTR_DEFAULT_STR_PARAM;
public const int ERRMODE_SILENT;
public const int ERRMODE_WARNING;
public const int ERRMODE_EXCEPTION;
public const int CASE_NATURAL;
public const int CASE_LOWER;
public const int CASE_UPPER;
public const int NULL_NATURAL;
public const int NULL_EMPTY_STRING;
public const int NULL_TO_STRING;
public const string ERR_NONE;
public const int FETCH_ORI_NEXT;
public const int FETCH_ORI_PRIOR;
public const int FETCH_ORI_FIRST;
public const int FETCH_ORI_LAST;
public const int FETCH_ORI_ABS;
public const int FETCH_ORI_REL;
public const int CURSOR_FWDONLY;
public const int CURSOR_SCROLL;

/* Methods */
public __construct(
string $dsn,
?string $username = null,
#[\SensitiveParameter] ?string $password = null,
?array $options = null
)
public beginTransaction(): bool
public commit(): bool
public static connect(
string $dsn,
?string $username = null,
#[\SensitiveParameter] ?string $password = null,
?array $options = null
): static
public errorCode(): ?string
public errorInfo(): array
public exec(string $statement): int|false
public getAttribute(int $attribute): mixed
public static getAvailableDrivers(): array
public inTransaction(): bool
public lastInsertId(?string $name = null): string|false
public prepare(string $query, array $options = []): PDOStatement|false
public query(string $query, ?int $fetchMode = null): PDOStatement|false
public query(string $query, ?int $fetchMode = PDO::FETCH_COLUMN, int
$colno): PDOStatement|false
public query(
string $query,
?int $fetchMode = PDO::FETCH_CLASS,
string $classname,
array $constructorArgs
): PDOStatement|false
public query(string $query, ?int $fetchMode = PDO::FETCH_INTO, object
$object): PDOStatement|false
public quote(string $string, int $type = PDO::PARAM_STR): string|false
public rollBack(): bool
public setAttribute(int $attribute, mixed $value): bool
}
PDO::beginTransaction — Inițiază o tranzacție
PDO::commit — Commite o tranzacție
PDO::connect — Conectați-vă la o bază de date și returnați o subclasă PDO pentru driverele care o
acceptă
PDO::__construct — Creează o instanță PDO reprezentând o conexiune la o bază de date
PDO::errorCode — Preluați SQLSTATE asociat cu ultima operațiune pe handle-ul bazei de date
PDO::errorInfo — Preluați informații de eroare extinse asociate cu ultima operațiune pe handle-ul
bazei de date
PDO::exec — Execută o instrucțiune SQL și returnează numărul de rânduri afectate
PDO::getAttribute — Preluați un atribut de conexiune la baza de date
PDO::getAvailableDrivers — Returnează o serie de drivere PDO disponibile
PDO::inTransaction — Verifică dacă este în interiorul unei tranzacții
PDO::lastInsertId — Returnează ID-ul ultimei valori de rând sau secvență inserată
PDO::prepare — Pregătește o instrucțiune pentru execuție și returnează un obiect instrucțiune
PDO::query — Pregătește și execută o instrucțiune SQL fără substituenți
PDO::quote — Indică un șir de caractere pentru a fi utilizat într-o interogare
PDO::rollBack — Derulează înapoi o tranzacție
PDO::setAttribute — Setați un atribut

class PDOStatement implements IteratorAggregate {


/* Properties */
public string $queryString;

/* Methods */
public bindColumn(
string|int $column,
mixed &$var,
int $type = PDO::PARAM_STR,
int $maxLength = 0,
mixed $driverOptions = null
): bool
public bindParam(
string|int $param,
mixed &$var,
int $type = PDO::PARAM_STR,
int $maxLength = 0,
mixed $driverOptions = null
): bool
public bindValue(string|int $param, mixed $value, int $type = PDO::PARAM_STR):
bool
public closeCursor(): bool
public columnCount(): int
public debugDumpParams(): ?bool
public errorCode(): ?string
public errorInfo(): array
public execute(?array $params = null): bool
public fetch(int $mode = PDO::FETCH_DEFAULT, int $cursorOrientation =
PDO::FETCH_ORI_NEXT, int $cursorOffset = 0): mixed
public fetchAll(int $mode = PDO::FETCH_DEFAULT): array
public fetchAll(int $mode = PDO::FETCH_COLUMN, int $column): array
public fetchAll(int $mode = PDO::FETCH_CLASS, string $class, ?array
$constructorArgs): array
public fetchAll(int $mode = PDO::FETCH_FUNC, callable $callback): array
public fetchColumn(int $column = 0): mixed
public fetchObject(?string $class = "stdClass", array $constructorArgs = []): object|
false
public getAttribute(int $name): mixed
public getColumnMeta(int $column): array|false
public getIterator(): Iterator
public nextRowset(): bool
public rowCount(): int
public setAttribute(int $attribute, mixed $value): bool
public setFetchMode(int $mode): bool
public setFetchMode(int $mode = PDO::FETCH_COLUMN, int $colno): bool
public setFetchMode(int $mode = PDO::FETCH_CLASS, string $class, ?array
$constructorArgs = null): bool
public setFetchMode(int $mode = PDO::FETCH_INTO, object $object): bool
}

PDOStatement::bindColumn — Leagă o coloană la o variabilă PHP


PDOStatement::bindParam — Leagă un parametru la numele variabilei specificat
PDOStatement::bindValue — Leagă o valoare la un parametru
PDOStatement::closeCursor — Închide cursorul, permițând executarea din nou a instrucțiunii
PDOStatement::columnCount — Returnează numărul de coloane din setul de rezultate
PDOStatement::debugDumpParams — Eliminați o comandă pregătită SQL
PDOStatement::errorCode — Preluați SQLSTATE asociat cu ultima operație de pe handle-ul
instrucțiunii
PDOStatement::errorInfo — Preluați informații de eroare extinse asociate cu ultima operațiune de
pe mânerul instrucțiunii
PDOStatement::execute — Execută o instrucțiune pregătită
PDOStatement::fetch — Preia următorul rând dintr-un set de rezultate
PDOStatement::fetchAll — Preia rândurile rămase dintr-un set de rezultate
PDOStatement::fetchColumn — Returnează o singură coloană de pe următorul rând al unui set de
rezultate
PDOStatement::fetchObject — Preia următorul rând și îl returnează ca obiect
PDOStatement::getAttribute — Preluați un atribut de instrucțiune
PDOStatement::getColumnMeta — Returnează metadate pentru o coloană dintr-un set de rezultate
PDOStatement::getIterator — Obține iteratorul setului de rezultate
PDOStatement::nextRowset — Avansează la următorul set de rânduri într-un handle de instrucțiune
cu mai multe rânduri
PDOStatement::rowCount — Returnează numărul de rânduri afectate de ultima instrucțiune SQL
PDOStatement::setAttribute — Setează un atribut de instrucțiune
PDOStatement::setFetchMode — Setați modul de preluare implicit pentru această instrucțiune
class PDOException extends RuntimeException {
/* Properties */
protected int|string $code;
public ?array $errorInfo = null;
/* Inherited properties */
protected string $message = "";
private string $string = "";
protected int $code;
protected string $file = "";
protected int $line;
private array $trace = [];
private ?Throwable $previous = null;
/* Inherited methods */
public Exception::__construct(string $message = "", int $code = 0, ?Throwable
$previous = null)
final public Exception::getMessage(): string
final public Exception::getPrevious(): ?Throwable
final public Exception::getCode(): int
final public Exception::getFile(): string
final public Exception::getLine(): int
final public Exception::getTrace(): array
final public Exception::getTraceAsString(): string
public Exception::__toString(): string
private Exception::__clone(): void
}

36. MYSQL

Important Există mai multe API-uri PHP pentru accesarea bazei de date MySQL. Utilizatorii pot
alege între extensiile mysqli sau PDO_MySQL.

Important Această secțiune explică opțiunile pentru conectarea aplicațiilor PHP la MySQL și
clarifică termeni esențiali:
1. API (Interfață de Programare a Aplicației): Definește clasele, funcțiile și metodele pentru
comunicarea cu baza de date. API-urile pot fi procedurale (apelare funcții) sau orientate pe
obiecte (instanțiere clase și apelare metode), preferându-se abordarea orientată pe obiecte
pentru organizare mai bună.
2. Conector: Software care permite aplicației PHP să comunice cu serverul MySQL, asigurând
conexiunea și gestionarea comunicării, inclusiv cu alte biblioteci intermediare.
3. Driver: Software specific pentru comunicarea cu un anumit tip de bază de date. De
exemplu, driverul PDO MySQL facilitează interacțiunea între stratul PDO și serverul
MySQL. Termenii „conector” și „driver” sunt uneori folosiți interschimbabil, dar un driver
reprezintă partea specifică bazei de date a unui conector.
4. Extensie: În PHP, extensiile sunt componente care extind funcționalitatea de bază a
limbajului. De exemplu, extensia mysqli expune un API pentru MySQL, iar extensia PDO
MySQL furnizează o interfață către stratul PDO, fără a expune direct un API
programatorului.
Termenii API, conector, driver și extensie au roluri distincte, fiind esențiali pentru dezvoltarea
aplicațiilor conectate la baze de date MySQL.
Important PHP oferă diferite API-uri pentru conectarea la MySQL. Mai jos arătăm API-urile
furnizate de extensiile mysqli și PDO. Fiecare fragment de cod creează o conexiune la un server
MySQL care rulează pe „[Link]” folosind numele de utilizator „utilizator” și parola „parolă”.
Și se execută o interogare pentru a saluta utilizatorul.

Compararea API-urilor MySQL


<?php
// mysqli
$mysqli = new mysqli("[Link]", "user", "password", "database");
$result = $mysqli->query("SELECT 'Hello, dear MySQL user!' AS _message FROM DUAL");
$row = $result->fetch_assoc();
echo htmlentities($row['_message']);

// PDO
$pdo = new PDO('mysql:host=[Link];dbname=database', 'user', 'password');
$statement = $pdo->query("SELECT 'Hello, dear MySQL user!' AS _message FROM DUAL");
$row = $statement->fetch(PDO::FETCH_ASSOC);
echo htmlentities($row['_message']);

Compararea declarațiilor pregătite


<?php
// mysqli
$mysqli = new mysqli("[Link]", "user", "password", "database");
$statement = $mysqli->prepare("SELECT District FROM City WHERE Name=?");
$statement->execute(["Amersfoort"]);
$result = $statement->get_result();
$row = $result->fetch_assoc();
echo htmlentities($row['District']);

// PDO
$pdo = new PDO('mysql:host=[Link];dbname=database', 'user', 'password');
$statement = $pdo->prepare("SELECT District FROM City WHERE Name=?");
$statement->execute(["Amersfoort"]);
$row = $statement->fetch(PDO::FETCH_ASSOC);
echo htmlentities($row['District']);

Important Extensiile PHP mysqli și PDO_MySQL sunt pachete ușoare deasupra unei biblioteci
client C. Extensiile pot folosi fie biblioteca mysqlnd, fie biblioteca libmysqlclient. Alegerea unei
biblioteci este o decizie de compilare.
Important Biblioteca mysqlnd face parte din distribuția PHP. Oferă funcții precum conexiuni leneșe
și stocarea în cache a interogărilor, caracteristici care nu sunt disponibile cu libmysqlclient, așa că
este foarte recomandată utilizarea bibliotecii încorporate mysqlnd. Consultați documentația
mysqlnd pentru detalii suplimentare și o listă de caracteristici și funcționalități pe care le oferă.

// Recommended, compiles with mysqlnd


$ ./configure --with-mysqli=mysqlnd --with-pdo-mysql=mysqlnd

// Alternatively recommended, compiles with mysqlnd


$ ./configure --with-mysqli --with-pdo-mysql

// Not recommended, compiles with libmysqlclient


$ ./configure --with-mysqli=/path/to/mysql_config
--with-pdo-mysql=/path/to/mysql_config
Important Interogările MySQL sunt tamponate în mod implicit, ceea ce înseamnă că rezultatele sunt
transferate imediat pe partea PHP și stocate în memorie. Aceasta permite numărarea rândurilor,
navigarea în rezultate și emiterea de interogări suplimentare pe aceeași conexiune, dar necesită mai
multă memorie, în special pentru seturi de rezultate mari. Memoria este eliberată automat la finalul
cererii sau când setul de rezultate este eliberat explicit.
Important Interogările fără tampon, în schimb, preiau datele treptat de la server, utilizând mai puțină
memorie în PHP, dar cresc sarcina pe server și limitează utilizarea conexiunii până la preluarea
completă a datelor. Acestea sunt recomandate doar pentru seturi mari de rezultate procesate
secvențial, fiind mai greu de utilizat și mai restrictive, de exemplu, numărul total de rânduri nu este
cunoscut până la preluarea completă.
Important Interogările tamponate sunt mai simple și flexibile, motiv pentru care sunt utilizate
implicit.

Exemplu de interogare fără tampon: mysqli


<?php
$mysqli = new mysqli("localhost", "my_user", "my_password", "world");
$unbufferedResult = $mysqli->query("SELECT Name FROM City", MYSQLI_USE_RESULT);

foreach ($unbufferedResult as $row) {


echo $row['Name'] . PHP_EOL;
}
?>

Exemplu de interogare fără tampon: pdo_mysql


<?php
$pdo = new PDO("mysql:host=localhost;dbname=world", 'my_user', 'my_password');
$pdo->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, false);

$unbufferedResult = $pdo->query("SELECT Name FROM City");


foreach ($unbufferedResult as $row) {
echo $row['Name'] . PHP_EOL;
}
?>

Important Setul de caractere trebuie înțeles și definit, deoarece are un efect asupra fiecărei acțiuni și
include implicații de securitate. De exemplu, mecanismul de evadare (de exemplu,
mysqli_real_escape_string() pentru mysqli și PDO::quote() pentru PDO_MySQL) va adera la
această setare. Este important să realizați că aceste funcții nu vor folosi setul de caractere care este
definit cu o interogare, deci, de exemplu, următoarele nu vor avea efect asupra lor:

Probleme cu setarea setului de caractere cu SQL


<?php
$mysqli = new mysqli("localhost", "my_user", "my_password", "world");
// Will NOT affect $mysqli->real_escape_string();
$mysqli->query("SET NAMES utf8mb4");
// Will NOT affect $mysqli->real_escape_string();
$mysqli->query("SET CHARACTER SET utf8mb4");
// But, this will affect $mysqli->real_escape_string();
$mysqli->set_charset('utf8mb4');
// But, this will NOT affect it (UTF-8 vs utf8mb4) -- don't use dashes here
$mysqli->set_charset('UTF-8');
?>

Setarea exemplului setului de caractere: mysqli


<?php
$mysqli = new mysqli("localhost", "my_user", "my_password", "world");

echo 'Initial character set: ' . $mysqli->character_set_name() . "\n";

if (!$mysqli->set_charset('utf8mb4')) {
printf("Error loading character set utf8mb4: %s\n", $mysqli->error);
exit;
}

echo 'Your current character set is: ' . $mysqli->character_set_name() . "\n";


?>

Setarea exemplului setului de caractere: pdo_mysql


<?php
$pdo = new PDO("mysql:host=localhost;dbname=world;charset=utf8mb4", 'my_user', 'my_pass');
?>

Acest text oferă o introducere în opțiunile de conectare a aplicațiilor PHP la o bază de date MySQL,
discutând concepte precum API-uri, conectori, drivere și extensii:
1. API-uri: Definează funcții, clase și metode necesare pentru comunicarea aplicației PHP cu
bazele de date. Pot fi procedurale (funcții apelate direct) sau orientate pe obiecte (clase și
metode). API-urile orientate pe obiecte sunt preferate pentru cod mai organizat.
2. Conectori: Software care permite aplicației să se conecteze la MySQL, gestionând
comunicarea între PHP și serverul bazei de date.
3. Drivere: Module software specializate pentru interacțiunea cu un tip specific de server de
baze de date. De exemplu, driverul PDO MySQL permite stratului PDO să comunice cu
MySQL.
4. Extensii: Module PHP care extind funcționalitatea de bază, expunând API-uri sau funcții
specifice pentru MySQL, precum mysqli sau PDO MySQL.
5. API-uri MySQL principale în PHP:
• Extensia mysqli: Include interfață orientată pe obiecte și procedurală, suport pentru
declarații pregătite, tranzacții, declarații multiple și depanare.
• PDO (PHP Data Objects): Strat de abstractizare pentru baze de date care suportă
mai multe tipuri de drivere.
Extensia mysqli este recomandată pentru utilizarea funcțiilor avansate disponibile în MySQL 4.1.3
și versiunile ulterioare.
Important Extensia mysqli are o interfață duală. Suportă paradigma de programare procedurală și
orientată pe obiecte.
Important Utilizatorii care migrează de la vechea extensie mysql pot prefera interfața procedurală.
Interfața procedurală este similară cu cea a vechii extensii mysql. În multe cazuri, numele funcțiilor
diferă doar prin prefix. Unele funcții mysqli iau un mâner de conexiune ca prim argument, în timp
ce funcțiile de potrivire din vechea interfață mysql îl iau ca un ultim argument opțional.

Migrare ușoară de la vechea extensie mysql


<?php
$mysqli = mysqli_connect("[Link]", "user", "password", "database");
$result = mysqli_query($mysqli, "SELECT 'Please do not use the deprecated mysql extension for
new development. ' AS _msg FROM DUAL");
$row = mysqli_fetch_assoc($result);
echo $row['_msg'];

$mysql = mysql_connect("[Link]", "user", "password");


mysql_select_db("test");
$result = mysql_query("SELECT 'Use the mysqli extension instead.' AS _msg FROM DUAL",
$mysql);
$row = mysql_fetch_assoc($result);
echo $row['_msg'];

Interfață orientată pe obiect și procedurală


<?php

$mysqli = mysqli_connect("[Link]", "user", "password", "database");

$result = mysqli_query($mysqli, "SELECT 'A world full of ' AS _msg FROM DUAL");
$row = mysqli_fetch_assoc($result);
echo $row['_msg'];

$mysqli = new mysqli("[Link]", "user", "password", "database");

$result = $mysqli->query("SELECT 'choices to please everybody.' AS _msg FROM DUAL");


$row = $result->fetch_assoc();
echo $row['_msg'];

Important Serverul MySQL acceptă utilizarea diferitelor straturi de transport pentru conexiuni.
Conexiunile folosesc TCP/IP, socketuri de domeniu Unix sau conducte numite Windows.
Important Numele de gazdă localhost are o semnificație specială. Este legat de utilizarea socket-
urilor de domeniu Unix. Pentru a deschide o conexiune TCP/IP la localhost, trebuie folosit
[Link] în locul numelui de gazdă localhost.

<?php
$mysqli = new mysqli("localhost", "user", "password", "database");
echo $mysqli->host_info . "\n";
$mysqli = new mysqli("[Link]", "user", "password", "database", 3306);
echo $mysqli->host_info . "\n";

Localhost via UNIX socket


[Link] via TCP/IP
Important Acest text explică valorile implicite și opțiunile disponibile pentru conexiunile PHP-
MySQL folosind extensia mysqli:
1. Valori implicite pentru conexiuni:
• Pe Unix, conexiunile implicite utilizează socket-ul Unix /tmp/[Link] dacă
gazda este nesetată sau goală.
• Pe Windows, gazda . implică o conexiune prin conducte denumite, utilizând implicit
\\.\pipe\MySQL.
• Dacă nu se utilizează socket-uri Unix sau conducte, portul implicit este 3306.
2. Opțiuni de conectare:
• Se pot seta opțiuni (ex.: setări de caractere, comenzi de inițializare) înainte de
stabilirea conexiunii.
• Procesul implică trei pași: inițializarea conexiunii cu mysqli_init(), setarea
opțiunilor cu mysqli::options() și conectarea cu
mysqli::real_connect().
3. Pooling de conexiuni:
• Conexiuni persistente: Rămân deschise după terminarea unui script și sunt
reutilizate dacă se solicită aceeași combinație de gazdă, utilizator, parolă, socket, port
și bază de date.
• Fiecare proces PHP are propriul pool de conexiuni.
4. Gestionarea conexiunilor persistente:
• Dacă nu există o conexiune disponibilă în pool, se creează una nouă.
• Conexiunile persistente sunt resetate implicit înainte de reutilizare folosind
mysqli::change_user() pentru a elimina stările anterioare (ex.: tranzacții
deschise).
• Resetarea conexiunii oferă siguranță, dar implică un cost de performanță.
5. Optimizare:
• Comportamentul implicit prioritizează siguranța (resetarea conexiunii), dar
utilizatorii pot ajusta setările pentru a maximiza performanța (ex.: recompilarea cu
MYSQLI_NO_CHANGE_USER_ON_PCONNECT).
Alegerea între performanță și siguranță depinde de cerințele aplicației.

Important Declarațiile pot fi executate cu mysqli::query(), mysqli::real_query() și


mysqli::multi_query(). Funcția mysqli::query() este cea mai comună și combină instrucțiunea de
execuție cu o preluare în tampon a setului de rezultate, dacă există, într-un singur apel. Apelarea
mysqli::query() este identică cu apelarea mysqli::real_query() urmată de mysqli::store_result().

<?php

mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
$mysqli = new mysqli("[Link]", "user", "password", "database");

$mysqli->query("DROP TABLE IF EXISTS test");


$mysqli->query("CREATE TABLE test(id INT)");
Important După executarea instrucțiunii, rezultatele pot fi fie preluate dintr-o dată, fie citite rând cu
rând de pe server. Buffering-ul setului de rezultate la nivelul clientului permite serverului să
elibereze resursele asociate cu rezultatele declarației cât mai curând posibil. În general, clienții
consumă lent seturi de rezultate. Prin urmare, se recomandă utilizarea seturilor de rezultate
tamponate. mysqli::query() combină execuția instrucțiunilor și tamponarea setului de rezultate.

<?php

mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
$mysqli = new mysqli("[Link]", "user", "password", "database");

$mysqli->query("DROP TABLE IF EXISTS test");


$mysqli->query("CREATE TABLE test(id INT)");
$mysqli->query("INSERT INTO test(id) VALUES (1), (2), (3)");

$result = $mysqli->query("SELECT id FROM test ORDER BY id ASC");

echo "Reverse order...\n";


for ($row_no = $result->num_rows - 1; $row_no >= 0; $row_no--) {
$result->data_seek($row_no);
$row = $result->fetch_assoc();
echo " id = " . $row['id'] . "\n";
}

echo "Result set order...\n";


foreach ($result as $row) {
echo " id = " . $row['id'] . "\n";
}

Output:

Reverse order...
id = 3
id = 2
id = 1
Result set order...
id = 1
id = 2
id = 3

Important Funcțiile mysqli::query(), mysqli::real_query() și mysqli::multi_query() sunt folosite


pentru a executa instrucțiuni nepregătite. La nivelul protocolului MySQL Client Server, comanda
COM_QUERY și protocolul text sunt folosite pentru executarea instrucțiunilor. Cu protocolul text,
serverul MySQL convertește toate datele unui set de rezultate în șiruri de caractere înainte de
trimitere. Această conversie se face indiferent de tipul de date din coloana setului de rezultate SQL.
Bibliotecile client mysql primesc toate valorile coloanelor ca șiruri. Nu se mai face nicio turnare pe
partea clientului pentru a converti coloanele înapoi în tipurile lor native. În schimb, toate valorile
sunt furnizate ca șiruri PHP.
<?php

mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
$mysqli = new mysqli("[Link]", "user", "password", "database");

$mysqli->query("DROP TABLE IF EXISTS test");


$mysqli->query("CREATE TABLE test(id INT, label CHAR(1))");
$mysqli->query("INSERT INTO test(id, label) VALUES (1, 'a')");

$result = $mysqli->query("SELECT id, label FROM test WHERE id = 1");


$row = $result->fetch_assoc();

printf("id = %s (%s)\n", $row['id'], gettype($row['id']));


printf("label = %s (%s)\n", $row['label'], gettype($row['label']));

Output:
id = 1 (string)
label = a (string)

Important Execuția instrucțiunii pregătite constă din două etape: pregătire și execuție. În etapa de
pregătire, un șablon de declarație este trimis la serverul bazei de date. Serverul efectuează o
verificare de sintaxă și inițializează resursele interne ale serverului pentru utilizare ulterioară.

<?php

mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
$mysqli = new mysqli("[Link]", "user", "password", "database");

/* Non-prepared statement */
$mysqli->query("DROP TABLE IF EXISTS test");
$mysqli->query("CREATE TABLE test(id INT, label TEXT)");

/* Prepared statement, stage 1: prepare */


$stmt = $mysqli->prepare("INSERT INTO test(id, label) VALUES (?, ?)");

/* Prepared statement, stage 2: bind and execute */


$id = 1;
$label = 'PHP';
$stmt->bind_param("is", $id, $label); // "is" means that $id is bound as an integer and $label as a
string

$stmt->execute();

Important O instrucțiune pregătită poate fi executată în mod repetat. La fiecare execuție, valoarea
curentă a variabilei legate este evaluată și trimisă la server. Declarația nu este analizată din nou.
Șablonul de declarație nu este transferat din nou pe server.
<?php

mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
$mysqli = new mysqli("[Link]", "user", "password", "database");

/* Non-prepared statement */
$mysqli->query("DROP TABLE IF EXISTS test");
$mysqli->query("CREATE TABLE test(id INT, label TEXT)");

/* Prepared statement, stage 1: prepare */


$stmt = $mysqli->prepare("INSERT INTO test(id, label) VALUES (?, ?)");

/* Prepared statement, stage 2: bind and execute */


$stmt->bind_param("is", $id, $label); // "is" means that $id is bound as an integer and $label as a
string

$data = [
1 => 'PHP',
2 => 'Java',
3 => 'C++'
];
foreach ($data as $id => $label) {
$stmt->execute();
}

$result = $mysqli->query('SELECT id, label FROM test');


var_dump($result->fetch_all(MYSQLI_ASSOC));

Important Declarațiile pregătite consumă resurse serverului și trebuie închise explicit după
utilizare. Dacă nu sunt închise, ele se închid automat când handle-ul este eliberat. În unele cazuri,
utilizarea instrucțiunilor pregătite poate fi mai puțin eficientă, deoarece execuția lor o singură dată
presupune mai multe interacțiuni client-server decât o instrucțiune nepregătită. De asemenea, pentru
operațiuni de tip INSERT, se recomandă utilizarea sintaxei MySQL multi-INSERT, care necesită
mai puține călătorii client-server.

<?php

mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
$mysqli = new mysqli("[Link]", "user", "password", "database");

$mysqli->query("DROP TABLE IF EXISTS test");


$mysqli->query("CREATE TABLE test(id INT)");

$values = [1, 2, 3, 4];

$stmt = $mysqli->prepare("INSERT INTO test(id) VALUES (?), (?), (?), (?)");


$stmt->bind_param('iiii', ...$values);
$stmt->execute();
Important Protocolul MySQL Client Server definește un protocol diferit de transfer de date pentru
declarațiile pregătite și declarațiile nepregătite. Declarațiile pregătite folosesc așa-numitul protocol
binar. Serverul MySQL trimite datele setului de rezultate „ca atare” în format binar. Rezultatele nu
sunt serializate în șiruri de caractere înainte de trimitere. Bibliotecile client primesc date binare și
încearcă să convertească valorile în tipuri de date PHP adecvate. De exemplu, rezultatele dintr-o
coloană SQL INT vor fi furnizate ca variabile întregi PHP.

<?php

mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
$mysqli = new mysqli("[Link]", "user", "password", "database");

/* Non-prepared statement */
$mysqli->query("DROP TABLE IF EXISTS test");
$mysqli->query("CREATE TABLE test(id INT, label TEXT)");
$mysqli->query("INSERT INTO test(id, label) VALUES (1, 'PHP')");

$stmt = $mysqli->prepare("SELECT id, label FROM test WHERE id = 1");


$stmt->execute();
$result = $stmt->get_result();
$row = $result->fetch_assoc();

printf("id = %s (%s)\n", $row['id'], gettype($row['id']));


printf("label = %s (%s)\n", $row['label'], gettype($row['label']));

Important Rezultatele din instrucțiunile pregătite pot fi fie preluate prin legarea variabilelor de
ieșire, fie prin solicitarea unui obiect mysqli_result. Variabilele de ieșire trebuie să fie legate după
executarea instrucțiunii. O variabilă trebuie să fie legată pentru fiecare coloană a setului de rezultate
de instrucțiuni.

<?php

mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
$mysqli = new mysqli("[Link]", "user", "password", "database");

/* Non-prepared statement */
$mysqli->query("DROP TABLE IF EXISTS test");
$mysqli->query("CREATE TABLE test(id INT, label TEXT)");
$mysqli->query("INSERT INTO test(id, label) VALUES (1, 'PHP')");

$stmt = $mysqli->prepare("SELECT id, label FROM test WHERE id = 1");


$stmt->execute();

$stmt->bind_result($out_id, $out_label);

while ($stmt->fetch()) {
printf("id = %s (%s), label = %s (%s)\n", $out_id, gettype($out_id), $out_label,
gettype($out_label));
}
Important Procedurile stocate pot avea parametri IN, INOUT și OUT, în funcție de versiunea
MySQL. Interfața mysqli nu are o noțiune specială pentru diferitele tipuri de parametri.

<?php
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
$mysqli = new mysqli("[Link]", "user", "password", "database");

$mysqli->query("DROP TABLE IF EXISTS test");


$mysqli->query("CREATE TABLE test(id INT)");

$mysqli->query("DROP PROCEDURE IF EXISTS p");


$mysqli->query("CREATE PROCEDURE p(IN id_val INT) BEGIN INSERT INTO test(id)
VALUES(id_val); END;");

$mysqli->query("CALL p(1)");

$result = $mysqli->query("SELECT id FROM test");

var_dump($result->fetch_assoc());

Important Procedurile stocate pot returna seturi de rezultate. Seturile de rezultate returnate dintr-o
procedură stocată nu pot fi preluate corect folosind mysqli::query(). Funcția mysqli::query()
combină execuția instrucțiunilor și preluarea primului set de rezultate într-un set de rezultate
tamponat, dacă există. Cu toate acestea, există seturi suplimentare de rezultate de procedură stocată
ascunse utilizatorului, care fac ca mysqli::query() să nu returneze seturile de rezultate așteptate de
utilizator.
Important Seturile de rezultate returnate dintr-o procedură stocată sunt preluate folosind
mysqli::real_query() sau mysqli::multi_query(). Ambele funcții permit preluarea oricărui număr de
seturi de rezultate returnate de o instrucțiune, cum ar fi CALL. Eșecul de a prelua toate seturile de
rezultate returnate de o procedură stocată provoacă o eroare.

<?php
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
$mysqli = new mysqli("[Link]", "user", "password", "database");
$mysqli->query("DROP TABLE IF EXISTS test");
$mysqli->query("CREATE TABLE test(id INT)");
$mysqli->query("INSERT INTO test(id) VALUES (1), (2), (3)");

$mysqli->query("DROP PROCEDURE IF EXISTS p");


$mysqli->query('CREATE PROCEDURE p() READS SQL DATA BEGIN SELECT id FROM test;
SELECT id + 1 FROM test; END;');
$mysqli->multi_query("CALL p()");

do {
if ($result = $mysqli->store_result()) {
printf("---\n");
var_dump($result->fetch_all());
$result->free();
}
} while ($mysqli->next_result());
Important MySQL permite executarea mai multor instrucțiuni într-un singur șir, folosind
mysqli::multi_query(). Instrucțiunile sunt separate prin punct și virgulă, iar toate seturile de
rezultate trebuie preluate. Se pot combina instrucțiuni care returnează seturi de rezultate cu cele care
nu, într-o singură instrucțiune multiplă.

<?php

mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
$mysqli = new mysqli("[Link]", "user", "password", "database");

$mysqli->query("DROP TABLE IF EXISTS test");


$mysqli->query("CREATE TABLE test(id INT)");

$sql = "SELECT COUNT(*) AS _num FROM test;


INSERT INTO test(id) VALUES (1);
SELECT COUNT(*) AS _num FROM test; ";

$mysqli->multi_query($sql);

do {
if ($result = $mysqli->store_result()) {
var_dump($result->fetch_all(MYSQLI_ASSOC));
$result->free();
}
} while ($mysqli->next_result());

Output:
array(1) {
[0]=>
array(1) {
["_num"]=>
string(1) "0"
}
}
array(1) {
[0]=>
array(1) {
["_num"]=>
string(1) "1"
}
}

Important Funcțiile API mysqli::query() și mysqli::real_query() nu setează un indicator de


conexiune necesar pentru activarea interogărilor multiple pe server. Un apel API suplimentar este
utilizat pentru mai multe instrucțiuni pentru a reduce daunele atacurilor accidentale de injecție SQL.
Un atacator poate încerca să adauge instrucțiuni precum ; DROP DATABASE mysql sau ;
SELECTARE SLEEP(999). Dacă atacatorul reușește să adauge SQL la șirul de instrucțiuni, dar
mysqli::multi_query() nu este folosit, serverul nu va executa instrucțiunea SQL injectată și rău
intenționată.
<?php
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
$mysqli = new mysqli("[Link]", "user", "password", "database");
$result = $mysqli->query("SELECT 1; DROP TABLE [Link]");
?>

PHP Fatal error: Uncaught mysqli_sql_exception: You have an error in your SQL syntax;
check the manual that corresponds to your MySQL server version for the right syntax to
use near 'DROP TABLE [Link]' at line 1

Important Serverul MySQL acceptă tranzacții în funcție de motorul de stocare utilizat. Începând cu
MySQL 5.5, motorul de stocare implicit este InnoDB. InnoDB are suport complet pentru tranzacții
ACID. Tranzacțiile pot fi controlate folosind apeluri SQL sau API. Este recomandat să utilizați
apeluri API pentru activarea și dezactivarea modului de autocommit și pentru comiterea și anularea
tranzacțiilor.

<?php
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
$mysqli = new mysqli("[Link]", "user", "password", "database");

/* Recommended: using API to control transactional settings */


$mysqli->autocommit(false);

/* Won't be monitored and recognized by the replication and the load balancing plugin */
$mysqli->query('SET AUTOCOMMIT = 0');

Important Pachetele de caracteristici opționale, cum ar fi pluginul de replicare și echilibrare a


încărcăturii, pot monitoriza cu ușurință apelurile API. Pluginul de replicare oferă echilibrare a
încărcăturii în funcție de tranzacții, dacă tranzacțiile sunt controlate cu apeluri API. Echilibrarea
încărcăturii în funcție de tranzacție nu este disponibilă dacă instrucțiunile SQL sunt utilizate pentru
setarea modului de comitere automată, comiterea sau anularea unei tranzacții.

<?php
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
$mysqli = new mysqli("[Link]", "user", "password", "database");
$mysqli->autocommit(false);

$mysqli->query("INSERT INTO test(id) VALUES (1)");


$mysqli->rollback();

$mysqli->query("INSERT INTO test(id) VALUES (2)");


$mysqli->commit();

Important Un set de rezultate MySQL conține metadate. Metadatele descriu coloanele găsite în
setul de rezultate. Toate metadatele trimise de MySQL sunt accesibile prin interfața mysqli.
Extensia nu efectuează modificări sau modificări neglijabile ale informațiilor pe care le primește.
Diferențele dintre versiunile de server MySQL nu sunt aliniate. Metadatele este accesul prin
interfața mysqli_result.
<?php

mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
$mysqli = new mysqli("[Link]", "user", "password", "database");

$result = $mysqli->query("SELECT 1 AS _one, 'Hello' AS _two FROM DUAL");


var_dump($result->fetch_fields());

Important Metadatele seturilor de rezultate create folosind instrucțiuni pregătite sunt accesate în
același mod. Un handle adecvat pentru mysqli_result este returnat de
mysqli_stmt::result_metadata().

<?php

mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
$mysqli = new mysqli("[Link]", "user", "password", "database");

$stmt = $mysqli->prepare("SELECT 1 AS _one, 'Hello' AS _two FROM DUAL");


$stmt->execute();
$result = $stmt->result_metadata();
var_dump($result->fetch_fields());

Important Conexiunile persistente permit reutilizarea unei conexiuni între client și bază de date,
reducând costurile de creare a unor noi conexiuni. În mysqli, conexiunile persistente sunt deschise
prin adăugarea unui "p:" la numele gazdei. Totuși, aceste conexiuni pot lăsa stări imprevizibile dacă
un client nu le închide corespunzător. Mysqli gestionează curățarea automată a conexiunilor
persistente, incluzând rollback, închiderea tabelelor temporare, deblocarea meselor și resetarea
variabilelor de sesiune. Aceasta asigură că conexiunile sunt într-o stare curată la reutilizare. Totuși,
curățarea automată poate afecta performanța, iar aceasta poate fi dezactivată printr-o opțiune de
compilare a PHP.

class mysqli {
/* Properties */
public readonly int|string $affected_rows;
public readonly string $client_info;
public readonly int $client_version;
public readonly int $connect_errno;
public readonly ?string $connect_error;
public readonly int $errno;
public readonly string $error;
public readonly array $error_list;
public readonly int $field_count;
public readonly string $host_info;
public readonly ?string $info;
public readonly int|string $insert_id;
public readonly string $server_info;
public readonly int $server_version;
public readonly string $sqlstate;
public readonly int $protocol_version;
public readonly int $thread_id;
public readonly int $warning_count;
/* Methods */
public __construct(
?string $hostname = null,
?string $username = null,
#[\SensitiveParameter] ?string $password = null,
?string $database = null,
?int $port = null,
?string $socket = null
)
public autocommit(bool $enable): bool
public begin_transaction(int $flags = 0, ?string $name = null): bool
public change_user(string $username, #[\SensitiveParameter] string $password, ?string
$database): bool
public character_set_name(): string
public close(): true
public commit(int $flags = 0, ?string $name = null): bool
public connect(
?string $hostname = null,
?string $username = null,
#[\SensitiveParameter] ?string $password = null,
?string $database = null,
?int $port = null,
?string $socket = null
): bool
public debug(string $options): true
public dump_debug_info(): bool
public execute_query(string $query, ?array $params = null): mysqli_result|bool
public get_charset(): ?object
#[\Deprecated]
public get_client_info(): string
public get_connection_stats(): array
public get_server_info(): string
public get_warnings(): mysqli_warning|false
#[\Deprecated]
public init(): ?bool
#[\Deprecated]
public kill(int $process_id): bool
public more_results(): bool
public multi_query(string $query): bool
public next_result(): bool
public options(int $option, string|int $value): bool
#[\Deprecated]
public ping(): bool
public static poll(
?array &$read,
?array &$error,
array &$reject,
int $seconds,
int $microseconds = 0
): int|false
public prepare(string $query): mysqli_stmt|false
public query(string $query, int $result_mode = MYSQLI_STORE_RESULT):
mysqli_result|bool
public real_connect(
?string $hostname = null,
?string $username = null,
#[\SensitiveParameter] ?string $password = null,
?string $database = null,
?int $port = null,
?string $socket = null,
int $flags = 0
): bool
public real_escape_string(string $string): string
public real_query(string $query): bool
public reap_async_query(): mysqli_result|bool
#[\Deprecated]
public refresh(int $flags): bool
public release_savepoint(string $name): bool
public rollback(int $flags = 0, ?string $name = null): bool
public savepoint(string $name): bool
public select_db(string $database): bool
public set_charset(string $charset): bool
public ssl_set(
?string $key,
?string $certificate,
?string $ca_certificate,
?string $ca_path,
?string $cipher_algos
): true
public stat(): string|false
public stmt_init(): mysqli_stmt|false
public store_result(int $mode = 0): mysqli_result|false
public thread_safe(): bool
public use_result(): mysqli_result|false
}

mysqli::$affected_rows — Obține numărul de rânduri afectate într-o operațiune anterioară MySQL


mysqli::autocommit — Activează sau dezactivează modificarea automată a bazei de date
mysqli::begin_transaction — Pornește o tranzacție mysqli::change_user — Schimbă utilizatorul
conexiunii la baza de date
mysqli::character_set_name — Returnează setul de caractere curent al conexiunii la baza de date
mysqli::close — Închide o conexiune la baza de date deschisă anterior
mysqli::commit — Commite tranzacția curentă
mysqli::$connect_errno — Returnează codul de eroare de la ultimul apel de conectare mysqli::
$connect_error — Returnează o descriere a ultimei erori de conectare
mysqli::__construct — Deschide o nouă conexiune la serverul MySQL
mysqli::debug — Efectuează operațiuni de depanare
mysqli::dump_debug_info — Transferați informațiile de depanare în jurnal
mysqli::$errno — Returnează codul de eroare pentru cel mai recent apel de funcție
mysqli::$error — Returnează o descriere șir a ultimei erori
mysqli::$error_list — Returnează o listă de erori de la ultima comandă executată
mysqli::execute_query — Pregătește, leagă parametri și execută instrucțiunea SQL
mysqli::$field_count — Returnează numărul de coloane pentru cea mai recentă interogare
mysqli::get_charset — Returnează un obiect de set de caractere
mysqli::$client_info — Obține informații despre client MySQL
mysqli::$client_version — Returnează versiunea clientului MySQL ca număr întreg
mysqli::get_connection_stats — Returnează statistici despre conexiunea client
mysqli::$host_info — Returnează un șir reprezentând tipul de conexiune utilizat
mysqli::$protocol_version — Returnează versiunea protocolului MySQL utilizat
mysqli::$server_info — Returnează versiunea serverului MySQL
mysqli::$server_version — Returnează versiunea serverului MySQL ca număr întreg
mysqli::get_warnings — Obține rezultatul SHOW WARNINGS
mysqli::$info — Preia informații despre cea mai recentă interogare executată
mysqli::init — Inițializează MySQLi și returnează un obiect pentru utilizare cu
mysqli_real_connect()
mysqli::$insert_id — Returnează valoarea generată pentru o coloană AUTO_INCREMENT de
ultima interogare
mysqli::kill — Cere serverului să oprească un fir MySQL
mysqli::more_results — Verificați dacă mai există rezultate de interogare dintr-o interogare multiplă
mysqli::multi_query — Efectuează una sau mai multe interogări în baza de date
mysqli::next_result — Pregătește următorul rezultat din multi_query
mysqli::options — Setați opțiuni
mysqli::ping — trimite ping la o conexiune la server sau încearcă să se reconecteze dacă
conexiunea sa întrerupt
mysqli::poll — Conexiuni de sondaj
mysqli::prepare — Pregătește o instrucțiune SQL pentru execuție
mysqli::query — Efectuează o interogare pe baza de date
mysqli::real_connect — Deschide o conexiune la un server mysql
mysqli::real_escape_string — Escape caractere speciale dintr-un șir pentru a fi utilizate într-o
instrucțiune SQL, ținând cont de setul de caractere curent al conexiunii
mysqli::real_query — Execută o interogare SQL
mysqli::reap_async_query — Obține rezultatul unei interogări asincrone
mysqli::refresh — Reîmprospătează
mysqli::release_savepoint — Elimină punctul de salvare numit din setul de puncte de salvare ale
tranzacției curente
mysqli::rollback — Derulează înapoi tranzacția curentă
mysqli::savepoint — Setați un punct de salvare numit tranzacție
mysqli::select_db — Selectează baza de date implicită pentru interogările bazei de date
mysqli::set_charset — Setează setul de caractere client
mysqli::$sqlstate — Returnează eroarea SQLSTATE din operația anterioară MySQL
mysqli::ssl_set — Folosit pentru stabilirea de conexiuni sigure folosind SSL
mysqli::stat — Obține starea curentă a sistemului
mysqli::stmt_init — Inițializează o instrucțiune și returnează un obiect pentru utilizare cu
mysqli_stmt_prepare
mysqli::store_result — Transferă un set de rezultate din ultima interogare
mysqli::$thread_id — Returnează ID-ul firului pentru conexiunea curentă
mysqli::thread_safe — Returnează dacă siguranța firului este dată sau nu
mysqli::use_result — Inițiază o recuperare a unui set de rezultate
mysqli::$warning_count — Returnează numărul de avertismente generate de cea mai recentă
interogare executată
class mysqli_stmt {
/* Properties */
public readonly int|string $affected_rows;
public readonly int|string $insert_id;
public readonly int|string $num_rows;
public readonly int $param_count;
public readonly int $field_count;
public readonly int $errno;
public readonly string $error;
public readonly array $error_list;
public readonly string $sqlstate;
public int $id;

/* Methods */
public __construct(mysqli $mysql, ?string $query = null)
public attr_get(int $attribute): int
public attr_set(int $attribute, int $value): bool
public bind_param(string $types, mixed &$var, mixed &...$vars): bool
public bind_result(mixed &$var, mixed &...$vars): bool
public close(): true
public data_seek(int $offset): void
public execute(?array $params = null): bool
public fetch(): ?bool
public free_result(): void
public get_result(): mysqli_result|false
public get_warnings(): mysqli_warning|false
public more_results(): bool
public next_result(): bool
public num_rows(): int|string
public prepare(string $query): bool
public reset(): bool
public result_metadata(): mysqli_result|false
public send_long_data(int $param_num, string $data): bool
public store_result(): bool
}

mysqli_stmt::$affected_rows — Returnează numărul total de rânduri modificate, șterse, inserate sau


potrivite cu ultima instrucțiune executată
mysqli_stmt::attr_get — Folosit pentru a obține valoarea curentă a unui atribut de instrucțiune
mysqli_stmt::attr_set — Folosit pentru a modifica comportamentul unei instrucțiuni pregătite
mysqli_stmt::bind_param — Leagă variabilele la o instrucțiune pregătită ca parametri
mysqli_stmt::bind_result — Leagă variabilele la o instrucțiune pregătită pentru stocarea rezultatelor
mysqli_stmt::close — Închide o instrucțiune pregătită
mysqli_stmt::__construct — Construiește un nou obiect mysqli_stmt
mysqli_stmt::data_seek — Ajustează indicatorul de rezultat la un rând arbitrar din rezultatul stocat
în tampon
mysqli_stmt::$errno — Returnează codul de eroare pentru cel mai recent apel de instrucțiune
mysqli_stmt::$error — Returnează o descriere șir pentru ultima eroare de declarație
mysqli_stmt::$error_list — Returnează o listă de erori din ultima instrucțiune executată
mysqli_stmt::execute — Execută o instrucțiune pregătită
mysqli_stmt::fetch — Preluați rezultatele dintr-o instrucțiune pregătită în variabilele legate
mysqli_stmt::$field_count — Returnează numărul de coloane din instrucțiunea dată
mysqli_stmt::free_result — Eliberează memoria rezultată stocată pentru mânerul de instrucțiune dat
mysqli_stmt::get_result — Obține un set de rezultate dintr-o instrucțiune pregătită ca obiect
mysqli_result mysqli_stmt::get_warnings — Obține rezultatul SHOW WARNINGS
mysqli_stmt::$insert_id — Obține ID-ul generat din operația anterioară INSERT
mysqli_stmt::more_results — Verificați dacă există mai multe rezultate de interogare dintr-o
interogare multiplă
mysqli_stmt::next_result — Citește următorul rezultat dintr-o interogare multiplă
mysqli_stmt::$num_rows — Returnează numărul de rânduri preluate de pe server
mysqli_stmt::$param_count — Returnează numărul de parametri pentru instrucțiunea dată
mysqli_stmt::prepare — Pregătește o instrucțiune SQL pentru execuție
mysqli_stmt::reset — Resetează o instrucțiune pregătită
mysqli_stmt::result_metadata — Returnează metadatele setului de rezultate dintr-o declarație
pregătită
mysqli_stmt::send_long_data — Trimite date în blocuri
mysqli_stmt::$sqlstate — Returnează eroarea SQLSTATE din operația anterioară a instrucțiunii
mysqli_stmt::store_result — Stochează un set de rezultate într-un buffer intern

class mysqli_result implements IteratorAggregate {


/* Properties */
public readonly int $current_field;
public readonly int $field_count;
public readonly ?array $lengths;
public readonly int|string $num_rows;
public int $type;

/* Methods */
public __construct(mysqli $mysql, int $result_mode = MYSQLI_STORE_RESULT)
public data_seek(int $offset): bool
public fetch_all(int $mode = MYSQLI_NUM): array
public fetch_array(int $mode = MYSQLI_BOTH): array|null|false
public fetch_assoc(): array|null|false
public fetch_column(int $column = 0): null|int|float|string|false
public fetch_field(): object|false
public fetch_field_direct(int $index): object|false
public fetch_fields(): array
public fetch_object(string $class = "stdClass", array $constructor_args = []):
object|null|false
public fetch_row(): array|null|false
public field_seek(int $index): true
public free(): void
public close(): void
public free_result(): void
public getIterator(): Iterator
}

mysqli_result::__construct — Construiește un obiect mysqli_result


mysqli_result::$current_field — Obține decalajul câmpului curent al unui indicator de rezultat
mysqli_result::data_seek — Ajustează indicatorul de rezultat la un rând arbitrar din rezultat
mysqli_result::fetch_all — Preluați toate rândurile rezultate ca o matrice asociativă, o matrice
numerică sau ambele
mysqli_result::fetch_array — Preluați următorul rând al unui set de rezultate ca asociativ, o matrice
numerică sau ambele
mysqli_result::fetch_assoc — Preluează următorul rând al unui set de rezultate ca o matrice
asociativă
mysqli_result::fetch_column — Preluează o singură coloană de pe următorul rând al unui set de
rezultate
mysqli_result::fetch_field — Returnează următorul câmp din setul de rezultate
mysqli_result::fetch_field_direct — Preluați metadate pentru un singur câmp
mysqli_result::fetch_fields — Returnează o matrice de obiecte reprezentând câmpurile dintr-un set
de rezultate
mysqli_result::fetch_object — Preluează următorul rând al unui set de rezultate ca obiect
mysqli_result::fetch_row — Preluează următorul rând al unui set de rezultate ca o matrice
enumerată
mysqli_result::$field_count — Obține numărul de câmpuri din setul de rezultate
mysqli_result::field_seek — Setați indicatorul de rezultat la un câmp specificat
mysqli_result::free — Eliberează memoria asociată unui rezultat
mysqli_result::getIterator — Preluați un iterator extern
mysqli_result::$lengths — Returnează lungimile coloanelor rândului curent din setul de rezultate
mysqli_result::$num_rows — Obține numărul de rânduri din setul de rezultate

final class mysqli_driver {


/* Properties */
public readonly string $client_info;
public readonly int $client_version;
public readonly int $driver_version;
public int $report_mode;
}

mysqli_driver::embedded_server_end — Oprește serverul încorporat


mysqli_driver::embedded_server_start — Inițializați și porniți serverul încorporat
mysqli_driver::$report_mode — Setează modul de raportare a erorilor mysqli

final class mysqli_warning {


/* Properties */
public string $message;
public string $sqlstate;
public int $errno;

/* Methods */
private __construct()
public next(): bool
}

mysqli_warning::__construct — Constructor privat pentru a interzice instanțierea directă


mysqli_warning::next — Preluați următorul avertisment
final class mysqli_sql_exception extends RuntimeException {
/* Properties */
protected string $sqlstate = "00000";
/* Inherited properties */
protected string $message = "";
private string $string = "";
protected int $code;
protected string $file = "";
protected int $line;
private array $trace = [];
private ?Throwable $previous = null;

/* Methods */
public getSqlState(): string
/* Inherited methods */
public Exception::__construct(string $message = "", int $code = 0, ?Throwable
$previous = null)
final public Exception::getMessage(): string
final public Exception::getPrevious(): ?Throwable
final public Exception::getCode(): int
final public Exception::getFile(): string
final public Exception::getLine(): int
final public Exception::getTrace(): array
final public Exception::getTraceAsString(): string
public Exception::__toString(): string
private Exception::__clone(): void
}

mysqli_sql_exception::getSqlState — Returnează codul de eroare SQLSTATE

mysqli_connect — Alias pentru mysqli::__construct mysqli::escape_string — Alias pentru


mysqli_real_escape_string mysqli_execute — Alias pentru mysqli_stmt_execute
mysqli_get_client_stats — Returnează statistici client pe proces mysqli_get_links_stats —
Returnează informații despre linkurile deschise și stocate în cache mysqli_report — Alias pentru
mysqli_driver->report_mode mysqli::set_opt — Alias pentru mysqli_options

S-ar putea să vă placă și