Metoda has 0 friends


Autoloader dla PHP5

Swego czasu napisałem klasę, która pozwala zapomnieć klientowi o używaniu funkcji w rodzaju include czy require_once.
Działanie jest relatywnie proste: klasa na podstawie konfiguracji przechowywanej w pliku XML skanuje wskazane katalogi, tj. buduje mapę plików *.php i ich lokalizacji. Dzięki przykryciu funkcji __autoload() wyszukuje w mapie odpowiednią klasę/interfejs i dołącza ją do wykonywanego skryptu w momencie żądania.
Jedyne o czym należy pamiętać, to konwencje nazewnicze których trzeba się trzymać (jeśli podobnie jak ja, nie lubisz stosować się do czyichś, zawsze możesz zmodyfikować metodę load() ) – klasa ich pilnuje. Istota konwencji polega na różnicach w zapisie nazw plików i deklaracji wewnątrz ich: klasy trzymamy w plikach Nazwa.class.php i tak też je deklarujemy, tj.
class Nazwa {}
Interfejsy trzymamy w plikach Nazwa.interface.php, natomiast deklarujemy nieco inaczej:
interface iNazwa {}
z kolei klasy abstrakcyjne, jak można się domyślić przechowujemy w plikach Nazwa.abstract.php, a deklarujemy jako:
abstract class aNazwa {}
Tyle zasad. Klasa dodatkowo pilnuje „sztucznej” przestrzeni nazw, sztucznej ponieważ tylko zgłasza E_USER_ERROR w przypadku zindeksowania duplikatów.
Nie jest chyba niczym dziwnym, że w przypadku większych projektów, każdorazowe indeksowanie struktury katalogów ma znaczący wpływ na wydajność aplikacji. W swojej wspaniałomyślności ;-) przewidziałem to i wprowadziłem dodatkowy atrybut konfiguracyjny, tj. cache który ustawiony na true, przechowuje mapę w postaci zserializowanej tablicy, umożliwiając szybki jej odczyt. Oczywiście cache należy stosować tylko w środowisku tzw. produkcyjnym, ponieważ w przeciwnym wypadku nowo dodane klasy będą poza zasięgiem autoloadera.
Klasę można pobrać stąd i oczywiście zapisać ją zgodnie z konwencjami ;-) jako LoadMagic.class.php (uploader wordpressa zmienia nazwę pliku). DTD (robione na szybkiego, wybaczcie1) do pliku konfiguracyjnego znajduje się tutaj.
1 Piszę wybaczcie, bo jakimś cudem ten blog subskrybuje 15 osób. Wow. Metoda has 15 friends!


Polityka niepełnosprawna

Stary tekst, pisany gdzie indziej, przeniesiony tutaj.

Wszyscy to znamy: dostępność, użyteczność, semantyczna struktura, dobra współpraca z technologiami wspierającymi, które za pośrednictwem syntezy mowy ułatwiają kontakt z informacją niewidomym, specjalistyczny sprzęt oraz inne cudowne idee wdrażane dla dobra ludzkości, rozwoju sieci i szpanu. To jednak jest o przykrej sprawie.
Continue reading this entry »


Frameworki

Frameworki do PHP to dziwny twór. Do wyboru do koloru: przeładowane dokumentacją, nieudokumentowane w ogóle, za to wszystkie chwalą się głośno swoim reusability i orientacją na enterprise, klonując rozwiązania znane z Javy/Ruby’ego/.NET/innych. Wydawać by się mogło, że ilu programistów tyle frameworków. Kogo to boli?
Bynajmniej nie mnie, bo wychodząc z założenia, że rozwiązań uniwersalnych nie ma, a elastyczność rzucona na pożarcie rzeszom mniej i bardziej rozgarniętych programistów implikuje złożoność i nadmiarowość, lepiej potwierdzić regułę z pierwszego akapitu i napisać coś na własne potrzeby.
Programuję dla internetu nie od dziś i wiem, że oprócz potrzeb mam też nawyki i bariery ideologiczne, tj. nie będę opierał się na frameworku, który, przykładowo, zakłada stosowanie konwencji nazewniczych nie odpowiadających używanym przeze mnie. Lubię czyste i czytelne rozwiązania – np. każdą klasę piszę osobno, zawsze w pliku NazwaKlasy.class.php (a abstracyjne oznaczam NazwaKlasy.abstract.php), nie preferuję PHP do generowania JavaScriptu, bo tego też piszę całkiem osobno i nawet nie zagnieżdżam żadnych wywołań w znacznikach zdarzeniowych etc. etc.
I nie ryzykuję wiele twierdząc, że mniej czasu zajmie mi projekt i implementacja własnego rozwiązania do, uwaga, szybkiego tworzenia aplikacji łatwych w utrzymaniu, niż przebijanie się przez dokumentację obcego co klasę, tudzież przyswajanie zasad, których usilnie uczyłem się wyzbywać zaczytując się na kiblu w autorytatywnej literaturze.


