PHP.ee
 php.ee   linuxator.com   whee 
29.07.10 / 21:53
  Artiklid
  » Algajaile
  » Andmebaasid
  » Varia
  » Graafika
  » Advanced
Logi sisse:
< nimi
< pass
Unustasid passi?
Kas eelistad võimalusel PHP koodi objektorienteeritult kirjutada?
 Jah, see teeb töö lihtsamaks
 Jah, see on lihtsalt lahe
 Nii ja naa, ei tunne erilist võitu
 Ei, mõttetu ajakulu
 Ei oska objektorienteeritult progeda
Tulemused
Liitu listiga!
Telli PHP uudiskiri
Nimi:
Email
Kasutajafunktsioonid PHP's
Martin Rebane

Ilmselt igaüks on kasutanud tavalisi PHP funktsioone nagu strlen, isset, substr. Ilma funktsioonideta oleks ju PHP programmeerimine, nagu ka igasugune muu programmeerimine, mõeldamatu. Kui lihtsamad asjad saab vast PHP oma funktsioonidega ära aetud, siis keerulisemateks ülesanneteks jääb nendest väheseks. Siin tulevadki appi kasutajafunktsioonid - need, mis programmeerija ise kirjutab.

Selles artiklis on juttu kahest asjast:
-sellest, mis asjad on kasutajafunktsioonid ja kuidas neid kasutada
-mis asjad on rekursiivsed funktsioonid ja kus ning kuidas neid kasutada


Kasutajafunktsiooni kirjutamine

Kasutajafunktsioon on niisiis funktsioon, mis ei ole PHP'sse sisse ehitatud, vaid mille programmeerija ise kirjutab. Lihtne näide võiks olla selline:

PHP kood:


 
<?php
function arvuta($num1$num2)
{
    echo 
'Esimene number on: '.$num1;
    echo 
'<br />Teine number on: '.$num2;
    echo 
'<br />Nende summa on: '.($num1+$num2);
}
?>


Seletame natuke:
function arvuta($num1, $num2)
function tähistab seda, et tegu on funktsiooniga.
arvuta on selle funktsiooni nimi.
Funktsiooni parameetriks määrasime $num1 ja $num2, mis tähendab seda, et seda funktsiooni välja kutsudes peavad olema kindlasti antud parameetrid $num1 ja $num2. Ülejäänud kraam funktsiooni sees on täiesti tavaline PHP kood, mis ei erine mingilgi määral "tavalisest" PHP koodist, mida sa mujal kasutad.

Funktsiooni väljakutsumine on ka imelihtne ning ka see ei erine tavaliste PHP funktsioonide väljakutsumisest ning töötab täpselt samamoodi nagu iga teisegi funktsiooni korral:

arvuta($num1, $num2);

või

arvuta(4, 5);



Funktsiooni sees kasutatavad muutujad

Oma näites andsime funktsioonile kaks kohustuslikku muutujat: $num1 ja $num2. Need nimed on kasutusel ainult funktsiooni sees, st funktsiooni väljakutsudes ei pea me kasutama samu nimesid, vaid võime seda teha ka nii:

<?php
$a=4;
$b=7;
arvuta($a, $b);
?>


Neid funktsioonile edastavaid muutujaid nimetatakse tegelikult funktsiooni argumentideks. Kuid argumente saab funktsioonile anda ka teisiti, vaatame nüüd natuke alternatiivseid võimalusi ka.
Praegu olid mõlemad argumendid kohustuslikud, kuid neid võib vabalt ka mittekohustuslikeks defineerida, nimelt:
Näide 1 - sel juhul peab funktsioonile andma ainult ühe argumendi, teine on vabatahtlik:

PHP kood:


 
<?php
function arvuta($num1$num2=4)
{
    echo 
'Esimene number on: '.$num1;
    echo 
'<br />Teine number on: '.$num2;
    echo 
'<br />Nende summa on: '.($num1+$num2);
}
?>


Juhul, kui kutsume funktsiooni välja nii:

