Functii in PHP
Daca ai parcurs primele capitole ale acestui curs, ar trebui sa stii destul de mult PHP astfel incat sa poti crea scripturi simple proprii. Totusi, programele prezentate pana la acest punct sunt procedurale sau liniare, ceea ce inseamna ca instructiunile sunt executate secvential, una dupa alta.
Pe masura ce scripturile tale PHP vor deveni din ce in ce mai complexe, este doar o chestiune de timp pana ce vei intampina probleme datorita stilului de programare secvential. In acest tutorial, poti afla o noua metoda de a-ti organiza programul PHP, in care acesta nu este executat liniar, ci modular, prin salturi de la o bucata de cod la alta. Acest tip de programare se bazeaza in mod special pe o structura care poarta numele de ?functie? (?function?), care este creata o singura data, dar poate fi executata de mai multe ori. O functie primeste argumente (parametrii) si returneaza o valoare.
Definirea unei functii
O functie poate fii definita in mod clasic ca: ?o lista de instructiuni, grupate ca o singura entitate ce poate fi apelata prin intermediul unui nume?. Mai simplu, o functie reprezinta un set de instructiuni ce indeplinesc o anumita sarcina, si care pot si apelate si executate din orice punct al scriptului tau PHP.
In PHP, fiecare functie reprezinta un bloc de cod distinct. Codul unei functii este propriu acelei functii si nu poate fi accesat de nici o alta instructiune continuta intr-o alta functie, cu exceptia cazului in care este apelata functia. Codul care reprezinta corpul unei functii este ascuns fata de restul programului si, cu exceptia cazului in care foloseste date sau variabile globale, nu poate afecta si nu poate fi afectat de catre alte componente ale programului. In PHP, toate functiile au acelasi nivel al domeniului de actiune, adica nu se poate defini o functie in interiorul unei functii.
Orice limbaj de programare are un set de functii predefinite (built-in), pe baza carora un programator isi poate defini propriile functii.
Functiile sunt utile pentru ca:
1. functiile definite de catre utilizator permit separarea codului in subsectiuni mai usor de identificat, inteles si corectat.
2. cu ajutorul functiilor, poti crea un program modular, ce permite reutilizarea codului.
3. modificarile sunt mai usor de implementat, deoarece corpul unei functii este modificat o singura data (in definitia functiei), chiar daca in programul principal, el este apelat de mai multe ori.
Crearea unei functii
Iata un exemplu pentru a intelege cum opereaza o functie:
<?php // definitia functiei function myStandardResponse() { echo "Get lost, jerk!<br /><br />"; } // in autobuz echo "Hey lady, can you spare a dime? <br />"; myStandardResponse(); // la birou echo "Can you handle Joe's workload, in addition to your own, while he's in Tahiti for a month? You'll probably need to come in early and work till midnight, but we are confident you can handle it. Oh, and we can't pay you extra because of budgetary constraints...<br />"; myStandardResponse(); // la petrecere echo "Hi, haven't I seen you somewhere before?<br />"; myStandardResponse(); ?>
Codul de mai sus va afisa:
Hey lady, can you spare a dime?
Get lost, jerk!
Can you handle Joe’s workload, in addition to your own, while he’s in Tahiti for a month?
You’ll probably need to come in early and work till midnight, but we are confident you can
handle it. Oh, and we can’t pay you extra because of budgetary constraints…
Get lost, jerk!
Hi, haven’t I seen you somewhere before?
Get lost, jerk!
Primul lucru pe care scriptul de mai sus in face este sa defineasca o functie, utilizand cuvantul cheie function, urmat de numele functiei ? myStandardResponse(). Declaratiile care formeaza corpul functiei sunt plasate intre acolade, ele putand contine instructiuni conditionale sau repetitive (bucle), apeluri catre alte functii PHP sau functii definite de catre utilizator.
Definirea unei functii rezolva doar pe jumatate problema, deoarece ea trebuie sa fie si apelata. In PHP si in alte multe limbaje de programare, apelul unei functii se realizeaza prin intermediul numelui ei, ca in exemplul de mai sus. Invocarea unei functii definite de catre utilizator este la fel cu apelarea unei functii PHP native (built-in), cum ar fi echo().
Formatul standard pentru o functie este urmatorul:
function numele_functiei (parametrii optionali ai functiei) {
instructiune 1...
instructiune 2...
.
.
.
instructiune n...
}
Transmiterea parametrilor
Functiile asemanatoare celei din exemplul de mai sus vor afisa acelasi mesaj de fiecare data cand sunt apelate, ceea ce dupa un anumit timp poate deveni plictisitor. Poti face aceste functii mai interesante transmitand functiei diferite argumente care determina rezultate diferite ale executiei functiei.
Daca o functie urmeaza sa foloseasca argumente, trebuie sa declare variabile care sa accepte valorile argumentelor. Aceste variabile se numesc parametrii formali ai functiei. Acestia se comporta ca orice alta variabila locala in interiorul functiei, fiind creati la intrarea in functie si distrusi la iesire.
Daca datele de intrare (parametrii) difera, atunci si valoarea returnata de functie va fi alta.
Pentru a observa cum functioneaza acest mecanism, in exemplul urmator poti vedea o functie care primeste un singur argument (raza unui cerc) si afiseaza o valoare calculata utilizand valoarea acestuia (lungimea cercului). Dupa cum arata functia care urmeaza, declaratiile parametrilor survin dupa numele functiei:
// definitia functiei function getCircumference($radius) { echo "Circumferinta unui cerc cu raza $radius este ".sprintf("%4.2f", (2 * $radius * pi()))."<br />"; } // apelul functiei cu argumentul 10 getCircumference(10); // apelul functiei cu argumentul 20 getCircumference(20);
In acest exemplu, atunci cand functia getCircumference() este apelata, valorile 10, si apoi 20, sunt atribuite variabilei $radius, ce este ulterior utilizata de catre codul din corpul functiei.
Functiile pot fi apelate cu mai mult de un parametru, si anume cu o lista de parametrii separati prin virgula:
// definitia functiei function changeCase($str, $flag) { /* executa instructiunea indicata de variabila $flag */ switch($flag) { case 'U': print strtoupper($str)."<br />"; break; case 'L': print strtolower($str)."<br />"; break; default: print $str."<br />"; break; } } // apeleaza functia changeCase("The cow jumped over the moon", "U"); changeCase("Hello Sam", "L");
In functie de valoarea celui de-al doilea parametru, instructiunea switch selecteaza ramura corespunzatoare si manipuleaza primul argument.
PHP nu necesita precizarea tipurilor de date ale argumentelor care sunt transmise, acesta fiind identificate la executia scriptului. Ca si in cazul variabilelor locale, se pot face atribuiri parametrilor formali ai unei functii sau pot fi folositi in orice expresie permisa in PHP. Chiar daca aceste variabile au atributia speciala de a receptiona valoarea argumentelor transmise functiei, acestea pot fi folosite ca orice alta variabila locala.
Instructiunea return
Instructiunea return are doua utilizari importante. Mai intai, determina o iesire imediata din functia care o contine. Cu alte cuvinte, determina ca executia programului sa revina la codul de apel. In al doilea rand, poate fi folosita pentru a returna o valoare.
Exista doua metode prin care o functie isi inceteaza executia si revine la apel. Prima survine cand ultima instructiune din functie a fost executata si, conceptual vorbind, a fost intalnita acolada de inchidere. In realitate, nu sunt prea multe functii care folosesc aceasta metoda prestabilita de terminare a executiei. Majoritatea functiilor folosesc instructiunea return pentru a stopa executia, fie deoarece trebuie returnata o valoare, fie pentru a simplifica si mari eficienta codurilor functiei.
Nu uita, o functie poate contine mai multe instructiuni return.
Iata un exemplu de functie care foloseste return:
// definitia functiei function getCircumference($radius) { /* returneaza valoare (lungimea cercului calculata in functie de raza) */ return (2 * $radius * pi()); } /* apeleaza functia cu argumentul 10 si retine rezultatul in variabila $result */ $result = getCircumference(10); /* apeleaza functia cu argumentul 20 si afiseaza valoarea returnata */ print getCircumference(20);
In exemplul de mai sus, argumentul transmis functiei getCircumference() este procesat, iar rezultatul este returnat in programul principal unde poate fi memorat intr-o variabila, afisat sau folosit pentru alte calcule.
Instructiunile din cadrul unei functii pot folosi valoarea returnata de catre o alta functie:
// definitia functiei function getCircumference($radius) { // returneaza valoarea (lungimea cercului) return (2 * $radius * pi()); } /* afiseaza valoarea returnata intr-un format special folosind functia print */ print "Raspunsul este ".sprintf("%4.2f", getCircumference(20));
O functie va returna intotdeauna o singura valoare, dar aceasta poate fi un array, ca in exemplu de mai jos:
/* definitia unei functii care are ca parametru o lista (array) de adrese de email */ function getUniqueDomains($list) { /* parcurge lista, imparte adresele dupa caracterul @ si adauga numele domeniilor in array-ul $domains */ $domains = array(); foreach ($list as $l) { $arr = explode("@", $l); $domains[] = trim($arr[1]); } // sterge valorile duplicate din array si returneaza-l return array_unique($domains); } /* citeste adresele de email din fisierul ?data.txt? in array-ul $fileContents */ $fileContents = file("data.txt"); /* apeleaza functia cu argumentul $fileContents si memoreaza valoarea returnata in vectorul $returnArray */ $returnArray = getUniqueDomains($fileContents); // afiseaza vectorul $returnArray foreach ($returnArray as $d) { print "$d, "; }
Functia file ia ca parametru un nume de fisier transmis ca un sir de caractere si intoarce intr-un array continutul fisierului respectiv.
Presupunand ca fisierul ?data.txt? are urmatorul continut:
test@test.com
a@x.com
zooman@deeply.bored.org
b@x.com
guess.me@where.ami.net
testmore@test.com
scriptul de mai sus va afisa:
test.com, x.com, deeply.bored.org, where.ami.net,
Ca o observatie in plus, instructiunea return determina iesirea dintr-o functie si revenirea in programul principal.
Ordinea parametrilor
Ordinea in care sunt transmisi parametrii este de asemenea importanta. Functia din exemplul urmator are ca prim argument un nume, in timp ce al doilea argument reprezinta o locatie.
// defineste functia function introduce($name, $place) { print "Hello, I am $name from $place"; } // apeleaza functia introduce("Moonface", "The Faraway Tree");
Scriptul de mai sus va afisa:
Hello, I am Moonface from The Faraway Tree
Daca inversezi cei doi parametrii si rulezi din nou scriptul, mesajul afisat va fi:
Hello, I am The Faraway Tree from Moonface
Daca unul dintre parametrii este omis, PHP genereaza un mesaj de eroare:
Warning: Missing argument 2 for introduce() in myfunction.php on line 3 Hello, I am Moonface from
Pentru a evita astfel de erori, PHP ofera posibilitatea de declara valori implicite pentru parametrii unei functii. Cu alte cuvinte, parametrii devin optionali, iar in cazul omiterii lor la apelarea functiei, vor fi folosite valorile lor implicite (default). Iata un exemplu:
// definitia functiei function introduce($name="John Doe", $place="London") { print "Hello, I am $name from $place"; } // apelarea functiei introduce("Moonface");
Mesajul afisat va fi:
Hello, I am Moonface from London
Poti observa ca apelul functiei cuprinde un singur argument, desi definitia ei necesita doi. Cu toate acestea, deoarece am specificat valori default pentru parametrii, argumentul care lipseste este inlocuit cu valoarea sa implicita, iar PHP nu genereaza un mesaj de eroare.
Func_num_args() si func_get_args()
Exemplele anterioare din acest tutorial au un punct comun: functiile care au fost definite au un numar fix de parametri. Pentru a depasi acest inconvenient, utilizand functiile func_num_args() si func_get_args() se pot crea functii cu un numar variabil de argumente, ca in exemplul urmator:
// definitia functiei function someFunc() { // preia array-ul cu argumentele transmise $args = func_get_args(); // afiseaza argumentele print "Ai transmis urmatoarele argumente:"; foreach ($args as $arg) { print " $arg "; } print "<br />"; } // apeleaza functia cu argumente diferite someFunc("red", "green", "blue"); someFunc(1, "soap");
Daca apelezi functia cu un argument de tip array, nu va fi afisat continutul acestuia, ci cuvantul ?Array?. Pentru a putea transmite ca parametru un array, in corpul functiei trebuie adaugat un test care sa verifice tipul argumentelor.
// definitia functiei function someFunc() { // memoreaza numarul de argumente in variabila $numArgs $numArgs = func_num_args(); // preia lista de argumente $args = func_get_args(); // afiseaza argumentele print " Ai transmis urmatoarele argumente:"; for ($x = 0; $x < $numArgs; $x++) { print "<br />Argument $x: "; /* Verifica daca argumentul curent este un array, daca da, afiseaza continutul acestuia */ if (is_array($args[$x])) { print " ARRAY "; foreach ($args[$x] as $index => $element) { print " $index => $element "; } } else { print " $args[$x] "; } } } // apeleaza functia someFunc("red", "green", "blue", array(4,5), "yellow");
Variabile locale si globale
Variabilele declarate in interiorul unei functii sunt denumite variabile locale. Variabilele locale nu sunt recunoscute in exteriorul blocului de cod propriu. Ele exista numai atat timp cat blocul de cod in interiorul caruia au fost declarate este executat. Altfel spus, o variabila este creata la intrarea in blocul sau propriu de cod si este distrusa la iesire.
Cel mai comun bloc de cod in interiorul caruia se declara variabilele locale este functia.
Sa consideram exemplul de mai jos:
// defineste o variabila in programul principal $today = "Tuesday"; // definitia functiei function getDay() { // defineste o variabila in interiorul functiei $today = "Saturday"; // afiseaza variabila print "In interiorul functiei: $today<br />"; } // apeleaza functia getDay(); // afiseaza variabila print "In programul principal: $today";
La rularea scriptului, mesajul afisat va fi:
In interiorul functiei: Saturday
In programul principal: Tuesday
Variabila $today este declarata de doua ori, o data in programul principal si a doua oara in getDay(). Variabila $today din getDay() nu are nici o legatura cu variabila $today din programul principal si aceasta deoarece fiecare variabila $today este cunoscuta numai codului din acelasi bloc in care a fost declarata.
Daca o variabila locala si una globala au acelasi nume, toate trimiterile la numele acelei variabile din interiorul blocului de cod in care a fost declarata variabila locala se vor referi numai la variabila locala si nu vor avea efect asupra variabilei globale.
Cu alte cuvinte, valoarea atribuita variabilei $today in cadrul functiei este vizibila doar in interiorul acesteia, de unde vine si denumirea de variabila locala.
In plus, variabilele locale nu pot fi accesate din programul principal. De exemplu, scriptul :
// definitia functiei function getDay() { // defineste variabila in interiorul functiei $today = "Saturday"; } getDay(); print "Astazi este $today";
va afisa :
Astazi este
Daca in setarile php.ini de pe serverul tau, error_reporting cuprinde constanta E_NOTICE, exemplul de mai sus va afisa si urmatorul mesaj:
Notice: Undefined variable: today in x1.php on line 10
Pentru a face variabilele locale vizibile in afara functiei, ele pot fi declarate ca variabile globale utilizand cuvantul cheie global. Spre deosebire de variabilele locale, variabilele globale sunt recunoscute de catre toate componentele programului si pot fi folosite de orice fragment de cod. De asemenea, acestea isi pastreaza valoarea in timpul executiei programului.
Iata exemplul de mai sus rescris, de data aceasta declarand $today ca variabila globala:
// defineste variabila in programul principal $today = "Tuesday"; // defineste functia function getDay() { // declara $today ca variabila globala global $today; // initializeaza variabila in interiorul functiei $today = "Saturday"; // afiseaza variabila print "In interiorul functiei: $today<br />"; } // afiseaza variabila print "In programul principal, inainte de rularea functiei: $today <br />"; // apeleaza functia getDay(); // afiseaza variabila print "Dupa apelarea functiei: $today";
Scriptul va afisa:
In programul principal, inainte de rularea functiei: Tuesday
In interiorul functiei: Saturday
Dupa apelarea functiei: Saturday
Odata ce o variabila a fost declarata ca fiind globala, ea este accesibila atat din interiorul functiei, cat si din programul principal.
In plus, PHP defineste o serie de variabile super-globale, disponibile indiferent de locul in care sunt apelate. Cateva dintre acestea sunt $_SERVER, $_POST si $_GET , ce permit accesarea numelui scriptului ce este executat sau preluarea valorilor dintr-un formular care a fost transmis, chiar si in corpul unei functii.
Apel prin valoare, apel prin referinta
In general, argumentele pot fi transmise subrutinelor (functiilor) in doua moduri. Primul se numeste apel prin valoare (?passing by value?). Prin aceasta metoda, se copiaza valoarea unui argument in parametrul formal al unei functii. In acest caz, modificarile asupra parametrului nu au nici un efect asupra argumentului.
Apelul prin referinta (?passing by reference?) este cea de-a doua modalitate de a transfera argumente unei functii. In acest caz, adresa unui argument este copiata in locatie de memorie a parametrului. In interiorul functiei, adresa este folosita pentru a accesa argumentul efectiv folosit in apelul functiei. Aceasta inseamna ca modificarile operate asupra parametrului afecteaza si argumentul.
Cu cateva exceptii, PHP foloseste apelul prin valoare pentru transmiterea argumentelor. In general, aceasta inseamna ca argumentele folosite la apelul unei functii nu sunt influentate de codul din corpul functiei.
Sa incepem cu urmatorul exemplu:
// creeaza o variabila $today = "Saturday"; // defineste functia function setDay($day) { $day = "Tuesday"; print "In interiorul functiei: $day<br />"; } // apeleaza functia pentru a afisa variabila setDay($today); // afiseaza variabila print "In exteriorul functiei: $today";
Dupa cum se poate observa si in exemplele anterioare, datorita faptului ca argumentul $today a fost transmis prin valoare, scriptul va afisa:
In interiorul functiei: Tuesday
In exteriorul functiei: Saturday
Variabila $today din programul principal va ramane neschimbata deoarece doar continutul ei este transmis functiei.
Exemplul de mai sus poate fi modificat pentru apelul prin referinta:
// creeaza variabila $today = "Saturday"; // definitia functiei care afiseaza variabila function setDay(&$day) { $day = "Tuesday"; print "In interiorul functiei: $day<br />"; } // apeleaza functia setDay($today); // afiseaza valoare variabilei print "In exteriorul functiei: $today";
Dupa cum se poate observa, o variabila transmisa prin referinta este precedata de caracterul ampersand (&). Continul variabilei este modificat in interiorul functiei, iar noua valoare este vizibila si la returnarea din functie.
La executia scriptului, mesajul afisat este:
In interiorul functiei: Tuesday
In exteriorul functiei: Tuesday
Cunoscand modalitatea de transmitere a parametrilor prin referinta, putem spune ca, prin intermediul cuvantului cheie global, o variabila este declarata ca referinta astfel incat modificarile asupra ei sunt vizibile si in programul principal.
In urmatoarea sectiune a acestui curs, poti afla cum sa grupezi functii similare in clase si poti citi despre obiecte in PHP5.
Transmiterea parametrilor
Functiile asemanatoare celei din exemplul de mai sus vor afisa acelasi mesaj de fiecare data cand sunt apelate, ceea ce dupa un anumit timp poate deveni plictisitor. Poti face aceste functii mai interesante transmitand functiei diferite argumente care determina rezultate diferite ale executiei functiei.
Daca o functie urmeaza sa foloseasca argumente, trebuie sa declare variabile care sa accepte valorile argumentelor. Aceste variabile se numesc parametrii formali ai functiei. Acestia se comporta ca orice alta variabila locala in interiorul functiei, fiind creati la intrarea in functie si distrusi la iesire.
Daca datele de intrare (parametrii) difera, atunci si valoarea returnata de functie va fi alta.
Pentru a observa cum functioneaza acest mecanism, in exemplul urmator poti vedea o functie care primeste un singur argument (raza unui cerc) si afiseaza o valoare calculata utilizand valoarea acestuia (lungimea cercului). Dupa cum arata functia care urmeaza, declaratiile parametrilor survin dupa numele functiei:
// definitia functiei function getCircumference($radius) { echo "Circumferinta unui cerc cu raza $radius este ".sprintf("%4.2f", (2 * $radius * pi()))."<br />"; } // apelul functiei cu argumentul 10 getCircumference(10); // apelul functiei cu argumentul 20 getCircumference(20);
In acest exemplu, atunci cand functia getCircumference() este apelata, valorile 10, si apoi 20, sunt atribuite variabilei $radius, ce este ulterior utilizata de catre codul din corpul functiei.
Functiile pot fi apelate cu mai mult de un parametru, si anume cu o lista de parametrii separati prin virgula:
// definitia functiei function changeCase($str, $flag) { /* executa instructiunea indicata de variabila $flag */ switch($flag) { case 'U': print strtoupper($str)."<br />"; break; case 'L': print strtolower($str)."<br />"; break; default: print $str."<br />"; break; } } // apeleaza functia changeCase("The cow jumped over the moon", "U"); changeCase("Hello Sam", "L");
In functie de valoarea celui de-al doilea parametru, instructiunea switch selecteaza ramura corespunzatoare si manipuleaza primul argument.
PHP nu necesita precizarea tipurilor de date ale argumentelor care sunt transmise, acesta fiind identificate la executia scriptului. Ca si in cazul variabilelor locale, se pot face atribuiri parametrilor formali ai unei functii sau pot fi folositi in orice expresie permisa in PHP. Chiar daca aceste variabile au atributia speciala de a receptiona valoarea argumentelor transmise functiei, acestea pot fi folosite ca orice alta variabila locala.