Jeśli piszesz kod obiektowy, autoloader jest koniecznością. Bez autoloadera musiałbyś dodać linię z dołączonym plikiem klasy, zanim będziesz mógł go zainicjować. Może to szybko stać się uciążliwe, gdy pracujesz z wieloma klasami. Autoloader to funkcja, która uruchamia się za każdym razem, gdy instancja nowej klasy jest tworzona i zawiera plik klasy, zanim nastąpi instancja.
Przestrzenie nazw to sposób strukturyzacji i hermetyzacji kodu, który pomaga uniknąć kolizji nazw. Jeśli zamierzasz pisać OOP, zaleca się również używanie przestrzeni nazw. Pamiętaj, że możesz zaimplementować autoloader bez używania przestrzeni nazw w kodzie OOP.
Możesz użyć tego kodu do motywu lub wtyczki WordPress lub dowolnego kodu PHP poza WordPress – po prostu odpowiednio zmodyfikuj ścieżki. W tym przykładzie tworzę autoloader dla motywu WordPress.
Zasady dotyczące przestrzeni nazw i struktury klas
Wdrożenie autoloadera wymagałoby pewnych zdefiniowanych reguł dla struktury kodu i tego, gdzie je znaleźć. Korzystanie z przestrzeni nazw upraszcza to nieco, ponieważ przestrzeń nazw może odnosić się do folderu, w którym znajdują się klasy.
Najpierw podejmij decyzję, jaka powinna być nazwana twoja przestrzeń nazw. Zwykle jest to coś unikalnego dla twojego kodu, na przykład nazwa motywu. Na przykład przestrzeń nazw dla motywu tej witryny to AWhitePixelTheme
. Oznacza to, że aby autoloader działał, wszystkie klasy muszą znajdować się w tej przestrzeni nazw.
namespace AWhitePixelTheme;
Moją pierwszą zasadą jest to, że każdy plik klasy będzie zawsze zawierał tylko jedną klasę, a nazwa klasy musi być taka sama jak nazwa pliku. Na przykład; klasa MyTest
musi być zdefiniowana w pliku MyTest.php
.
Moja druga zasada to struktura klas w folderach. Postanawiam, że wszystkie zajęcia znajdują się w folderze src
w moim motywie. Mogę umieścić pliki klas bezpośrednio w tym folderze, a do tego muszą one znajdować się w zdefiniowanej powyżej przestrzeni nazw „root". Ale jeśli chcę tworzyć podfoldery i umieszczać w nich pliki klas, ich przestrzenie nazw muszą zawierać strukturę folderów. Na przykład klasa plik MyTest.php
, który znajduje się w folderze src/Test/
, musi mieć zdefiniowaną tę przestrzeń nazw:
namespace AWhitePixelThemeTest;
Tworzenie autoloadera
Lubię przechowywać autoloader w osobnym pliku i poza src/
folderem, który jest zdefiniowany tylko dla plików klas w przestrzeni nazw. Jako przykład utworzę plik autoloader.php
w folderze inc/
w moim motywie.
PHP ma wbudowaną funkcję autoloadera: spl_autoload_register. Podajesz nazwę swojej funkcji autoloadera jako parametr, aw tej funkcji otrzymujesz żądaną klasę jako argument (to, co new
wstawiasz podczas tworzenia instancji klasy). Podczas tworzenia instancji klas z przestrzeniami nazw, np new AWhitePixelThemeTestMyTest()
., dostarczoną zmienną do tej funkcji będzie "AWhitePixelThemeTestMyTest"
.
Dodajmy funkcję autoloadera, a w niej zdefiniujemy wymaganą przestrzeń nazw dla autoloadera:
Następnie musimy dołączyć ten plik, aby nasz autoloader został zarejestrowany. Ponieważ jest to w motywie, dodam uwzględnienie w motywie functions.php
. Jeśli używasz tego dla wtyczki, umieść go w plikach wtyczki. Plik autoloadera musi zostać dodany wcześniej, przed utworzeniem instancji klas. Umieszczam to w pierwszym wierszu mojego functions.php
:
require_once(get_template_directory(). '/inc/autoloader.php');
Jeśli używasz go do motywu potomnego lub wtyczki, zmodyfikuj ścieżkę do swoich potrzeb.
I to wszystko. Teraz automat ładujący jest na miejscu, ale nic nie robi. Wróćmy do funkcji autoloadera i zakończmy ją.
Pisanie i testowanie funkcji autoloadera
Najpierw musimy upewnić się, że żądana nazwa klasy faktycznie znajduje się w naszej przestrzeni nazw. Po prostu sprawdzamy, czy podana nazwa klasy przestrzeni nazw zawiera ciąg przestrzeni nazw, a jeśli nie, wychodzimy z funkcji. Następnie usuwamy nazwę przestrzeni nazw z ciągu, dzięki czemu możemy opracować dowolne podfoldery i plik klasy.
Teraz przekształcimy podaną przestrzeń nazw w rzeczywistą ścieżkę do pliku. Najpierw zastąpimy wszelkie odwrotne ukośniki ""
w przestrzeni nazw znakiem separatora folderu – do tego używamy stałej PHP DIRECTORY_SEPARATOR
. Na samym końcu dodajemy ".php"
. I na koniec przed napisem dodajemy pełną ścieżkę główną. Ponieważ jest to wewnątrz motywu, używam get_template_directory()
. Jeśli używasz tego dla wtyczki, użyj metody, która zwraca pełną ścieżkę do wtyczki.
...
$class = str_replace($namespace, '', $class);
$class = str_replace('', DIRECTORY_SEPARATOR, $class). '.php';
$directory = get_template_directory();
$path = $directory. DIRECTORY_SEPARATOR. 'src'. DIRECTORY_SEPARATOR. $class;
}
Wszystko, co musimy teraz zrobić, to sprawdzić, czy plik istnieje, a jeśli tak, zażądać go.
...
$path = $directory. DIRECTORY_SEPARATOR. 'src'. DIRECTORY_SEPARATOR. $class;
if (file_exists($path)) {
require_once($path);
}
}
Otóż to!
Przetestujmy to. Utwórz podfolder Test
w folderze swojego motywu src/
, a wewnątrz niego umieść plik php o nazwie MyTest.php
. Zdefiniuj w nim klasę MyTest
, przestrzegając zasad przestrzeni nazw: AWhitePixelThemeTest
. Po prostu dodam wypis „Sukces” w funkcji konstrukcji, abyśmy mogli łatwo zobaczyć, że faktycznie inicjuje ona klasę.
W naszym functions.php, po zażądaniu autoloadera, po prostu tworzymy instancję klasy:
$test = new AWhitePixelThemeTestMyTest();
Odśwież swoją witrynę WordPress i zobacz, że otrzymujesz „Sukces!” wyprowadzane.
Autoloader automatycznie ładuje wszystkie pliki klas, które znajdują się w naszej zdefiniowanej przestrzeni nazw, i postępuje zgodnie z poprawnymi regułami. Możesz tworzyć wystąpienia klas z dowolnego miejsca w motywie, nawet w samych klasach.
Pełna funkcja automatycznego ładowania
Dla porównania, oto nasza ostateczna funkcja automatycznego ładowania:
spl_autoload_register('awhitepixel_autoloader');
function awhitepixel_autoloader($class) {
$namespace = 'AWhitePixelTheme';
if (strpos($class, $namespace) !== 0) {
return;
}
$class = str_replace($namespace, '', $class);
$class = str_replace('', DIRECTORY_SEPARATOR, $class). '.php';
$directory = get_template_directory();
$path = $directory. DIRECTORY_SEPARATOR. 'src'. DIRECTORY_SEPARATOR. $class;
if (file_exists($path)) {
require_once($path);
}
}