O tym, że PHP ssie!

O tym, że PHP ssie!

Dziś będzie o pewnym lubianym przez wszystkich języku programowania. Z pewnością w ten artykuł nie będzie wyczerpujący i dokładny. Będzie też za długi by niedzielni czytelnicy przebrnęli do końca. Przemyslenia tutaj zawarte są podparte moim doświadczeniem z tym „ssącym” językiem i krótkim (bo 2 letnim) kontaktem z porządniejszymi językami, zdobytym podczas studiów.

Język zna chyba każdy, kto dotykał problemu tworzenia stron internetowych głębiej niż tylko statyczne strony z obrazkami. Język szalenie popularny i często stosowany. Tylko, kaczka, czemu?

Personal Home Page powstał ponad 15 lat temu jako proste skrypty wykonywane po stronie serwera. Autor używał swojego wynalazku do śledzenia, kto czyta jego CV. PHP miał służyć też takim duperelom, jak wstawienie aktualnej daty, czy prosty licznik odwiedzin. Banalne makra, obsługa formularzy, w końcu – obsługa bazy danych. [1]

Dziś ten język jest obecny nawet na darmowych hostingach, a zna go chociażby syn sąsiadki, który zrobi firmie szanownego pana prezesa stronę za 10% jej rzeczywistej wartości. Personal Home Page Tools rozrósł się do takich rozmiarów, że używają go największe portale internetowe i bardzo poważne witryny. Tylko, nie rozumiem, czemu? Czemu mimo tylu wad jest taki popularny? Tego roztrząsać nie będę, skupię się raczej na samych cechach języka, które mnie przeszkadzają najbardziej.

Pierwszą wadą, która wkurza niemiłosiernie jest brak konsekwencji w rozwoju PHP.
Raz mamy nazwę w notacji podkreślnikowej, innym razem w konwencji wielbłądziej. AddSlashes i phpInfo obok ini_set. W samym PHP jeszcze da się to przełknąć, ale w zewnętrznych frameworkach jest już totalny sajgon. Wystarczy porównać framework Joomli i Zend. Jakby tego było mało, przykładowo funkcje wyszukujące przyjmują parametry w różnej kolejności. Raz jest to haystack, needle a innym razem needle, haystack. Raz jest array_map(‚callback’,$array) a innym razem array_filter($array,’callback’). Czy nie można było rozwijając język zadbać o spójne nazewnictwo? [2]

Drażni duplikowanie funkcji. Mamy funkcje implode i explode obok split i join. Czemu to służy – nie wiem. W samochodzie piąte koło się przydaje, gdy jedno padnie. W PHP to piąte koło jest podpięte cały czas, chociaż nie trzeba go wymieniać. Do wyszukiwania wewnątrz stringów możemy użyć funkcji z rodziny str*, preg*, ereg*. Różnią się sposobem działania, specyfiką, szybkością. Początkujący webmaster lub programista który specyfiki danej rodziny funkcji nie poznał stosuje je wymiennie, lub tylko tą grupę która więcej potrafi i którą wcześniej poznał. Czemu nie można było stworzyć kontenera wyszukiwania, który zwracałby odpowiedni obiekt realizujący wyszukiwanie, na przykład: match.get() match.getRegExp() match.getPreg() do pobrania odpowiednio obecnie najwydajniejszego (w danej wersji) operującego na prostych stringach, najwydajniejszego bazującego na wyrażeniach regularnych i w końcu specyficznego obiektu? Admin lub programista, gdyby chcieli, mogliby łatwo ustawić, co ma być tym najlepszym backendem. W ten sposób można ukryć implementację przed użytkownikiem, a jemu pozwolić korzystać z poleceń w sposób bezstresowy. Nie byłoby dylematów, który wybrać, nie krzywiłbym się na widok ereg, a pani dr na labolatoriach by się nie dziwiła, że preg_ jednak można zmusić do pracy… Innym problemem jest niekonsekwencja w zgłaszaniu błędów. Raz mamy e_warning innym razem wyjątek. Czasami przy nieudanym wykonaniu funkcje zwracają zero lub -1. Nie można by się tak zdecydować tylko na jeden sposób?

Razi mnie w tym języku porąbana składnia. Zmienne mogą sie brać z powietrza, wszystkie muszą mieć dolarka przed nazwą do którego napisać jednym palcem się nie da. Każde polecenie musi się kończyć średnikiem. I nie ma przebacz. Nie ma, że brak średnika nie zmienia niczego. Rozumiem, że dolarki to spadek po Perlu, a średniki po C, ale bez przesady. W Perlu znaczki przed zmiennymi mówią jak zmienna będzie alokowana i jaki ma charakter. W PHP – nie. Mogę wskazać wiele języków, które bez obowiazkowych średników i dolarków sobie doskonale radzą. I nie osłabia to czytelności kodu.

Cechą języka, którą poczatkujący lubią jest brak stałego typowania. Możemy bezkarnie napisać: $sql=0; $sql=”select * from tabela”; a potem napisać: $sql=mysql_query($sql); i nic złego się nie stanie. Gorzej, gdy przyjdzie nam porównywać wartości różnych typów. String z intem. String zawierający liczbę zostanie obcięty do liczby i tak zostanie porównany. Wstawimy to to do zapytania SQL i katastrofa gwarantowana. Nie mówię już o tym, że wystarczy drobna literówka w nazwie zmiennej, by kod się wykonał, ale z efektem bardzo różnym od oczekiwanego. Normalny język rzuci błędem czy wyjątkiem. Natomiast PHP przybierze kamienną twarz i będzie się śmiać w duchu: a teraz szukaj sobie gdzie jest błąd!