arvuta(5);

Saab funktsioon oma käsutusse kaks muutujat:
$num1=5 ja $num2=4
Kutsudes aga nii:

arvuta(5, 7);

Saab funktsioon oma käsutusse $num1=5 ja $num2=7. Ehk siis juhul, kui vabatahtlik argument puudub, asendatakse see vaikimisi määratud väärtusega, antud juhul siis 4.

Veel mõned näited illustreerimaks funktsiooni defineerimist ning väljakutsumist(ruumi kokkuhoiu mõttes jätan funktsiooni "keha" pildilt välja).

function arvuta($num1='', $num2='3', $num3='')
//vaikimisi väärtus võib väga edukalt ka "tühjus" olla

Kõik argumendid on vabatahtlikud, ning välja võib seda funktsiooni kutsuda mitmeti:

arvuta();
arvuta('', 4, 6)
arvuta(5, '', 7);
arvuta(5, 4);

Idee on selles, et kui me tahame defineerida esimest ja kolmandat argumenti, siis ei saa vahelt ära jätta teist. Kui aga soovime ainult esimest defineerida, siis järgmisi vabatahtlikke muutujaid vaja ei ole. Kui funktsioon tahab saada segamini nii vabatahtlikke kui ka kohustuslikke muutujaid, siis on mõttekas funktsioon defineerida nii, et kohustuslikud on eespool, vaata ise miks:

PHP kood:


 
function arvuta($kala$mala$pala=5)
//ilma vabatahtliku muutujate kutseme välja nii:
arvuta(45);
//kui aga panna vabatahtlik argument esimeseks, siis:
function arvuta($pala=5$kala$mala)
//väljakutsumisel peaksime ikkagi vabatahtlikku argumenti mainima
arvuta(''45);


Aitab lobast. See peaks selge olema :)


Funktsioonisisesed ja globaalsed muutujad

Kui meie funktsioonil on parameetrid $num1 ja $num2, siis need on funktsioonisisesed parameetrid - st nad kehtivad ainult selle funktsiooni sees ning ainult konkreetse väljakutsumise ajal(järgmisel korral sama funktsiooni kasutades defineeritakse need muutujad uuesti). Näide:

PHP kood:


 
$kala
='ahven';
function 
kalamees($kala)
{
    echo 
"Kalamehe saagiks langes $kala";
}

kalamees('haug');

echo 
"<br />Kalamehe saagiks langes $kala";


See kood prindib meile:

Kalamehe saagiks langes haug - funktsiooni seest muutuja $kala
Kalamehe saagiks langes ahven - väljastpoolt funktsiooni muutuja $kala

See tuleneb sellest, et funktsioonisisesed muutujad on lokaalsed. Aga muudame natuke koodi ja teeme nad globaalseteks.

PHP kood:


 
$kala
='ahven';

function 
kalamees()
{
    global 
$kala;
    echo 
"Kalamehe saagiks langes $kala";
}

kalamees();

echo 
"<br />Kalamehe saagiks langes $kala";


Nüüd saame tulemuseks:

Kalamehe saagiks langes ahven
Kalamehe saagiks langes ahven

Seda seetõttu, et me defineerime funktsiooni sees muutja $kala globaalseks ja saame kasutada väljaspool funktsiooni defineeritud muutujaid. NB! Kui me muudame funktsiooni sees globaalse muutuja väärtust, siis see muutub ka väljaspool funktsiooni. Nt:

PHP kood:


 
$kala
='ahven';

function 
kalamees()
{
    global 
$kala;
    echo 
"Kalamehe saagiks langes $kala";
    
$kala='haug';
}

kalamees();

echo 
"<br />Kalamehe saagiks langes $kala";


Nüüd saame tulemuseks:

Kalamehe saagiks langes ahven
Kalamehe saagiks langes haug

Simpel, huh?


Muutujatele viitamine

Üks võimalus globaalsete muutujate kasutamisest mööda hiilida, on muutujatele viidata.

