JustPaste.it

Funkcje - Podstawy PHP

Funkcje

Funkcja jest pojęciem znanym z matematyki: to zbiór operacji przypisujący danej grupie parametrów jakiś rezultat. Posiada własną nazwę, za pomocą której można się do niej odwoływać, pobiera dane i generuje wynik ponownie zwracany do programu. PHP posiada bardzo dużą ilość predefiniowanych funkcji, lecz nie zawsze mogą one zaspokoić nasze potrzeby. Załóżmy, że mamy w kodzie witryny WWW jakiś często powtarzający się algorytm. Pisanie go za każdym razem od nowa naraża nas na stratę czasu i ryzyko błędów. Możemy jednak napisać sobie własną funkcję z jego kodem i następnie odwoływać się do niej, gdy będzie to potrzebne. Gdybyśmy w przyszłości chcieli dodać jakąś nową możliwość lub wykryli błąd, poprawiamy go w jednym miejscu i zmiana widoczna jest wszędzie. W tym rozdziale omówione zostaną wszystkie tajniki tworzenia własnych funkcji i przyłóż do niego szczególną uwagę, ponieważ jest to rzecz, której nie można nie znać.

Tworzenie własnych funkcji

Tworzenie funkcji w PHP jest niezwykle proste. Stosujemy następującą konstrukcję:

function nazwaFunkcji(parametry)
{
// kod funkcji
}

Od tego miejsca możemy wywoływać naszą funkcję w identyczny sposób, jak te dostępne w PHP.

<?php

function formatujTekst($tekst)
{
echo '<font color="red">'.strtoupper($tekst).'</font>';
}

formatujTekst('to jest tekst 1');
formatujTekst('to jest tekst 2');
?>

Stworzyliśmy tutaj funkcję formatujTekst, dzięki której ustalimy jednolite formatowanie dla tekstów prezentowanych na stronie. Pobiera ona jeden parametr: $tekst. Zauważ, że nazwę tę piszemy ze znakiem dolara. Gdybyśmy chcieli podać więcej parametrów, oddzielamy je od siebie przecinkami. Można też nie brać żadnego, zostawiając puste nawiasy. Deklaracje te mówią skryptowi, pod jakimi zmiennymi wprowadzane wartości mają być widoczne wewnątrz funkcji.

Kod funkcji jest dowolnym poprawnym kodem PHP i możemy w nim wykonywać wszystkie operacje, z tworzeniem nowych funkcji włącznie. Jednak zauważ, że nasza pierwsza funkcja nie zwraca wartości. Zamiast tego wynik wysyła od razu na ekran i próba wykonania

$zmienna = formatujTekst('to jest tekst 1');

nic by nam nie dała. Aby zwrócić cokolwiek jako wynik, musimy skorzystać z komendy return:

<?php

function formatujTekst($text)
{
return '<font color="red">'.strtoupper($text).'</font>';
}

echo formatujTekst('to jest tekst 1').'<br/>';
echo formatujTekst('to jest tekst 2').'<br/>';
?>

Po return podajemy wyrażenie generujące wartość do zwrócenia.

Zwróćmy uwagę na fakt, iż przy deklarowaniu parametrów nie podajemy żądanego typu danych. O to musimy zadbać sami, umieszczając na początku funkcji odpowiednie instrukcje warunkowe i w razie kłopotów zgłosić błąd. Napiszmy sobie skrypt wyświetlający zawartość katalogu. Stworzymy w nim jedną funkcję zwracającą zawartość podanego katalogu jako tablicę. Druga funkcja będzie uniwersalnym wyświetlaczem tablic. Dlaczego tak - zaraz wyjaśnimy.

<?php

function wyswietlKatalog($sciezka, $tylkoPliki = 0) // 1
{
$dir = opendir($sciezka); // 2
$wynik = array();
while($f = readdir($dir)) // 3
{
if(is_file($sciezka.$f)) // 4
{
$wynik[] = $f; // 5
}
elseif(is_dir($sciezka.$f) && $f != '.' && $f != '..' && !$tylkoPliki) // 6
{
$wynik[] = $f;
}
}
closedir($dir); // 7

return $wynik; // 8
} // end wyswietlKatalog();

function pokazListe(Array $lista) // 9
{
echo '<ul>';
foreach($lista as $element)
{
echo '<li>'.$element.'</li>';
}
echo '</ul>';
} // end pokazListe();

pokazListe(wyswietlKatalog('./katalog1/')); // 10
echo '<br/>';
pokazListe(wyswietlKatalog('./katalog2/', true)); // 11
?>

