Witaj, Gościu O nas | Kontakt | Mapa
Wortal Forum PHPEdia.pl Planeta Kubek IRC Przetestuj się!

Projektowanie aplikacji w PHP. Część pierwsza.

Standardy programowania w PHP.

Ostatni rozdział tego artykułu opisuje typowe dla PHP konwencje kodowania. Jakkolwiek nigdy nie jest stosownym przedwcześnie optymalizować kod, istnieje kilka ważnych zasad, do których powinno się stosować, aby już na początku wyciągnąć jak największą wydajność. W wielu aplikacjach stosowanie się do tychże zasad nie będzie miało znaczącego wpływu(strona WWW niekoniecznie będzie obciążona), co nie oznacza, że mamy pisać niechlujny i mało wydajny kod. Poza tym, istnieją sytuacje, kiedy liczy się każda mikrosekunda, a kiedy pracujesz nad takim projektem ważne jest, abyś był przyzwyczajony do pisania kodu zarówno poprawnego stylistycznie jak i wydajnościowo.

Jedną z najprostszych zasad tego typu jest właściwe użycie apostrofów(') i cudzysłowów("). PHP zawsze specjalnie parsuje ciąg znaków ograniczony cudzysłowami w poszukiwaniu zmiennych lub zagnieżdżonych wyrażeń, natomiast ciąg umieszczony pomiędzy apostrofami traktuje dosłownie. Rozważ poniższy przykład:

 <?php
 $typeOfString = "double quoted";
 $myString = "This is a \"$typeOfString\" string<br />\n";
 ?>

Przykład ten jest nie tylko nieczytelny - zmienna jest "wepchnięta" w ciąg, ale także niewydajny. Chociaż dla parsera do tylko ułamki sekund różnicy, w większym projekcie, obszernie operującym na ciągach, dodatkowy czas pracy może mieć zauważalny wpływ na działanie aplikacji. Aby tego uniknąć, ciągi powinny być kodowany w ten sposób:

<?php
 $typeOfString = 'single quoted';
 $myString = 'This is a "'.$typeOfString.'" string<br />'."\n";
 ?>

W powyższym przykładzie, wszystkie dosłowne ciągi są ograniczone apostrofami. Jedynym wystąpieniem cudzysłowu w tym przypadku jest objęcie nim znaku nowej linii, który nie zostanie poprawnie zinterpretowany pomiędzy apostrofami. Parser po prostu łączy ciągi ze zmienną i znakiem nowej linii, tym samym przetwarzając niedużą ilość tekstu.

Chociaż temat, którym się teraz zajmiemy, nie dotyczy PHP5, to w PHP4 obiekty domyślnie są przekazywane przez wartość, a nie przez referencje, co może prowadzić do znacznych spadków wydajności. Obiekty w PHP4 powinny być tworzone i przekazywane przez referencje, co pozwoli uniknąć tworzenia niepotrzebnych obiektów. Rozważ poniższe przykłady:

<?php
 $obj = new MyObject();
 callSomeFunction($obj);
?>

W tym przykładzie, PHP najpierw stworzy egzemplarz klasy MyObject, a potem skopiuje go do zmiennej $obj. Kiedy wywołujemy funkcję callSomeFunction(), obiekt po raz kolejny jest kopiowany, a następnie wysyłane do funkcji do lokalnego użytku. Jeśli MyObject jest obszerną klasą, zawierającą dużo danych, ujawnia nam się dosyć duży problem. Warto wiedzieć, że tak naprawdę rzadko zdarzają się sytuacje, kiedy obiekt ma być przekazany przez wartość - mając to na uwadze, rozważ poniższy przykład:

<?php
 $obj = &new MyObject();
 callSomeFunction(&$obj);
?>

W tym przypadku PHP tworzy instancje klasy MyObject a następnie przypisuje ją do zmiennej przy użyciu referencji, co jest równoważne stwierdzeniu, że nie tworzona jest nowa kopia, lecz po prostu przekazywany jest wskaźnik do pewnego miejsca w pamięci. Sytuacja powtarza się przy wywoływaniu funkcji callSomeFunction() - przekazywana jest referencja, nie kopia. To pozwala funkcji na operowanie na oryginale bez konieczności zwracania zmodyfikowanego obiektu.

Jedną z rzeczy o których trzeba wspomnieć jest także niepotrzebne pisanie funkcji/klas wykonujących operacje, które tak naprawdę mogą być wykonane przy pomocy wbudowanych funkcji PHP. Problem ten najczęściej tyczy się funkcji operujących na ciągach, tablicach czy obsługujących błędy. Ważne jest, aby każdy projektujący aplikację w PHP był zaznajomiony z manualem. Mimo trzyletniego doświadczenia w projektowaniu aplikacji PHP, nadal bardzo często korzystam z dokumentacji. Pamiętaj, aby zawsze sprawdzić w manualu, czy aby na pewno nie istnieje funkcja zanim zdefiniujesz swoją - funkcje wbudowane są szybsze w działaniu.

Przejdźmy dalej. Często na wydajność wpływa nawet odpowiedni wybór struktur kontrolnych w PHP - wiedza o tym, które są szybsze w danych sytuacjach przychodzi z czasem i doświadczeniem. Należy pamiętać, żeby używać ich w jak najbardziej wydajny sposób. Na przykład w pętlach, minimalizacja obliczeń, które nie zmieniają się w miarę przesuwania się pętli, jest dobrym sposobem na zwiększenie wydajności. Przyjrzyj się poniższym przykładom:

<?php
 $myArray = array('a', 'b', c');
 for ($i = 0; $i < count($myArray); $i++) 
 {
  print $myArray[$i];
 }
?>

W przedstawionym kodzie, podczas każdego wykonywania pętli, wielkość tablicy $myArray jest ponownie obliczana. Powinno się unikać takiej sytuacji, zmieniając kod pętli na taki:

for ($i = 0, $ii = count($myArray); $i < $ii; $i++)

W ostatnim przypadku, wielkość tablicy jest obliczana tylko za pierwszym razem i umieszczana jest w zmiennej $ii. Gdyby tak zlikwidować te pojedyncze wady kodu, w połączeniu z innymi problemami przedstawionymi w tym rozdziale, wydajność wzrosłaby, bez konieczności przepisywania całego kodu.

Następny problem godny uwagi - nigdy nie używaj zmiennych register_globals. Nie tylko z przyczyn związanych z bezpieczeństwem - opcja ta zmusza kod do stawiania przypuszczeń co do źródła i solidności danych. Używaj natomiast zalet zmiennych superglobalnych, a zmiennych tablicy $GLOBALS używaj oszczędnie - zwykle stałe bardziej pasują do przechowywania danych dostępnych globalnie. Ponadto, unikaj użycia instrukcji global - prowadzi ona do powstania nieelastycznego kodu, często prowadzącego projektanta do ogromnych strat czasu, w poszukiwaniu pierwotnego znaczenia zmiennych zadeklarowanych jako globalne. Jeśli masz dane obiekty, które muszą być dostępne globalnie, po prostu twórz do nich referencje, a intencja stanie się jasna i nikt nie będzie musiał się zastanawiać, skąd pochodzą informacje.

Ostatnią z głównych zasad dotyczących wydajności kodu jest unikanie nadmiernego includowania plików. Podczas gdy nieustannie doradzam i zachęcam do minimalizowania powtórzeń kodu, ważne jest także, aby nie przesadzać z modularyzacją kodu. Jeśli rzeczywiści potrzebujesz bardzo zmodularyzowanego kodu, a kod masz podzielony na sporą dawkę plików dołączanych, upewnij się, że załączasz tylko pliki naprawdę potrzebne. Jeżeli masz pięćdziesiąt klas, a skrypt wymaga tylko dwóch z nich, absolutnie nie includuj wszystkich. Zwykle w małych, a czasami w średnich aplikacjach, nie widać wyraźnego skoku wydajności.

Nadmierne użycie dołączania plików prowadzi do nadmiernego wykorzystania operacji IO dysku, co z kolei w dużej mierze powoduje wzrost ruchu na stronie WWW. Oczywiście nie znaczy to, że powinieneś się bać modularyzacji kodu - działaj po prostu w granicach zdrowego rozsądku. Jednym ze sposobów na ograniczenie załączania są instrukcje "include_once" i "require_once" - zapewniają one jednorazowe dołączanie jednego pliku. Kolejną sprawą jest umożliwienie dołączanym plikom dołączania innych, "podległych" plików - można w ten sposób połączyć includowane pliki w niby "łańcuchy". Pozwala to głównemu plikowi na dołączanie samych klas, a klasom z kolei na dołączanie zależnych od siebie plików - czyli krócej uniezależnia działanie klasy od głównego pliku. W ten sposób można ograniczyć zakłopotanie związane z wyborem, które pliki należy dołączyć.

Informacje na podobny temat:
Wasze opinie
Wszystkie opinie użytkowników: (7)
Pętla
Czwartek 07 Luty 2013 2:13:59 pm - mayu11 <kontakt_at_mariuszolszowski.pl>

Ym.. z tą pętlą to może lepiej:

for( $i = count( $arr ); $i > 0; --$i )
{
foo( $i );
}

Przy nieobowiązkowej dobrej kolejności, chyba jest ok ;) I nie trzeba trzech zmiennych.

Typo
Sobota 11 Grudzień 2010 11:58:48 am - mambax7

Zamiast:

function suqare($number)

powwino byc:

function square($number)

petla for
Środa 23 Styczeń 2008 6:36:47 pm - xiann

Do dobrze, ale dlaczego:
for ($i = 0, $ii = count($myArray); $i < $ii; $i++) {
print $myArray[$i];
}

skoro mamy:

foreach ($myArray as $v) {
print $v;
}

??

Referencje
Sobota 18 Sierpień 2007 5:36:39 pm - kkasprzak

Niestety autor artykułu mija się trochę z rzeczywistością jeśli chodzi o referencje w PHP4. Używanie referencji nie zawsze prowadzi do oszczędności pamięci wręcz w pewnych przypadkach prowadzi do zwiększenia jej zużycia. Referencje jak sugeruje autor nie zostały też stworzone po to aby oszczędzać pamięć ale po to żeby można było operować na oryginalnym obiekcie a nie na jego kopii w metodach klasy czy funkcjach. Samo przekazanie instancji klasy do funkcji nie prowadzi do stworzenia jego kopii jak stwierdza autor - nadal działa mechanizm przekazywania przez wartość. Kopia obiektu jest tworzona w momencie gdy wywołamy jedną z metod klasy lub nadpiszemy wartość któregokolwiek z atrybutów klasy w tej że funkcji/metodzie. Zauważmy jednak że odczyt atrybutów klasy nie wymaga już tworzenia kopii obiektu, dlatego też php4 tego nie robi. Dlatego też możemy bezpiecznie przekazywać obiekty przez wartość dopóki wykorzystujemy obiekt jako obiekt przenoszący dane (DVO) z jednym zastrzeżeniem, że czytamy bezpośrednio z atrybutów klasy a nie poprzez gettery. Każde wywołanie jakiejkolwiek metody na rzez obiektu prowadzi do stworzenia jego kopii!!!

Referencja nie jest żadnym wskaźnikiem do wyimaginowanego miejsca w pamięci, jest to tylko inna nazwa jednego z kontenerów zmiennych. Po prostu w tablicy symboli jedna lub więcej nazw wskazuje na ten sam kontener.

Przeanalizujmy poniższy przykład:

<?php

function suma(&$v) {
return array_sum($v);
}

$a = range(1, 1000000);
$b = $a;

$c = suma($a);

?>

Wierzcie lub nie ale ,,dzięki'' temu, że tablica do funkcji jest przekazywana przez referencję zmusiliśmy php do stworzenia dodatkowej kopii tablicy $a i stało się to dokładnie w momencie wywołania funkcji suma(). Dlaczego....? Dlatego, że php próbuje być sprytne i nie tworzy kopii zmiennej dopóki nie musi. W naszym przypadku gdy przypiszemy $b = $a nie jest tworzona kopia tablicy oba symbole wskazują na ten sam kontener zmiennej. Jednak gdy do gry wchodzi referencja php musi stworzyć dodatkową kopię ponieważ w przypadku gdy dokonalibyśmy modyfikacji zmiennej przekazanej przez referencję zmiany widoczne by były zarówno w zmiennej $a i $b.

Zainteresowanych szczegółami mechanizmu referencji i zmiennych w php4 odsyłam do jednego z numerów phparchitect lub lepiej kodu php.

Pozdrawiam
Karol Kasprzak

Ciekawe informacja z petla for
Niedziela 04 Luty 2007 12:56:04 am - andrews_p <andrews_p_at_o2.pl>

Zaciekawiła mnie informacja na temat pętli for i obliczania długości tablicy w pierwszej części fora.

for(i=0, dlugosc=count(array); i<dlugosc; i++)
{
//kod
}

Ciekawe rozwiązanie co faktycznie zmniejsza ilość obliczeń. Chodź nie istotne przy małym projekcie ale gdy na stronie jest kilkadziesiąt osób może dać duże rezultaty.

Mały błędzik
Piątek 22 Wrzesień 2006 1:54:25 pm - arqon <lilika_at_wp.pl>

W poddziale standarty kodowania , w trzecim listingu powinno być print $myNumberSquared; aby wyświetlał rezultat metody :)
Super artykuł...

Klamry zbyt rozwlekłe
Piątek 14 Kwiecień 2006 4:42:54 pm - akubiczek

Wszystko fajnie, chociaż klamry w osobnych liniach wydają mi się zbyt rozwlekłym rozwiązaniem, już lepiej trzymać się tego co proponuje pear, czyli klamra otwierająca w tej samej lini:

function foo() {
//do some
}

Nie nie traci się na czytelności, a wprost przeciwinie - może być bardziej czytelnie, bo więcej kodu da sie objąć wzrokiem.

Mentax.pl    NQ.pl- serwery z dodatkiem świętego spokoju...   
O nas | Kontakt | Mapa serwisu
Copyright (c) 2003-2017 php.pl    Wszystkie prawa zastrzeżone    Powered by eZ publish Content Management System eZ publish Content Management System