PHP kood:


 
<?php

function viitame(&$str)
{
    
$str=strtoupper($str);
}

$str='vaikesed tahed';
viitame($str);
echo 
$str;
?>


Ja üllatus-üllatus, välja prinditud vastus on suurte tähtedega. Maagiline asi on '&' märk funktsiooni argumendi nime ees. Kui aga ei ole soovi iga kord muutujale viidata, vaid ainult valikuliselt, siis võib viitamise viia ka funktsiooni väljakutsumise poolele.

PHP kood:


 
<?php

function viitame($str)
{
    
$str=strtoupper($str);
}

$str='vaikesed tahed';
$str2='ikka veel vaikesed tahed';
viitame(&$str); //siin viitame muutujale
viitame($str2); //siin ei viita muutujale
echo $str//tulemus on suurtähtedega, kuna muutuja muudeti tänu viitamisele
echo $str2//tulemus on väiketähtedega, kuna trükitakse originaal

?>


NB! Kui soovid funktsiooni sees kasutada/defineerida konstante, siis need on alati kättesaadavad, kuna konstandid, erinevalt muutujatest, on alati globaalsed ja kasutatavad igal pool.

PHP kood:


 
<?php
function foo()
{
    
//echo'me v2ljaspool funktsiooni defineeritud konstandi
    
echo TEST;
    
//defineerime teise konstandi
    
define(KALA'<br />see on kala');
}

//defineerime esimese konstandi
define(TEST'see on test');

foo();
//echo'me funktsiooni sees defineeritud konstandi
echo KALA;

?>


Tulemuseks on oodatult:

see on test
see on kala


Tagastatavad väärtused

Kui seni on meie funktsioonikesed ainult midagi echo'nud, siis tegelikult võivad nad ka vabalt väärtusi tagastada. Programmeerija valikul kas siis numbreid, stringe, tõeväärtuseid(true, false).

Teeme funktsiooni, mis vähendab talle antud stringi ühe tähe võrra ja tagastame stringi:

PHP kood:


 
<?php

function miinus($string)
{
    
$string=substr($string0, -1);

    return 
$string;
}

echo 
miinus('jaanalind');
?>


Seekord ei ütle funktsioon ise midagi, vaid tagastab väärtuse ning sellega võime teha, mida soovime, ülemises näites echo'sime selle, aga seda võib ka muudmoodi kasutada, nt muutuja väärtustamiseks:

$lyhike = miinus('jaanalind');

Täpselt nagu tavaliste PHP funktsioonide korralgi - mõni "ütleb" oma tulemuse kohe välja(nt print_r()), mõni seevastu tagastab selle(nt strlen()). Igaks juhuks üks näide ka tõeväärtusmuutujatega:

PHP kood:


 
function on_lind($lind)
{
    
//defineerime kõik linnud
    
$linnud=array('leevike''tihane''vares');

    
//vaatame, kas funktsioonile antud olevus on lind
    //ehk kas $lind on olemas ka jadas $linnud
    
if(in_array($lind$linnud))
    {
        
//on olemas, tagastame jah
        
return true;
    }
    else
    {
        
//ei ole olemas, tagastame ei
        
return false;
    }
}

//kutsume funktsiooni välja if-konstruktsiooni sees
if(on_lind('harakas'))
{
    echo 
'Harakas on lind!';
}
else
{
    echo 
'Harakas ei ole lind!';
}


Ja selle tulemus on loomulikult: "Harakas ei ole lind!", kuna 'harakas' ei eksisteeri jadas $linnud. Selle funktsiooni tööpõhimõte on sarnane nt PHP funktsioonidele isset() või seesama in_array(), mis tagastavad samuti kas true või false.


Rekursiivsed funktsioonid

Rekursioon tähendab seda, et funktsioon kutsub iseennast välja. Kasuks tuleb see näiteks mõne rekursiivsust nõudva ülesande(menüü joonistamine, mõned arvutusülesanded jne) lahendamisel. Lihtne mis?
OK, sain vihjest aru, näidet vaja. Võtame aluseks sellesama suhteliselt mõttetu funktsiooni jaanalinnust, ainult seekord kahandame seda sõna niikaua, kuni järel ainult üksainus täht:

