This post comes from the first version of this blog.
Please send me an email if anything needs an update. Thanks!
Język PHP zawiera w sobie dużo różnych “sztuczek”, przez co nasze życie może stać się o wiele łatwiejsze, ale istnieje możliwość, że zostanie przez nas znienawidzony do końca życia. W dzisiejszym wpisie chciałbym pokazać i wyjaśnić jedną z bardzo niejasnych i bardzo brzegowych kwestii, jaką jest zachowanie zasięgu zmiennych podczas przechodzenia do innych plików [np. w przypadku ich includowania]. Zapraszam do lektury.
Fotografia: Milian Wolff, CC-BY.
TL;DR.
Nie da się zdefiniować klasy ani wewnątrz funkcji, ani wewnątrz metody. Jeśli chcesz wiedzieć dlaczego - czytaj dalej.PHP: Definiowanie klasy wewnątrz funkcji lub metody.
Rozważmy następującą sytuację:
|
|
Co tutaj mamy? Teoretyczny programista [w tym przypadku ja] próbuje zdefiniować klasę Bar w zasięgu funkcji bar() w zakresie klasy Foo. Brzmi trochę pokrętnie, ale mam nadzieję, że wszyscy rozumiemy, jaki jest cel.
Nie ważne, czy dla podanego przypadku istnieje jakiś sensowny przypadek użycia - widziałem już tyle dziwnych pomysłów w programowaniu, że ten jeden mnie jakoś specjalnie nie dziwi. Z drugiej strony jakby się uprzeć, to na pewno coś by się znalazło [np. posiadanie prywatnych klas w zasięgu konkretnej funkcji], pomimo tego, że aktualnie ciężko byłoby mnie do tego przekonać - chyba, że ktoś wyperswadowałby mi używanie Dependency Injection Containera na rzecz czegoś JESZCZE lepszego.
Koniec rozważań - niestety tak to nie zadziała. Powód? Proszę bardzo:
Fatal error: Class declarations may not be nested in [file] on line [line]
Jedziemy dalej - spróbujmy więc tą klasę zaincludować. Nasz plik zmienia się następująco:
|
|
I plik z klasą:
|
|
Wynik?
Bar::baz
Działa? Działa. Tak jak chcemy? Niestety… nie. Otóż tutaj do gry wchodzi “sztuczka” interpretera PHP [manual funkcji include()]:
When a file is included, the code it contains inherits the variable scope of the line on which the include occurs. Any variables available at that line in the calling file will be available within the called file, from that point forward. However, all functions and classes defined in the included file have the global scope.Oznacza to, że jeśli włączamy do kodu kolejny plik poprzez jedną z instrukcji (include|require)(_once)(), zasięg zmiennych zostaje przeniesiony do kolejnego pliku - np. zmiennej zadeklarowane w metodzie i potem we włączonym pliku są dostępne tylko w tej metodzie - czyli dokładnie tak, jakbyśmy wstawili dany fragment kodu w miejsce funkcji włączającej. Wyjątkiem od tej reguły są funkcje i klasy - one są deklarowane w zasięgu globalnym.
W takim przypadku następujący kod da praktycznie ten sam wynik:
|
|
Wynik:
|
|
Tak samo wykona się definicja klasy w funkcji:
|
|
Wariantu z includowaniem pliku klasy w funkcji chyba nie muszę już komentować. ;] Mogę więc uznać temat za wyczerpany. Jeśli coś byłoby jeszcze niejasne, zapraszam do komentowania - odpowiem na wszystkie Wasze pytania. ;]