Opis skryptu:

  1. Oto deklaracja funkcji wyświetlania katalogów. Znak równości oraz wartość po drugim parametrze oznacza, że jest on opcjonalny. Jeżeli go nie podamy przy wywołaniu, przyjmie on wartość domyślną. Opcjonalnych parametrów może być więcej, z tym że podajemy je zawsze na końcu. W naszej funkcji opcjonalny parametr określa, czy funkcja ma zwracać wszystko (domyślny stan: 0), czy jedynie pliki (stan 1).
  2. Otwieramy katalog o podanej ścieżce
  3. Pętla pobierająca kolejne elementy katalogu, dopóki istnieją.
  4. Sprawdzamy, czy zwrócony element jest plikiem. Zauważ, że do zwróconej nazwy elementu musimy dokleić ścieżkę, ponieważ funkcja is_file() jest niezależna od opendir() i nie obchodzi jej, że w takim kontekście ją wywołujemy. Jeżeli rzeczywiście mamy plik, dodajemy go do tablicy wynikowej jako kolejny element.
  5. Niepodanie indeksu oznacza: "utwórz nowy element o indeksie MAX+1".
  6. Warunek sprawdzający, czy mamy do czynienia z katalogiem, jest dość skomplikowany. Użyliśmy tu operatorów && (logiczne "oraz"), aby zagwarantować, że wszystkie muszą być spełnione, aby dodać element do listy. Mamy tu kolejno: czy element jest katalogiem, czy nie ma on nazwy "." i ".." oraz czy funkcja ma od programisty zezwolenie na pobieranie katalogów.
  7. Zamykamy katalog
  8. Zwracamy tablicę jako wynik
  9. A oto mała niespodzianka. Począwszy od PHP 5 można definiować typy parametrów obiektowych, a od PHP 5.1 - tablic, które również są typem złożonym. Robimy to właśnie w taki sposób. Jeśli próbowalibyśmy wysłać tutaj np. liczbę, PHP zgłosiłby błąd.
  10. Wywołanie funkcji z jednym parametrem i przekierowanie wyniku do funkcji wyświetlającej listę.
  11. Ponowne wywołanie, lecz tym razem żądamy wyłącznie plików.

W ten sposób poznaliśmy już niemal wszystko, co dotyczy definiowania parametrów. Pozostała jeszcze jedna rzecz, a mianowicie pobieranie ich zupełnie nieokreślonej liczby. Uruchom taki oto skrypt:

<?php

function funkcja($a)
{
echo $a;
}

funkcja(1, 2, 3, 4, 5);
?>

Nasza funkcja pobiera tylko jeden parametr, lecz my podajemy mu pięć. Mogłoby się wydawać, że spowodujemy tym samym błąd, jednak tak się nie stanie. PHP nadmiarowych parametrów nie ignoruje. Choć nie zadeklarowaliśmy żadnego z nich podczas tworzenia funkcji, istnieje pewien sposób, aby je wydostać. Jest to funkcja func_get_args() zwracająca tablicę z wartościami wszystkich parametrów, które przekazaliśmy do funkcji.

<?php

function funkcja()
{
$parametry = func_get_args();
echo '<ul>';
foreach($parametry as $id => $wartosc)
{
echo '<li>'.$id.' - '.$wartosc.'</li>';
}
echo '</ul>';
}

funkcja(1, 2, 3, 4, 5);
?>

Istnieje także func_get_arg(numer) pobierająca wartość konkretnego parametru. Obie te funkcje operują bezpośrednio na funkcji, dlatego PHP nakłada kilka ograniczeń na ich stosowanie. Najlepiej jest pobrać wszystkie niezbędne parametry na samym początku tworzonej funkcji, aby uniknąć kłopotów.

Widzialność zmiennych

Napiszmy taki skrypt:

<?php

$zmienna = 'To jest zmienna';

function funkcja()
{
echo $zmienna.'<br/>';
}

funkcja();
echo $zmienna.'<br/>';
?>

Próbuje on wyświetlić dwa razy wartość tej samej zmiennej: z wnętrza funkcji oraz bezpośrednio w skrypcie. Po uruchomieniu okazuje się, że tylko bezpośrednie wyświetlenie podało nam prawidłowy wynik. echo wewnątrz funkcji nie pokazało żadnej wartości. Dlaczego? Zmienna przecież istnieje. I owszem, lecz tylko w tej części skryptu, w której została utworzona. PHP ma zaimplementowaną tzw. widzialność zmiennych - dla każdej funkcji tworzony jest osobny stos, niezależny od drugiego. Jeżeli więc utworzymy zmienną bezpośrednio w skrypcie, nie będzie ona istnieć w żadnej z naszych funkcji, gdyż te mają własne stosy. Ma to wyeliminować konflikty nazewnictwa.

Istnieje jednak sposób na powiedzenie PHP, że używana w funkcji zmienna jest już stworzona w stosie głównym skryptu. Po lekkiej modyfikacji skryptu otrzymujemy:

<?php

$zmienna = 'To jest zmienna';

function funkcja()
{
global $zmienna;
echo $zmienna.'<br/>';
}

funkcja();
echo $zmienna.'<br/>';
?>

Słowo kluczowe global informuje PHP, że wymienione po nim zmienne mają zostać zaimportowane ze stosu głównego.

Static

