Ta strona używa ciasteczek (cookies), dzięki którym nasz serwis może działać lepiej. Dowiedz się więcej Rozumiem

Optymalizacja kodu PHP

Jak wiemy wydajność kodu PHP ma spore znaczenie zarówno dla twórców małych jak i większych witryn. O ile korzystamy z gotowego rozwiązania takiego jak Windu CMS, nie musimy się o to martwić. To twórcy systemu dbają o jakość i szybkość oprogramoania, jeżeli natomiast chcemy sami coś napisać lub tworzymy plugin do instniejącego systemu, warto mieć na uwadze że pewne operacje znacznie bardziej obciążają nasz serwer.

IMG_6746

W artykule przedstawimy kilka sprytnych i dość prostych sposobów na przyśpieszenie działania naszego skryptu. Zaczynajmy!

Na samym początku warto zainstalować Xdebug
Rozszeżenie to pozwoli na analizowanie wykonywanych skryptów. Zrzuci do wskazanego katalogu plik z pełnymi danymi na temat naszego programu, co konkretnie ile czasu zajmuje i jak bardzo obciąża serwer.

Aby włączyć Xdebuga nalezy dokleić na koncu naszego pliku php.ini następujący fragment kodu
 

; XDEBUG Extension
zend_extension = "E:/Server/bin/php/php5.4.3/zend_ext/php_xdebug-2.2.0-5.4-vc9-x86_64.dll"

[xdebug]
xdebug.remote_enable = on
xdebug.profiler_enable = on
xdebug.profiler_enable_trigger = on
xdebug.profiler_output_name = cachegrind.out.%t.%p
xdebug.profiler_output_dir = "E:/Server/tmp"

Z ustawionymi odpowiednio ścieżkami

Xdebug zapisuje pliki w formie tak zwanych "cachegrid" aby w łatwy sposób analizowac wyniki polecam zastosowanie cache grid readera na przykład:
​kcachegrind.sourceforge.net

Dodatkowo z poziomu skryptu PHP możęsz wykorzystywać funkcjie
 

//Pamięć
echo xdebug_memory_usage(); 

//Szczytowe użycie pamięci 
echo xdebug_peak_memory_usage();

//Czas wykonywania
echo xdebug_time_index();

Tak zaopatrzeni możemy rpzeanalizować skrypt pod kątem wydajności i zdefiniować najabrdziej obciążajace fragmenty kodu którymi powinniśmy sięzająć w pierwszej kolejności.

Poprawny dobór technologii
Bardzo ważnym aspektem jest dobranie odpowiedniej technologi do zadania jakie wykonujemy, nalezy kierować się kilkoma zasadami
 
  • Dobór bazy danych
    • SQLite - dla prostych stron które nie geneurją więcej niz 100 requestów na sekundę oraz nie mają więcej niż 100k użytkowników meisięcznie należy zastosować bazę danych SQLite, jest to plikowy uproszczony odpowiednik MySQL, działa znacznie szybciej. Nadaje sięidealnie dla małych i średnich stron internetowych.
    • MySQL - Dla większych stron, które wymagają bardziej skomplikowanych operacji na bazie danych, należy zastosować bazę danych MySQL
  • Dobór technologii PHP
    • Zastosuj dostępny framework w wypadku gdy musisz zakodowac szybko portal czy skrypt, frameworki nie są wydajne, im wiekszy tym bardizej obciążą nasz serwer. Dobry przykąłdem jest Zend Framework który znacznie obciązy serwer i sprawi że nasza strona będzie powolna. Zend Framework ma sens w wypadku dużych i profesjonalnych serwisów gdzie mamy serwer dedykowany i na przykład dostęp do memcache.
    • Zastosuł własne rozwiązanie pisane od zera w przyapdku gdy zależy Ci na wydajności skryptu, w takim wypadku masz możliwość pełnego dopasowania wielkości frameworka do potrzeb systemu oraz masz też możliwośc pełnej optymalizacji kodu, nie jesteś uzależniony od zewnętrznej struktury.
3. Styl programowania, czego unikać?
Pewne operacjie są bardziej pracochłonne dla procesora niż inne dlatego stosujmy te lżejsze :-)

​Apostrof czy cudzysłów? 
​Wpisując frazę w cudzysłowie system będzie analizował kod w poszukiwaniu zaszytych w nim zmiennych, to sprawia że procesor jest bardziej obciążony, lepiej zapisać frazę w apostrofie i dokleić zmienną.
 
//Brak analizy, znacznie szybciej
$x = 'Witaj' . $zmienna;

//Analiza - wyszukiwanie zmiennych w stringu
$x = "Witaj $zmienna";

Dodatkowo pamiętamy aby stosować jak najmniej złączeń ciągów tekstowych (za pomocą kropki) każde takie złączenie to dodatkowe obciazenie dla serwera. Kodując starajmy się optymalizować tego typu syctacje.

W przypadku analizy stringów jeżeli mamy do czynienia z jednym wywołaniem, jest to znikoma skala optyamlziacji, ale już w globalnej skali gdzie na przykład mamy 1000 wywołań funkcji na sekundę, zaoszczędzona moc obliczeniowa zaczyna robić się pokaźna.

Unikaj operatora @
Służy on do blokowania wyśeitlania błędów, jego użycie spowoalnia nasz kod, dlatego nie stosujmy takiego rozwiązania.

Zapisuj wyniki działań od razu
Przykładowo, definiując czas ważności cookiesa możemy to zrobić mnożąc sekundy przez godziny i dni
setcookie('NaszCookie', 1, 60*60*12);