PHP kood:


 
<?php

function miinus($str)
{
    
//globaalne selleks, et oleks kasutatav iga kord, kui funktsiooni v2lja kutsume
    
global $lind;
    
//$str on üks t2ht väiksem, kui etteantud string
    
$str=substr($str0, -1);
    
//lisame muutujale $str'i otsa
    
$lind.='<br />'.$str;
    
//kui $str on suurem kui 1 tähem2äk, saadame uuele ringile
    
if(strlen($str)>1)
    {
        
miinus($str);
    }
}

$lind='jaanalind';
miinus($lind);
echo 
$lind;
?>


Selle funktsiooni tulemus on:

jaanalind
jaanalin
jaanali
jaanal
jaana
jaan
jaa
ja
j

Kas pole toredalt mõttetu? Aga siiski põhiline asi rekursiivsete funktsioonide juures on see, et nad peavad oma töö mingil hetkel ka ära lõpetama, muidu satuksid nad lõpmatusse tsüklisse. Selle saavutamiseks on meie "jaanalinnufunktsioonis" kasutusel selline lõik:

if(strlen($str)>1)

Ehk funktsioon kutsub ennast välja ainult seni, kuni järelejäänud string on veel suurem kui 1 tähemärk. Praktikas võiks rekursiivset funktsiooni kasutada näiteks menüü joonistamisel:

PHP kood:


 
/*(c)2001 Terry Fide*/
function teepuu($parent$prefix)
{
    
//mysql p2ring - siin on eeldatud, et db_query ja db_next_row on kasutajafunktsioonid
    //kui sa neid ise ei taha kirjutada, kasuta nende asemel tavalisi PHP mysql funktsioone
    
db_query("SELECT * FROM tabel WHERE parent = $parent");
    
//niikaua kuni ridasid j2tkub
    
while ($rida db_next_row())
    {
        
$string $prefix."/".$rida[nimi];
        echo 
$string."<br>n";
        
teepuu($rida[id], $string);
    }
}

//ja paneme asja k2ima:
teepuu(1,"");


Ülaltoodud näide eeldab umbes taolist SQLi tabelistruktuuri:

id #unikaalne key
parent #selle menüü id, mille alla see kuulub
nimi #menüü nimi


Funktsioonide nimed

Omatehtud kasutajafunktsioonidele võid loomulikult panna sellised nimed, nagu ise soovid, aga paar tingimust siiski on:

  • Nimi ei tohi kattuda PHP enda funktsiooninimedega

  • Funktsiooninimed on tõstutundetud - st kala() ja KaLa() kutsuvad välja sama funktsiooni

  • Funktsiooninimes tohib kasutad tähti, numbreid ning alakriipsu

  • Funktsiooninimi ei tohi alata numbriga



Kus ja miks funktsioone kasutada?

Funktsioonid on esimene samm koodi korduvkasutuseks. Kui sul tuleb teha samas koodis mitu korda ühte ja sama asja, siis on selle jaoks juba mõttekas funktsioon kirjutada ning iga kord see toiming läbi funktsiooni teostada. Teine aspekt on loomulikult see, et sa saad samu funktsioone ju väga edukalt erinevates projektides kasutada: nt teed eraldi faili MySql funktsioonidega, kus on funktsioonid ühenduse loomiseks, päringu esitamiseks jm vajaliku jaoks. Nii säästad iga kord hulga aega, kui ei pea mysql päringu tegemiseks kogu kraami otsast peale kirjutama, vaid lisad lihtsalt funktsioonifaili:

require_once('mysql_functions.php');


Samuti on funktsioonide tundmine eelduseks sisenemisele objektorienteerituse võrratusse maailma, aga sellest juba mõnes teises artiklis :)


Artikli kommentaarid

O