Obiekty sesyjne

Często zachodzi potrzeba przetrzymywania w sesji całych obiektów, przykładowo obiektu Użytkownik, czy np. Koszyk. Jak wiadomo obiekty mają swoje metody i pola, a czasem jest tego całkiem sporo. W warunkach niewielkiego obciążenia serwera problem może wydawać się błahy, ale w sytuacji kilku(nastu) tysięcy wizyt dziennie warto zastanowić się nad prostą i tyle samo niedoskonałą próbą rozwiązania.

Rozważyłem i wprowadziłem dziś w życie następujący pomysł: korzystając z magicznych (sic!) funkcji jakie udostępnia PHP5 napisałem prościutką klasę do obsługi sesji, która pozwala na przechowywanie i odtwarzanie obiektów po uprzednim ich spreparowaniu dzięki serializacji i kompresji.

Wygląda to mniej więcej tak:

public function __set($key, $value) {
if (self::$compress) {
$object = gzcompress(serialize($value), SESS_COMPRESS_LEVEL);
$value = $object;
}
$_SESSION[$key] = $value;
}

public function __get($key) {
if (self::$compress) {
$object = unserialize(gzuncompress($_SESSION[$key]));
} else $object = $_SESSION[$key];
return $object;
}

Oczywiście należałoby przeprowadzić choć najprostszy benchmark. Utworzyłem prosty obiekt składający się z 10 000 właściwości o wartościach wygenerowanych przez uniqid(). Czas obejmujący wywołania kilkunastu klas frameworka i akcji realizującej dynamiczne storzenie obiektu zawierającego 10 tysięcy pól i ich wartości oraz upchanie tego wszystkiego i ponowne pobranie z sesji wynosił średnio 0.092-0.094 sekundy. Z zastosowaniem kompresji i serializacji czas wykonania wynosił około 0.3 sekundy, a więc znacznie dłużej. Jakkolwiek rozmiar obiektu przechowywanego w sesji wynosił 53 245 bajtów (z zastosowaniem kompresji), a po zwróceniu go 420 057 bajtów.

Warto nadmienić także, że w przypadku obiektu zawierającego 10 dynamicznych pól, przykładowe czasy były następujące: 0.0072 z kompresją i serializacją oraz 0.0074 w przypadku standardowego sposóbu przechowywania i odzyskiwania. 

Jak to wyglądałoby w warunkach mocno obciążonego serwera i obiektów "rzeczywistych"… przekonamy się kiedyś.


Trzy rzeczy, które powinieneś wiedzieć o Ajaksie

Po pierwsze: AJAX nie jest nowoczesną technologią. Boom i hype to jedno, a data pierwszego szkicu roboczego zawierającego specyfikacje XMLHttpRequest to drugie.

Po drugie: możesz się nieźle zdziwić próbując wywołań typu cross-domain, ponieważ ze względów bezpieczeństwa żądania tego typu nie są dozwolone. Oczywiście potrzeba matką wynalazku i można to obejść stosując swoiste proxy, którego implementację można pobrać z ajaxextended.com. Jeżeli korzystasz z frameworka prototype, integrację należy przeprowadzić w następujący sposób:

  1. Odszukaj w prototype.js metodę getTransport:
    getTransport: function() {
    return Try.these( function() {
    return new ActiveXObject('Msxml2.XMLHTTP')},
    function() {return new ActiveXObject('Microsoft.XMLHTTP')},
    function() {return new XMLHttpRequest()} ) || false; },
  2. … i zamień ją odpowiednio na:
    getTransport: function() { return xmlhttp = new XMLHTTP(); },

Oczywiście nie wolno zapomnieć o dołączeniu do dokumentu skryptu z ajaxextended i zapewnienia mu komunikacji z klasą PHP z tego samego archiwum.

Po trzecie: Internet Explorer, nie wiedzieć czemu, keszuje żądania GET. Jeżeli np. tworzysz wywołania cykliczne z zastosowaniem jakiegoś interwału, możesz się zdziwić, ponieważ content który otrzymujesz odczytywany jest jednorazowo. Rozwiązaniem problemu jest zwyczajne zastosowanie POST.