Inną przydatną rzeczą jest przenoszenie niektórych zmiennych między wywołaniami tej samej funkcji. Dzięki temu nie musimy zapamiętywać ich wartości w globalnych tablicach, narażając się na konflikty nazewnictwa. Aby tego dokonać, wystarczy zadeklarować wybrane zmienne jako static, a ich wartość zostanie zapamiętana do następnego wywołania.

<?php

function koloruj()
{
static $i;

$i++;

if($i % 2 == 0)
{
return '#ffffff';
} else {
return '#cccccc';
}
} // end koloruj();

echo '<table width="30%">';
for($x = 0; $x < 10; $x++)
{
echo '<tr><td bgcolor="'.koloruj().'">'.$x.'</td></tr>';
}
echo '</table>';
?>

Powyższy przykład koloruje naprzemianlegle wiersze w tablicy. Sztuczka ta nie wymaga finezji: po prostu zwiększamy licznik i sprawdzamy, czy dzieli się bez reszty przez dwa. Jeśli tak, wstawiamy jeden kolor, jeśli nie - drugi. Z pomocą instrukcji switch można rozszerzyć algorytm na więcej kolorów.

Tutaj kolor jest zwracany przez odpowiednią funkcję. Zapamiętuje ona sobie stan wewnętrznego iteratora $i między kolejnymi wywołaniami przy pomocy słowa kluczowego static. Gdybyś usunął tę linijkę, funkcja cały czas zwracałaby ten sam kolor, gdyż zmienna tworzona byłaby w kółko od nowa z domyślną wartością 0.

Rekurencja

Rekurencja w programowaniu oznacza odwoływanie się funkcji do samej siebie. Jest użyteczna, w niektórych sytuacjach wręcz niezbędna, lecz pochłania znacznie więcej zasobów i należy się z tym liczyć.

Za pomocą rekurencji możemy wyświetlić w PHP drzewo katalogów:

<?php

function wyswietlKatalog($sciezka)
{
$dir = opendir($sciezka);
echo '<ul>';
while($f = readdir($dir))
{
if(is_dir($sciezka.$f) && $f != '.' && $f != '..')
{
echo '<li>'.$f;
wyswietlKatalog($sciezka.$f.'/'); // 1
echo '</li>';
}
}
echo '</ul>';
closedir($dir);
} // end wyswietlKatalog();

wyswietlKatalog('../../');
?>

Funkcja wyswietlKatalog() w przypadku napotkania katalogu w aktualnie sprawdzanej ścieżce, wywołuje samą siebie (1), z doklejoną do dotychczasowej ścieżki nazwą tego katalogu. W ten sposób możemy pobrać całe drzewo, niemniej w przypadku rozbudowanych struktur może trwać to nawet kilkanaście sekund! Musimy być także świadomi, że funkcja nie może zagnieżdżać się rekurencyjnie w nieskończoność. W pewnym momencie w PHP zwyczajnie zapcha się stos i wykonywanie takiego skryptu zostanie przerwane. Dlatego stosuj rekurencję z rozwagą i nie nadużywaj jej w miejscach, w których nie jest konieczna.

Użyteczne funkcje

PHP dysponuje kilkoma funkcjami do zarządzania funkcjami. Brzmi to może dość śmiesznie, lecz w praktyce bywa bardzo przydatne.

Na początek zastanówmy się, kiedy PHP sprawdza, że funkcja nie istnieje. Okazuje się, że nie dzieje się to w momencie kompilacji, lecz wykonywania skryptu. Ma to swoje uzasadnienie przy konstruowaniu modułowych skryptów (zajmiemy się nimi w następnym rozdziale). Pierwszy plik PHP odwołuje się do funkcji zdefiniowanych w drugim, lecz ten z kolei ładowany jest później. Gdyby z powodu nieistnienia jednej z nich skrypt byłby przerywany w momencie kompilacji, skrypt nie miałby żadnych szans na działanie. Ponadto nie dałoby się pracować ze skryptami korzystającymi z rozszerzeń, których na serwerze nie ma. Ma to sens, przecież instrukcją warunkową możemy zdefiniować alternatywny kod dla tych uboższych serwerów.

PHP ułatwia nam zadanie jeszcze bardziej. Za pomocą function_exists() możemy sprawdzić, czy podana przez nas funkcja istnieje. Narzędziem tym można sondować zarówno nasze własne, jak i definiowane przez rozszerzenia funkcje. W poniższym przykładzie wykorzystamy to do sprawdzenia, czy serwer posiada obsługę protokołu IMAP:

<?php
if(function_exists('imap_open'))
{
echo 'IMAP dostępny';
}
else
{
echo 'IMAP niedostępny';
}
?>

Innym sposobem sprawdzenia, czy rozszerzenie jest załadowane, jest skorzystanie z funkcji extension_loaded(), która ma tę przewagę, że działa także z rozszerzeniami obiektowymi, w których zwykłych funkcji nie ma:

<?php
if(extension_loaded('imap'))
{
echo 'IMAP dostępny';
}
else
{
echo 'IMAP niedostępny';
}
?>
 
Treść pochodzi ze strony WikiBooks i jest udostępniana na licencji GNU FDL 

 

Autor: WikiBooks