Włączanie plików + autoloader, chętnie bym posłuchał ciekawych pomysłów |
Tematy na forum Pro mogą zakładać jedynie moderatorzy. W otwartych tematach może pisać każdy, kto ma coś fachowego do powiedzenia. Wszystkie posty nie wnoszące nic do tematu będą natychmiast usuwane, a ich autorzy dostaną ostrzeżenie.
Jeśli uważasz, że jakiś temat jest warty dyskusji na tym forum, zgłoś go w temacie Propozycje.
Włączanie plików + autoloader, chętnie bym posłuchał ciekawych pomysłów |
10.02.2005, 17:23:52
Post
#1
|
|
Grupa: Zarejestrowani Postów: 521 Pomógł: 0 Dołączył: 3.11.2003 Skąd: 3city Ostrzeżenie: (0%) |
Problem stary jak świat: system wymaga włączenia sporej liczby plików i zarządzanie tym jest upierdliwe. Do tego nie należy włączać więcej kodu niż potrzeba, a najlepiej zrobić jakieś lazy load.
Oczywiście, technik jest wiele: 1) require_once rozsiane po plikach, najlepiej poprzedzone jakąś stałą, np. require_once ROOT_DIR . '/foo/Foo.class.php'; 2) Prado: deklarujemy namespacy - np. za pomocą funkcji using(), co dodaje nam ścieżki do include_path, a potem niech php znajdzie klasę. 3) Autoloader + mapa (nazwa klasy => ścieżka do pliku); autoloader wczytuje mapę i na jej podstawie jest w stanie znaleźć każdą klasę Są jeszcze jakieś inteligentne sposoby? Dobry mechanizm powinien być odporny na "przemeblowanie" struktury plików (np. chcemy połączyć kilka klas w jeden plik). BTW, włączanie plików bez klas (tylko funkcje i kod) jest gorsze, bo nie ma tego czegoś, czego można szukać po plikach... kolejna zaleta OOP? |
|
|
10.02.2005, 21:46:51
Post
#2
|
|
Grupa: Zarząd Postów: 2 277 Pomógł: 6 Dołączył: 27.12.2002 Skąd: Wołów/Wrocław |
Aby sprawę jeszcze bardziej skomplikować - warto pamietać o tym - że require_once i inlude_once jest w rzeczywistości bardzo wolne = każde wywołanie tych funkcji, nawet jeśli tym razem NIE MUSIAŁA ona ładować tego pliku, bo już był załadowany wcześniej, trwa niemal tyle samo, co require()
proste porównanie: http://www.phpinsider.com/smarty-forum/viewtopic.php?t=4323 I choć, jak ktoś to zauwazył w tym wątku, fizyczny zysk czasu jest niewielki, to jednak procentowo - różnica jest ogromna. -------------------- "Niezależnie od tego, jakie masz osiągnięcia, ktoś Ci pomaga..."
|
|
|
11.02.2005, 18:39:48
Post
#3
|
|
Grupa: Zarejestrowani Postów: 105 Pomógł: 0 Dołączył: 16.10.2004 Ostrzeżenie: (0%) |
Myślę, że moje rozwiązanie pomoże Ci, jeśli wpadniesz na jakiś dobry pomysł, to daj znać:
(nawiasem mówiąc każda klasa przekłada się na lokalizację w ten sposób: Projekt_Podgrupa_Costam -> /packages/projekt/podgrupa/projekt_podgrupa_costam.php zdecydowałem się na to, aby każdy plik miał pełną nazwę klasy, a instalator tworzył pakiety klas.) Plik poza_drzewkiem/packages/noname/noname_package.php
(zamiast kaboom w __autoload() będzie komunikat o tym, że strona nieczynna i próba poinformowania admina) Pliki *_package.php zawierają zlepek klas najczęściej wykorzystywanych w danym pakiecie (noname_package.php zawiera noname_(core,timer,exception itp).php . ) ImportEx różni się tym, że najpierw spróbuje władować pakiet (czyli np. jak władowywyję jakąś usługę, dajmy SQL, to automatycznie mam wyjątki, klase do łączenia, klase do zapytań itp.) Jeśli jestem pewien, że jakaś klasa/interfejs powinna być w systemie to poprostu z niej korzystam - jeśli nie jest władowana, to zrobi to autoload. (Klasa z pakietu nie musi sprawdzać innych z tego samego pakietu, najczęściej stosowana przeze mnie metoda) Jeśli wgrywam usługę (auth, sql, cache...) to daję CORE::ImportEx, żeby wgrać pakiet. Jeśli potrzebuję pojedynczą klasę to poprostu CORE::Import. Obie funkcje Import i ImportEx zwracają true/false, czyli ustrzegają mnie przed wykorzystaniem nieistniejącej klasy, a co za tym idzie przed Fatal Error. Przed próbą odczytania pliku oczywiście jest sprawdzenie, czy nie jest obecna już dana klasa/interfejs. -------------------- Com powiedział, powiedziałem.
|
|
|
18.02.2005, 14:39:33
Post
#4
|
|
Grupa: Zarejestrowani Postów: 521 Pomógł: 0 Dołączył: 3.11.2003 Skąd: 3city Ostrzeżenie: (0%) |
@Imperior:
Dwie słabe strony tu widzę: 1) Wszystko musi siedzieć w 2 miejscach: NN_LIB i NN_PRIVATE, co utrudnia model działania typu "user ściąga pakiet, wrzuca gdzie mu się podoba i chce żeby to działało". 2) Nie da się tego połączyć z zewnętrznymi bibliotekami, tzn takimi, gdzie nie ty decydujesz o nazwach klas. Za to podobają mi się dwie inne rzeczy: 1) Importowanie całych "pakietów". 2) Nazwa_Klasy niejako emuluje pakiety, których php nie ma (nie możesz zrobić $foo = new com.example.Foo). A mi się coraz bardziej podoba mapa:
Autoloader jest w tym momencie banalny. Takie mapy można nawet generować automatycznie przeszukując skryptem katalogi i parsując (tokenizując) pliki php. Można automatycznie łączyć mapy dostarczane z pakietami w jedną wspólną. Można dowolnie łączyć pliki w pakiety, wrzucać do jednego pliku, dzielić itd., a potem przegenerować mapę i dalej wszystko działa. Szczególnie podoba mi się to w kontekście trzymania "normalnej" hierarchii plików u siebie i dystrybuowania wszystkiego w jednym pliku po wycięci komentarzy i whitespaces. Wada - trzeba ten głupi plik wczytać zanim autoloader cokolwiek zrobi . I ciężko byłoby automatycznie wstawić stałe jak w przykładzie powyżej. |
|
|
18.02.2005, 15:03:36
Post
#5
|
|
Administrator PHPedia.pl Grupa: Developerzy Postów: 1 102 Pomógł: 2 Dołączył: 14.09.2003 Ostrzeżenie: (0%) |
Ja mysle, zeby rozwiazac to na podobnej zasadzie jak w javie. Mianowicie :
Mamy metode import, ta zaś wczytuje plik/pliki jakie chcemy. Czyli robimy:
W pierwszym przypadku wczyta klase Bar ktora jest w katalogu pl/bela/foo/bar/, a w drugim wczyta wszystkie klasy znajdujące się w katalogu pl/bela/foo, z wyjatkiem pl.bela.foo.bar.Bar bo informacja o tym ze taka klasa jest załadowa jest przetrzymywane w tablicy ( 2 posty wyzej jest wyjasnienie czemu ). Co do położenia katalogow pl/bela, net/php/smarty, nie przejmuje sie tym za bardzo, ponieważ są classpathy Aha, i nie definiuje package(); no bo po co -------------------- |
|
|
18.02.2005, 20:17:07
Post
#6
|
|
Grupa: Zarejestrowani Postów: 105 Pomógł: 0 Dołączył: 16.10.2004 Ostrzeżenie: (0%) |
Cytat(hawk @ 2005-02-18 13:39:33) Dwie słabe strony tu widzę: 1) Wszystko musi siedzieć w 2 miejscach: NN_LIB i NN_PRIVATE, co utrudnia model działania typu "user ściąga pakiet, wrzuca gdzie mu się podoba i chce żeby to działało". 2) Nie da się tego połączyć z zewnętrznymi bibliotekami, tzn takimi, gdzie nie ty decydujesz o nazwach klas. ad 1. NN_LIB jest podrzędne do NN_PRIVATE. W NN_LIB są trzymane właśnie pakiety, dla mnie nie do pomyślenia jest coś takiego, że user wrzuca jakiś pakiet gdzie mu się żywnie podoba, zamiast tego jest Instalator, przez którego może ściągnąć pakiet, uploadować, wskazać na serwerze i na podstawie plików konfiguracyjnych w pakiecie wszystko jest pięknie i ładnie instalowane razem z weryfikacją zależności. ad 2. Z pozoru... Jeśli pliki będą w NN_LIB to zostaną załadowane, jedynie musi być spełniony warunek, żeby nie miały '_' w nazwach... (a jeśli tak, to żeby były prawidłowo umieszczone, ale wtedy probelmu nie ma ) Ciekawe z tymi mapami... a gdyby rozszerzyć je o jakieś wyrażenia regularne? -------------------- Com powiedział, powiedziałem.
|
|
|
21.02.2005, 14:43:27
Post
#7
|
|
Grupa: Zarejestrowani Postów: 521 Pomógł: 0 Dołączył: 3.11.2003 Skąd: 3city Ostrzeżenie: (0%) |
@bela_666: Takie rozwiązanie na pewno pasuje do javy, ale czy pasuje do php? Wszystko rozbija się o wydajność. Trzeba te importy przeczytać, pozamieniać na slashe, znaleźć katalogi, wczytać pliki... Owszem, mamy classpath (tzn. include_path ), ale w php jest to kosztowna (IMHO, nie robiłem testów) opcja, bo szuka po dysku przy każdym requeście. A przecież nie pozbędziemy się bibliotek, które nie stosują się do naszego standardu (smarty, adodb, ...). Czyli classpath się rozrasta.
Do tego, w php opłaca się wczytywać tylko te pliki, które są niezbędne. W javie nie ma tego problemu, bo wczytujesz raz i masz spokój. W php starasz się zminimalizować ilość operacji dyskowych na jedno żądanie. W javie importy i w ogóle pakiety są potrzebne, bo 2 klasy w różnych pakietach mogą mieć tą samą nazwę i nie jest to problem. W php taka sytuacja jest niedozwolona, więc i pakiety są niepotrzebne (tak naprawdę jest to zabronione właśnie dlatego, że nie ma pakietów, ale skutek jest ten sam). W javie z importami jest jeden problem: w pewnym momencie robi się ich zbyt dużo i upraszczamy sobie życie pisząc import java.util.*. W php jest to nie do przyjęcia - za dużo niepotrzebnie włączanego kodu. Więc nie muszę się martwić o unikalność com.example.hawk, bo to i tak nic mi nie daje. @Imperior: sens regexpów zależy od tego, czy będą one szybsze niż wymienienie wszystkich klas. Czyli od wydajności. Podsumowując, idealnie chciałbym mieć: - nie muszę w swoich plikach php pisać require_once, przypominać sobie gdzie są potrzebne klasy, oraz upewniać się że nie pominąłem potrzebnego interfejsu - mogę obsługiwać zewnętrzne (nie moje) biblioteki tak samo (tzn też bez pamiętania o require_once smarty) - mogę w trakcie developmentu zmienić strukturę moich plików z klasami, przenieść do innych katalogów, itd. bez poprawiania mojej aplikacji - mogę zmienić coś w n-tej dystrybucji pakietu bez obawy, że kod użytkowników nie znajdzie mojej klasy - włączane są tylko te klasy, które są aktualnie potrzebne, i narzut czasy wykonania jest minimalny |
|
|
25.02.2005, 09:23:01
Post
#8
|
|
Grupa: Zarejestrowani Postów: 521 Pomógł: 0 Dołączył: 3.11.2003 Skąd: 3city Ostrzeżenie: (0%) |
@serafin: Możesz napisać więcej? Mi się zawsze wydawało że php nie pozwala na kropki w nazwie klasy. Tak bardzo mi się wydawało, że nigdy nie sprawdziłem. I czy to oznacza, że pełna nazwa klasy rzeczywiście brzmi System.Console.Out? Żeby autoloader mógł znaleźć klasę.
Bo problem z brakiem namespaces jest taki, że jak napiszemy $foo = new System.Console.Out, to php nie wie, że ma szukać klasy Out w System.Console, tylko szuka System.Console.Out. |
|
|
25.02.2005, 09:55:57
Post
#9
|
|
Grupa: Zarejestrowani Postów: 105 Pomógł: 0 Dołączył: 16.10.2004 Ostrzeżenie: (0%) |
Cytat(hawk @ 2005-02-25 08:23:01) Bo problem z brakiem namespaces jest taki, że jak napiszemy $foo = new System.Console.Out, to php nie wie, że ma szukać klasy Out w System.Console, tylko szuka System.Console.Out. A ściślej mówiąc to stara się odczytać stałe i połączyć je w jeden string. Ja to zrozumiałem w ten sposób, że pisze kod, który zawiera błędy z punktu widzenia parsera php, a który jest parsowany, aby poprawić te błędy i dopisać jakieś includy itp. Alternatywnie poprostu w kodzie jest coś jak: uses 'System.Console.Out'; i to jest odczytywane, żeby do pliku wynikowego dodać includy. serafin: czy coś w tym stylu miałeś na myśli? -------------------- Com powiedział, powiedziałem.
|
|
|
25.02.2005, 11:42:46
Post
#10
|
|
Grupa: Zarejestrowani Postów: 657 Pomógł: 2 Dołączył: 15.08.2003 Skąd: Łódź Ostrzeżenie: (0%) |
A co Wam się stanie gdy zamiast System.Out będzie System_Out ?
Czy warto stosować te wszystkie parsery/tokenizery czy co tam jeszcze (opóźniające czas wykonywania) aby wygrać "walke" z kropką ? -------------------- |
|
|
25.02.2005, 12:06:36
Post
#11
|
|
Grupa: Zarejestrowani Postów: 521 Pomógł: 0 Dołączył: 3.11.2003 Skąd: 3city Ostrzeżenie: (0%) |
Nic się nie stanie, poza utratą estetyki . Chociaż kwestia "kropka czy kreska" nie jest tutaj podstawowa. Problem jest raczej w tym, że autoloader będzie szukał klasy System_Out, a nie klasy Out w pakiecie System. Czyli na braku pakietów. I na tym, że na pewno znajdą się biblioteki, gdzie kreska jest używana do czegoś innego, co może wprowadzić system w błąd.
|
|
|
25.02.2005, 12:31:22
Post
#12
|
|
Grupa: Zarejestrowani Postów: 657 Pomógł: 2 Dołączył: 15.08.2003 Skąd: Łódź Ostrzeżenie: (0%) |
ale to jest php a nie java
Co do autoloadera... co za problem zrobić jakiś explode po znaku _ i odpowiednio sprawdzić? -------------------- |
|
|
25.02.2005, 12:48:42
Post
#13
|
|
Grupa: Zarejestrowani Postów: 521 Pomógł: 0 Dołączył: 3.11.2003 Skąd: 3city Ostrzeżenie: (0%) |
Co za problem? Sprawdzanie po zrobieniu explode jest kosztowne. Odwołanie do dysku, przemnożone przez ileś tam włączanych klas. A ja zakładałem sobie idealnie, że autoloader, jako "jądro jądra", musi być super szybki.
Żeby nie było że się czepiam: to nie jest zła metoda, na razie nie zakodowałem samemu nic mądrego (stąd ten wątek). Zawsze są zady i walety, ja tylko wymieniam słabe strony. |
|
|
25.02.2005, 12:50:43
Post
#14
|
|
Grupa: Przyjaciele php.pl Postów: 2 335 Pomógł: 6 Dołączył: 7.03.2002 Ostrzeżenie: (0%) |
Troche to stary kod ale moze sie przyda:
Wywolania: Import( 'db.*' ); includuje wszystkie klasy z katalogu include_path.'db/' Import( 'db.jakas_klasa' ); includuje klasy o nazwie jakas_klasa z katalogu db Pliki z klasami musza miec w nazwie .class.php Aha... pisany pod php 4, wiec bez autoloadera :/ Ten post edytował Seth 25.02.2005, 12:53:16 |
|
|
25.02.2005, 12:55:30
Post
#15
|
|
Administrator PHPedia.pl Grupa: Developerzy Postów: 1 102 Pomógł: 2 Dołączył: 14.09.2003 Ostrzeżenie: (0%) |
Seth, a czy te pregi nie spowalniają bardzo przy dużej ilości plików ?
-------------------- |
|
|
25.02.2005, 13:07:03
Post
#16
|
|
Grupa: Przyjaciele php.pl Postów: 2 335 Pomógł: 6 Dołączył: 7.03.2002 Ostrzeżenie: (0%) |
Jakies spowolnienie napewno jest ale za to mozna latwo zaincludowac kilka klas
|
|
|
26.02.2005, 00:02:23
Post
#17
|
|
Administrator PHPedia.pl Grupa: Developerzy Postów: 1 102 Pomógł: 2 Dołączył: 14.09.2003 Ostrzeżenie: (0%) |
Cytat(hawk) Podsumowując, idealnie chciałbym mieć: - nie muszę w swoich plikach php pisać require_once, przypominać sobie gdzie są potrzebne klasy, oraz upewniać się że nie pominąłem potrzebnego interfejsu - mogę obsługiwać zewnętrzne (nie moje) biblioteki tak samo (tzn też bez pamiętania o require_once smarty) - mogę w trakcie developmentu zmienić strukturę moich plików z klasami, przenieść do innych katalogów, itd. bez poprawiania mojej aplikacji - mogę zmienić coś w n-tej dystrybucji pakietu bez obawy, że kod użytkowników nie znajdzie mojej klasy - włączane są tylko te klasy, które są aktualnie potrzebne, i narzut czasy wykonania jest minimalny No chyba udało mi się to osiągnąć, mianowicie: tokenizer przejezdza po wszystkich katalogach i załączą pliki .php, a przy okazji pomija katalogi .svn ( coś się zawieszało ), wyciąga nazwy klas/interfejsów i to gdzie one się znajdują, wciska to do tablicy i generuje piękny pliczek autoload.php, wraz z funckją __autoload. No, to by było na tyle -------------------- |
|
|
26.02.2005, 09:35:42
Post
#18
|
|
Grupa: Zarejestrowani Postów: 134 Pomógł: 0 Dołączył: 27.01.2005 Skąd: Białystok Ostrzeżenie: (0%) |
Jeśli mogę wtrącić trzy grosze, ja myślę, że można przejechać po katalogach czymś takim:
Tylko trzeba zdefiniować stała ROOT_PATH i dodać do nazwy rozszerzenie i zdefiniować klasę CORE. Warunki:
-------------------- |
|
|
26.02.2005, 09:55:15
Post
#19
|
|
Grupa: Zarejestrowani Postów: 521 Pomógł: 0 Dołączył: 3.11.2003 Skąd: 3city Ostrzeżenie: (0%) |
@bela_666: pokaż pokaż pokaż
|
|
|
26.02.2005, 11:55:48
Post
#20
|
|
Grupa: Zarejestrowani Postów: 657 Pomógł: 2 Dołączył: 15.08.2003 Skąd: Łódź Ostrzeżenie: (0%) |
Nievinny: jakbyś zrobił cache jakiś to ok. Teraz uważam, że to jest najgorsze z najgorszych rozwiązań
-------------------- |
|
|
Wersja Lo-Fi | Aktualny czas: 27.09.2024 - 01:30 |