This post comes from the first version of this blog.
Please send me an email if anything needs an update. Thanks!

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:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
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ę:

1
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. ;]