Nie wiem już ile razy zachwycałem się na moim blogu możliwościami języków skryptowych, a najbardziej tymi, które możemy znaleźć w PHP. Dawno, dawno temu, kiedy jeszcze moja wiedza na temat tego języka była “cokolwiek nikła” zauważyłem w czytanym kodzie pewne ciekawe rozwiązanie. O ile na pierwszy rzut oka było ono zrozumiałe, o tyle wychodząc z praktyką wyniesioną z języków takich, jak Pascal / Delphi, czy C / C++ stwierdziłem, że to nie może być możliwe. Kiedy okazało się, że jednak może - ciężko było mi pozbierać myśli.

Fotografia: ejk, CC-BY-SA.

Wstęp: Dynamizm w kodzie.

Jak wszyscy dobrze wiemy, w językach kompilowanych ciężko jest wpłynąć na strukturę programu, czy też jego działanie “w trakcie jego działania”. Mechanizmy takie, jak Run-Time Type Information (RTTI) to jedynie półśrodki do osiągnięcia minimum kontroli nad tym, co się w naszym kodzie wywołuje.

Oczywiście programiści to grupa społeczna, która “nie jest w ciemię bita” i szybko zorganizowała sobie odpowiednie narzędzia, dzięki którym poszczególne funkcjonalności można było łatwo osiągnąć. Nie były to oczywiście narzędzia idealne, aczkolwiek wystarczające w zdecydowanej większości przypadków.

Wszystko zmieniło się w momencie, kiedy do szerokiej grupy programistów dotarła idea języków interpretowanych. Abstrakcja, jaką oni operowali przeniosła się z poziomu translacji kodu języka programowania na kod maszynowy na “interpretację” kodu języka przez interpreter / maszynę wirtualną. Przyniosło to istotny zysk - od teraz zarówno kod, jak i środowisko uruchomieniowe były kontrolowane przez programistów.

Nie trzeba być wielkim myślicielem, żeby dostrzec zyski płynące z takiego właśnie potraktowania całej sprawy. Jeśli jesteśmy w stanie zdefiniować własne środowisko uruchomieniowe i zmieniać / dostosować je do własnych wymagań, to jesteśmy także w stanie przekazać odpowiednie informacje do samego języka programowania, które to środowisko interpretuje. Dzięki temu… wszystko jest możliwe. ;]

PHP: Warunkowe definiowanie funkcji.

Tematem, który chcę podjąć w tym wpisie, jest warunkowe definiowanie funkcji. Brzmi znajomo? Jeśli nie spotkaliście się wcześniej z tym zagadnieniem, raczej nie. Weźmy pod uwagę następujący kod:

define('OS_VERSION', 'x64');

if('x64' == OS_VERSION)
	{
	function echoVersion()
		{
		echo 'This is 64-bit version.';
		return;
		}
	}
else
	{
	function echoVersion()
		{
		echo '32-bit version here.';
		return;
		}
	}

echoVersion();

Jaki będzie jego wynik? Otóż, wcale nie żaden “parse error”, nie wystąpi żaden błąd duplikacji nazwy funkcji. Powyższy listing wyrzuci nam na ekranie przeglądarki krótki tekst:

This is 64-bit version.

Okazuje się, że interpreter PHP wykonuje kod “na bieżąco” i nie skanuje go w poszukiwaniu potencjalnych problemów ze strukturą skryptu - w tym przypadku dwóch funkcji o tej samej nazwie. Dlatego w momencie, kiedy natrafi na warunek [if], interpretowany jest jedynie fragment kodu zawarty w jego pasującym bloku. Oczywiście, jeśli zmienimy definicję:

define('OS_VERSION', 'x86');

Otrzymamy wynik:

32-bit version here.

Oczywiście może istnieć tylko jedna funkcja o nazwie “echoVersion”, stąd w zależności od wartości stałej OS_VERSION zostanie zdefiniowany jeden z jej wariantów. Najbardziej zbliżona do tego możliwość występuje w językach C / C++, gdzie możemy na etapie kompilacji sterować kodem za pomocą makr preprocesora. Należy jednak pamiętać, że zrobienie czegoś takiego w trakcie wykonywania programu jest niemożliwe. Pod tym względem PHP zawiera w sobie dosyć unikalną funkcjonalność.

Takie rozwiązanie może być przydatne podczas pisania kodu, który ma się uruchomić w kilku środowiskach / wersjach, aczkolwiek po raz kolejny - jest to tylko pewnego rodzaju ciekawostka. W “prawdziwym programowaniu” powinniśmy wykorzystać np. wzorzec Strategii - nie dlatego, że powyższe rozwiązanie jest złe, ale dlatego, że nie możemy polegać na funkcjonalnościach, które jeden język posiada, a inny nie.

Ciekaw jestem Waszej opinii na temat warunkowego definiowania funkcji - czy podobnie jak ja uznacie to za niegroźną zabawkę, czy wręcz przeciwnie - za propagowanie bezwzględnie złych praktyk programistycznych. Czekam na komentarze. ;]