Zdaję sobie sprawę, że wady które wymieniłem biorą się z kompatybilności wstecznej i rozwijania silnika PHPa w nieładzie, bez koordynacji przez długi czas. Że większość tych problemów możnaby wyeliminować stosując OOP. Tylko, czemu dziś mamy w PHP tylko namiastkę obiektowości? Specyfikatory dostępu pojawiły się dopiero w PHP5. O przestrzeniach nazw do wersji 5.3 można pomarzyć jedynie. Z pewnych względów, separator też będzie udziwniony. Zamiast :: jak w c++, albo kropki jak w c# czy javie – backslash. [3] Największą zagadką pozostaje pytanie, kiedy PHP 5.3 lub PHP6 zawitają na serwery?

Inną cechą, która drażni mnie niemiłosiernie jest tendencja do myślenia za programistę i administratora serwera. PHP posiada dyrektywę safe mode, która odcina dostęp programisty od funkcji, które przy złej konfiguracji serwera mogą pozwolić coś namieszać. Z drugiej strony admin niedbale ustawi innego użytkownika na FTP, innego na webserver, wgramy plik skryptem na serwer i już nie usuniemy po FTPie. Safemode mocno utrudni to zadanie. PHP sam z siebie pozwala uruchomić polecenia powłoki. Dzięki temu zamiast pisać długi kod do wylistowania aktualnego katalogu piszemy `ls`. Proste, prawda? Ale po co? Safe mode na on i nici z tego. Kiedyś wykorzystałem notację apostrofów do uruchomienia zewnętrznego programu zamieniającego DOC na HTML. Na serwerze z safemode okazało się to niemożliwe.

Kolejną, dużo bardziej niebezpieczną funkcjonalnością jest register globals. Pozwala na podanie w formularzu (lub w pasku adresu) zmiennych i utworzenie ich automatycznie w skrypcie. Tak z powietrza. Potem zły chakier wywoła skrypt który miał być dołączany do innego, poda odpowiednie zmienne i skrypt się wykona, jak gdyby nigdy nic. A my dostaniemy włamanie na naszą witrynę. RG można wyłączyć, ale też niezawsze. Z bliżej nieznanych mi przyczyn na serwerach pewnej firmy na O, z ostatnią literką nazwy na M ustawienie dyrektywy wyłączającej RG wywołuje błąd 500 serwera. I bądź tu mądry, co jest przyczyną. Lepiej jest myśleć za programistę i powoływać za niego zmienne, a potem zmusić go do dbania o bezpieczeństwo tego skryptu.

Kolejną taką fajną funkcjonalnością jest Magic Quotes. Pierwotnie miało to zabezpieczać skrypty przed dodaniem wykonywalnych ciągów danych. W manualu do PHP zalecają wyłączenie tego, jednak wielu administratorów zdaje się mieć to zalecenie w poważaniu i pozostawia MQ włączone. A programista musi się martwić, żeby na nowym serwerze działało sprawnie…

Od czasu gdy PHP używa baz danych, a pseudoprogramiści w PHP budują strony internetowe spotykamy SQL Injection. Gdyby chociaż zapytania były prekompilowane, a dopiero potem uzupełniane treściami, problemu by nie było. PDO to potrafi. Tylko PDO jest bardzo młode i niewiele osób je stosuje. Efekt? Na labolatorium w którym prowadzacy kazał się zarejestrować w napisanym przez niego systemie gromadzacym oceny ustawiłem sobie piątkę jako ocenę końcową, na pierwszych zajęciach. Oczywiście było full disclosure, ale wykładowca był niepocieszony. Czy projektując język nie dało się o tym pomyśleć?

Zbliżając się do podsumowania chcę powiedzieć, że PHP jest łatwy do nauki. I powinien pozostać językiem do nauki. Taki nowoczesny Pascal. Pozwala na bardzo wiele, dużo toleruje. Początkujący pod okiem mistrza zostałby zganiony za błędy i nauczył się, jak pisać porządnie. Bez potworków w makaronowym kodzie. Cóż, tak niestety nie jest.

Kolejne wersje języka wyglądają coraz porządniej, ale dziedzictwo starszych wersji jest trudne do udźwignięcia. Zmusza do utrzymywania całego tego nagromadzonego przez lata bajzlu. Najlepiej byłoby całość rozwalić i zbudować odnowa. Taką koncepcję, wraz z wskazaniem koniecznych zmian przedstawił na swoim blogu Zyx [4]. Mi osobiście postulowane przez niego zmiany się podobają, jednak chcę uciekać od tego języka. Im szybciej i im dalej, tym lepiej. Java, Python, C++, C#. Z naciskiem na 2 ostatnie.

Na końcu wyjaśnię, że do napisania tego tekstu bardziej mnie zmobilizowały wejścia na mój blog z keywordu „php ssie” i jego wysoka pozycja w ^g na to hasło, niż moje ewentualne problemy z tym językiem. Na tę chwilę ich po prostu nie mam, dyskutuję za to z pythonem. 😛

[1] http://minimax.aster.net.pl/kursy/php-podrecznik/intro-history.html
[2] http://www.phpdevblog.net/2009/08/haystack-needle-sheet.html
[3] http://wiki.php.net/rfc/namespaceseparator
[4] http://www.zyxist.com/pokaz.php/jak_mogloby_wygladac_php
http://ferrante.pl/2007/07/07/mamo-umiem-php/