Co samo możemy zapisać od razu bez mnożenia
setcookie('NaszCookie', 1, 
43200);

Oszczędzi to moc obliczeniową naszego procesora.



Unikaj zbędnego przeliczania
Częstym błędem jest stosowanie funkcji count w pętli, wykonywana jest ona wtedy każdorazowo za kazdym przejściem pętli, dlatego warto wszstko co się da wyciągać z pętli na zewnątrz i przekazywać do niej gotowe wyniki.
 
$counter = count($x);
for($i=0; $i<$counter ; ++$i)
{
    echo $x[$i];
}


Przestrzegaj typów danych.
PHP oferuje wiele ułatwień, jednym z nich jest na przykład automatyczna zamiana typów danych. Jezeli funkcja wymagajaca danych liczbowych otrzyma liczbę w postaci stringu, PHP sam zamieni dane na właściwe, należy unikać takiej sytuacji. Generalnie powinniśmy unikać ułatwień oferowanych rpzez PHP, każde z nich obciaża nasz serwer dodatkowymi obliczeniami.


Jak ominąć to wszystko i znacznie przyśpieszyć wydajność kodu nie rezygnując jednocześnie z ułatwień?
Rozwiązanie jest proste. Powinniśmy cachować wyniki naszych skryptów PHP. Tam gdzie tylko można powinnismy zapisywać wynik do tablicy, następnie serializować ją i zapisywać do pliku.
Jedna z najabrdizej wydajnych oepracji w PHP to sprawdzanie czy plik istnieje. Jest ona domyślnie cachowana przez serwer. Często sprawdzenie czy istnieje plik zamiast sprawdzania czy zmienna jest ustawiona w bazie znacznie poprawia wydajność kodu.

Prosty przykład optymalizacji po przez zapis wyniku do cache
 
    public static function loadFrontJS(){
        $file = __SITE_PATH.'/cache/system/frontjslist-'.config::get('template').'-'.md5(HOME).'.tmp';
        if (file_exists($file)){
             $resourcesJS = unserialize(file_get_contents($file));
        }else{
            $plugins = explode(',', FRONT_PLUGINS);
            $resourcesJS = array_merge(
                (array)self::loadResourceByPlugins($plugins,'front-system','js'),
                (array)self::loadResource(themesDB::getAllResources('js'),'front-theme', 'js')
            );    
            if (config::get('inPlaceEditor')==1) {
                $resourcesJS = array_merge($resourcesJS,array(
                    HOME.'app/plugins/html/resources/ckeditor/ckeditor.js',
                    HOME.'app/plugins/html/resources/js/ckeditor.inline.config.js'
                ));
            }
            file_put_contents($file, serialize($resourcesJS));            
        }
        return $resourcesJS;    
    }
 
Jak widzimy system najpierw sprawdza czy istnieje plik z wcześniej zapisanymi danymi a następnie jeżeli istnieje pobiera wynik z pliku, wykonuje tylko 2 operacje i to w dodatku bardzo mało zasobożerne. W przeciwnym razie wykonuje cały kod a na koniec zapisuje wynik do potomności.

Rzecz jasna cachować wszystkeigo nie powinniśmy, są pewne dane które ulegają ciągłym zmianom, wtedy niestety ale skrypt musi wykonywać się każdorazowo. 

Kiedy mamy już tak zoptymalizowany kod, warto przetestować wydajność naszych rozwiązań.
Służy do tego Apache Benchmark.

Apache benchmark
AB jest standardowo zainstalowane na takich serwerach jak XAMPP czy też WAMP, aby go wywołać nalezy uruchomić linie poleceń w winduws lub console w rpzyapdku systemów OSX czy Linux. W konsoli nalezy wywołać odpowiednio:

OSX/LINUX
​ab -k -r -c 400 -n 60000 [URL HERE]

​Windows
C:\ cd E:\Server\bin\apache\apache2.4.2\bin
ab -c 10 -n 10000 http://www.example.com/

Nalezy znależć odpowiedni katalog w stukturze plików na naszym serwerze, w tym wypadku jest to WAMP Server.

Wywołujemy adres naszej strony z odpowiednimi parametrami
n - liczba requestów
c - liczba jednoczesnych wywołań

W odpowiedzi otrzymamy czasy potrzebne na każdy request oraz wiele innych przydatnych informacji na temat wydajność sktypru.
Warto wyłączyć wszystkie zbędne usługi oraz powtórzyć testy 3 razy w celu wyeliminiowania błędów pomiarowych.

Dokumentacja AB znajduje się pod linkiem:
http://httpd.apache.org/docs/2.2/programs/ab.html

Podsumowanie
Na zakończenie pamietajmy że nie warto poświęcać zbyt dużej uwagi na operacje wykonywane jednorazowo i rzadko. Optymalizacja tych fragmentrów kodu, nie da nam tak wiele jak optymalizacja operacji wykonywanych kilka albo kilkaset razy w ciągu jednego requesta. Wtedy każda milisekunda zaoszczędzona jest zwielokrotniana co daje widoczne rezultaty. Dlatego warto na samym początku przeprowadzić analize kodu przy pomocy Xdebuga. Zobaczymy dzięki temu co w naszym skrypcie zajmuje najwięcej czasu. Po takiej analizie zabieramy się najpierw za te najcięższe fragmenty, eliminując je przechodzimy do tych lepiej zoptymalizowanych aby jeszcze bardziej je dopracować.

W krótce w poradniki dla początkujących na temat instalacji xdebuga oraz obsługi apache benchmark