![]() |
![]() ![]() |
![]() |
![]()
Post
#1
|
|
Grupa: Zarejestrowani Postów: 1 374 Pomógł: 149 Dołączył: 1.03.2006 Ostrzeżenie: (0%) ![]() ![]() |
dla mnie to chore wywoływac metodę magiczną wewnątrz klasy.
-------------------- |
|
|
![]()
Post
#2
|
|
![]() Grupa: Moderatorzy Postów: 8 989 Pomógł: 1550 Dołączył: 8.08.2008 Skąd: Słupsk/Gdańsk ![]() |
Nieprawda. Jest sens, jeżeli niesie to za sobą jakieś dodatkowe operacje.
-------------------- |
|
|
![]()
Post
#3
|
|
Grupa: Zarejestrowani Postów: 1 374 Pomógł: 149 Dołączył: 1.03.2006 Ostrzeżenie: (0%) ![]() ![]() |
Nieprawda. Jest sens, jeżeli niesie to za sobą jakieś dodatkowe operacje. Nie. Nie ma sensu bo to samo mozna zrobić dowolna metodą choćby prywatną. Ten post edytował JoShiMa 25.02.2011, 10:15:37 -------------------- |
|
|
![]()
Post
#4
|
|
![]() Grupa: Moderatorzy Postów: 8 989 Pomógł: 1550 Dołączył: 8.08.2008 Skąd: Słupsk/Gdańsk ![]() |
Przykład
Widzisz sens? To teraz wyobraź sobie, że zastąpienie tych dwóch metod można zastąpić jedną, magiczną __set. Jak najbardziej jest sens takiego działania.
Powód edycji: [wookieb]:
-------------------- |
|
|
![]()
Post
#5
|
|
![]() Grupa: Zarejestrowani Postów: 6 476 Pomógł: 1306 Dołączył: 6.08.2006 Skąd: Kraków Ostrzeżenie: (0%) ![]() ![]() |
Sensowność metod magicznych sama w sobie jest sprawą mocno dyskusyjną. Ale nie widzę problemu by używać ich z wnętrza obiektu - sytuacja jest przecież dokładnie taka sama jak na zewnątrz.
EDIT: Cytat Jak najbardziej jest sens takiego działania. No właśnie nie ma. ![]() Ten post edytował Crozin 25.02.2011, 10:24:37 |
|
|
![]()
Post
#6
|
|
![]() Grupa: Moderatorzy Postów: 8 989 Pomógł: 1550 Dołączył: 8.08.2008 Skąd: Słupsk/Gdańsk ![]() |
Sensowność metod magicznych sama w sobie jest sprawą mocno dyskusyjną. Słyszałem o tym ale nadal nie widzę powodu by widzieć w tym jakiekolwiek przeciwwskazania. -------------------- |
|
|
![]()
Post
#7
|
|
Grupa: Zarejestrowani Postów: 1 374 Pomógł: 149 Dołączył: 1.03.2006 Ostrzeżenie: (0%) ![]() ![]() |
Przykład
Widzisz sens? To teraz wyobraź sobie, że zastąpienie tych dwóch metod można zastąpić jedną, magiczną __set. Jak najbardziej jest sens takiego działania. Zaręczam Ci, że to samo co możesz umieścić w finkcji __set() możesz umieścić w dowolnej metodzie. Skoro możesz ten kod zwinąć do metody __set() możesz go również zwinąć i umieścić w dowolnej metodzie. funkcje magiczne nie są aż tak magiczne jak się niektórym wydaje. -------------------- |
|
|
![]()
Post
#8
|
|
![]() Grupa: Administratorzy Postów: 1 552 Pomógł: 211 Dołączył: 7.07.2009 Skąd: NJ ![]() |
Nie widzę przeszkód w stosowaniu metod magicznych, jeżeli ktoś ma ochotę - zwłaszcza że widzę ich zasadność. Będzie jednak (z tego co wiem) problem z Reflection API?
|
|
|
![]()
Post
#9
|
|
![]() Grupa: Moderatorzy Postów: 8 989 Pomógł: 1550 Dołączył: 8.08.2008 Skąd: Słupsk/Gdańsk ![]() |
Chyba jednak nie zdajecie sobie sprawy co mówicie. Metody __set i __get umożliwiają zapewnienie dodatkowej logiki w aplikacji tak samo jak "set*" i "get*". Co jeżeli mam 100 właściwości w klasie? 200 metod get i set? Strasznie słabe. Wolę sobie zrobić metodę magiczną __call w połączeniu __set i __get i mieć identyczna funkcjonalność w znaczniej bardziej efektywny sposób.
Mówiąc, że takie operacje można zastąpić dowolną inna metodą jest trochę utrudnianiem losu samemu sobie. Podam doskonały przykład. W C++ są dostępne wektory. Dzięki przeciążeniu operatorów (coś ala "metoda magiczna") można na nich w bardzo łatwy sposób wykonywać operacje matematycze. Będziemy rezygnować z tak niewyobrażalnej wygody tylko po to, żeby "jasno" było widać w kodzie "set"? Straszne słabe. Dla jasności przykładu. Przykładowy wektor to (1,2). Dodanie do niego drugiego wektora (2,3) następuje w ten sposób. (1 + 2, 2 + 3) = (3, 5) Sam stosuje w większości set i get ale to tylko daltego by zapewnić sobie wywołania łańcuchowe. Przy dużej ilości właściwości to nie ma żadnego sensu. -------------------- |
|
|
![]()
Post
#10
|
|
![]() Grupa: Zarejestrowani Postów: 6 476 Pomógł: 1306 Dołączył: 6.08.2006 Skąd: Kraków Ostrzeżenie: (0%) ![]() ![]() |
Cytat Słyszałem o tym ale nadal nie widzę powodu by widzieć w tym jakiekolwiek przeciwwskazania. Co przemawia za metodami magicznymi?- W pewnych przypadkach pozwalają uratować się przed utratą wstecznej kompatybilności. Dodatkowe "zalety": - krótszy kod - bo to właśnie różnica 4 znaków na linię świadczy o jakości kodu. Wady: - Kod staje się nielogiczny. Nagle operacje, które nie powinny mieć miejsca stają się możliwe i są kompletnie nieprzewidywalne. - Brak wsparcia ze strony IDE. - Niezbyt ciekawa sytuacja przy debuggowaniu/próbie zrozumienia kodu. - Problemy przy dokumentowaniu kodu. - A przede wszystkim... kod staje się magiczny czyli tracimy jego klarowność i jednoznaczność/oczywistość. Cytat Będzie jednak (z tego co wiem) problem z Reflection API? Całe szczęście z poziomu refleksji nie istnieje coś takiego. Metody magiczne same w sobie niczym nie różnią się od tych normalnych. Jedynie interpreter przed wyrzuceniem błędu o braku metody/właściwości sprawdza czy aby przypadkiem jakaś magiczna metoda, która mogła by się tym zająć nie istnieje. Możesz odwoływać się do nich jak do każdej innej metody: $obj->__call('abc', array('def'));EDIT: Cytat Co jeżeli mam 100 właściwości w klasie? 200 metod get i set? Strasznie słabe. Strasznie słabe to jest posiadanie takiej ilości właściwości. Poza tym przecież mamy coś takiego jak... tablice i kolekcje.__set spisze się jedynie w przypadku, gdy dla wszystkich przypadków użycia będziemy mieli względnie taki sam algorytm. Bo jeżeli każdą zmienną miałbyś traktować indywidualnie skończyłbyś z dwoma setkami IFów. Co do przeciążania operatorów. Faktycznie w przypadku wielu struktur matematycznych są fajne. Fajnie jest zrobić sobie $myVector - 5 czy $myMatrix * $myMatrix. Ale jedyne co zyskujemy to różnicę kilku znaków ($myVector.substract(5) VS $myVector - 5) a w zamian otrzymujemy mechanizm przez którego powstają potworki których zasada działania jest kompletnie nielogiczna/niezrozumiała/magiczna. To samo spotkało metody magiczne w PHP - są one używane w nieprawidłowy sposób. Chyba tylko po to by ich używać. Ten post edytował Crozin 25.02.2011, 10:43:22 |
|
|
![]()
Post
#11
|
|
![]() Grupa: Moderatorzy Postów: 8 989 Pomógł: 1550 Dołączył: 8.08.2008 Skąd: Słupsk/Gdańsk ![]() |
Wady: - Kod staje się nielogiczny. Nagle operacje, które nie powinny mieć miejsca stają się możliwe i są kompletnie nieprzewidywalne. No nie. Wszystko ma swoje zadania. I ktoś kto projektuje klasę wie o co chodzi. Potem odpowiednio udokumentować i po problemie. Podałem Ci przykład wyżej. Jeżeli zmieniasz jedną wartość to druga się usuwa. Po co użytkownik po swojej stronie miałby to sam sprawdzać? A co gorsza kontrolować w takim przypadku kolejność wywołania "zmiany" właściwości? Jest to jak najbardziej wygodne. Poza tym "set" również może w takim wypadku spowodować Twoim zdaniem "nielogiczne" zachowania. Cytat - Brak wsparcia ze strony IDE. Netbeans Kod @property-read @property-write @property @method I jechana. Cytat - Niezbyt ciekawa sytuacja przy debuggowaniu/próbie zrozumienia kodu. To faktycznie jest troszkę utrudnione Cytat - Problemy przy dokumentowaniu kodu. Czytaj wyżej. To, że PHPDOC chyba takich rzeczy nie wspiera to jego problem. Cytat - A przede wszystkim... kod staje się magiczny czyli tracimy jego klarowność i jednoznaczność/oczywistość. Argument zbity wyżej. P.S. Wydzielam. -------------------- |
|
|
![]()
Post
#12
|
|
![]() Grupa: Zarejestrowani Postów: 6 476 Pomógł: 1306 Dołączył: 6.08.2006 Skąd: Kraków Ostrzeżenie: (0%) ![]() ![]() |
Przede wszystkim powinieneś myśleć nie o autorze klasy, a o jej użytkowniku (nawet jeżeli jest to sam autor).
Przecież nigdzie nie zmieniłem żadnej wartości, jedynie zmieniłem wartość właściwości varA. Usuwam przypisanie wartości - zwraca mi ładnie "varB", przywracam przypisanie wartości jakiejś innej właściwości - zwraca mi NULLa. W taki oto prosty sposób kod staje się magiczny. O ile w przypadku gdy sam jesteś autorem i użytkownikiem dasz sobie bez problemu radę. Ale wyobraź sobie zewnętrzną bibliotekę z piętnastoma takimi obiektami, każdy z jakimś "zwalniającym nas z potrzebny niepotrzebnego pisania" potworkiem pod postacią __set(). A później dochodzą Ci kolejne 4 biblioteki z kolejnymi potworkami - idzie się pochlastać w końcu. Przykład drugi: Ale reakcja jest trochę inna - od razu wiadomo, że jedynym możliwym miejscem zmiany wartości varB jest metoda setVarA(). Trzeba jeszcze zaznaczyć, że nie jest to najlepszy kod. 10 getterów/setterów najparwdopodobniej powinno być zastąpionych jedną parą, a operacje powinny być wykonywane na tablicy. Trzeba pamiętać, że cała magiczność ogranicza się do zamiany $obj->__set('var', $value) na $obj->var = $value. Naprawdę nie zyskujemy niczego poza kilkoma znaczkami. Ahh.. mogłaby to być jeszcze metoda getVarB() (która przykładowo zwracałaby raz varB a raz NULL w zależności od ilości wywołań) - ale wtedy do pierwszego listingu należałoby też dodać wtf spowodowane przez __get() ![]() |
|
|
![]()
Post
#13
|
|
![]() Grupa: Moderatorzy Postów: 8 989 Pomógł: 1550 Dołączył: 8.08.2008 Skąd: Słupsk/Gdańsk ![]() |
To może podam przykład z życia.
Pomińmy piękno tego kodu. Dlaczego linijka oznaczona komentarzem nie miałaby istnieć? Przecież z logicznego punktu widzenia skoro podajemy obiekt Cache do klasy to nie po to, żeby sobie był, tylko żeby z niego skorzystać? Nielogicznym byłoby w tym przypadku wymuszenie konieczności ustawienia flagi używana Cache. A co gdybym dopisał opcję ustawiania flagi $useCache na false w przypadku usunięcia obiektu Cache? To jest jak najbardziej logiczne zachowanie. Klasa to nie tablica, której przypisujemy po prostu wartości do właściwości. Służy do wykonywania konkretnych zadań w których mieści się kontrola nad wartościami w jej wnętrzu. Drugi przykład.
Dlaczego nie miałbym usunąć obiektu użytkownika skoro nie ma id sesji co oznacza, że nie powinno jej być. Oczywiście identyczne zachowania można zrobić za pomocą get i set, tylko co stoi na przeszkodzi aby wykorzystać w tym celu magię? Dla mnie jest to tylko różnica "przyzwyczajeń", niczego więcej. -------------------- |
|
|
![]()
Post
#14
|
|
![]() Grupa: Moderatorzy Postów: 4 362 Pomógł: 714 Dołączył: 12.02.2009 Skąd: Jak się położę tak leżę :D ![]() |
To ja dorzucę jeszcze moją uwagę. Funkcje magiczne, jako wewnętrzne klasy mają dostęp do wszystkiego i są widoczne/ tworzą funkcje jako public z zewnątrz. W efekcie Wywołanie nieistniejącego settera/gettera, daje nam dostęp do wszystkich atrybutów, niezależnie od ich specyfikatora dostępu (!). W tym momencie poszło się paść private i protected. Wszystko jest widoczne dla wszystkich. Stworzenie więc jednego do wszystkiego to zakładanie sobie sznura na szyję.
-------------------- Najpierw był manual... Jeśli tam nie zawarto słów mądrości to zapytaj wszechwiedzącego Google zadając mu własciwe pytania. A jeśli i on milczy to Twój problem nie istnieje :D
|
|
|
![]()
Post
#15
|
|
![]() Grupa: Moderatorzy Postów: 8 989 Pomógł: 1550 Dołączył: 8.08.2008 Skąd: Słupsk/Gdańsk ![]() |
To ja dorzucę jeszcze moją uwagę. Funkcje magiczne, jako wewnętrzne klasy mają dostęp do wszystkiego i są widoczne/ tworzą funkcje jako public z zewnątrz. W efekcie Wywołanie nieistniejącego settera/gettera, daje nam dostęp do wszystkich atrybutów, niezależnie od ich specyfikatora dostępu (!). Zastanów się z 10 razy i napisz post jeszcze raz. Poza tym __get i __set nie służy jedynie do uzyskiwania dostępu do zmiennych prywatnych i chronionych. -------------------- |
|
|
![]()
Post
#16
|
|
![]() Grupa: Zarejestrowani Postów: 898 Pomógł: 80 Dołączył: 31.05.2008 Ostrzeżenie: (20%) ![]() ![]() |
Dla mnie jest rzeczą okrutną że nie można __set i __get ustawić na private ;(
-------------------- cojack blog - mój blog (na jakiś czas off).
"jak czegoś nie wiem, to nie myślę że wiem" - moja domena |
|
|
![]()
Post
#17
|
|
Grupa: Zarejestrowani Postów: 6 Pomógł: 1 Dołączył: 16.10.2007 Ostrzeżenie: (0%) ![]() ![]() |
Z mojej perspektywy to trochę tak jakby sprzeczać czy lepiej użyć "return" czy "echo".
Jednego i drugiego należy używać tam gdzie to jest potrzebne (ułatwia życie, tworzy kod łatwiejszy do modyfikacji itp). Np. używając metod magicznych do view helperów (niezbyt ładny przykład) : oczywiście zamiast tego (bo to magiczne, nieładne i nieczytelne) można użyć:
Moim zdaniem pierwszego kodu używa się łatwiej i szybciej niż drugiego - zwłaszcza w sytuacji gdy mamy 700 linii w szablonie i nie chcemy z jakichś powodów tworzyć ich tam 4000. Tego samego helpera i metod magicznych można użyć w klasie która służy do budowania całego grida czy formularza lub w samej klasie helper by nie dublować kodu. Teraz gdy dochodzi dodatkowy rodzaj helpera, wystarczy dodać odpowiednią klasę obsługi a samego wrapera już nie trzeba ruszać. Oczywiście możemy zrobić fabrykę która zwraca odpowiedni rodzaj helpera i wtedy nie mamy części kłopotów, ale pojawiają się inne - każde podejście ma swoje wady i zalety i składni języka należy użyć w zależności od potrzeb (i naszych preferencji). |
|
|
![]()
Post
#18
|
|
![]() Grupa: Moderatorzy Postów: 4 362 Pomógł: 714 Dołączył: 12.02.2009 Skąd: Jak się położę tak leżę :D ![]() |
Zastanów się z 10 razy i napisz post jeszcze raz. Poza tym __get i __set nie służy jedynie do uzyskiwania dostępu do zmiennych prywatnych i chronionych. Wookieb... Dobrze napisałem. Używając __set i __get, tworzymy metodę, która udostępnia wszystkim na zewnątrz atrybuty klasy. Jeśli byśmy tego nie chcieli w pełni, to musimy to ograniczać już wewnątrz definicji tej metody. Przykładowo mamy wspomnianą przez Ciebie klasę z 200 atrybutami, w tym 5 private i 5 protected, z których nie wszystkie chcemy udostępniać na zewnątrz. Co robimy? Sięgamy po refleksję by sprawdzić, czy dany atrybut jest na "black-liście"? Fajnie... Kosztem naszej wygody (linie kodu) zarżynamy wydajnościowo aplikację, która oprócz magii jeszcze po refleksję sięga.O to mi chodziło w przykładzie. __set i __get oraz inna magia daje dostęp nie zawsze w sposób jaki byśmy chcieli ostatecznie uzyskać i musimy nad tym panować. Poza tym powiedz mi jedno wookieb: "Czy __set i __get ruszają do działania jeśli atrybut jest public?", bo jak dla mnie nie. Sam kwantyfikator zezwala na grzebanie mi w zmiennych public, więc o czym my mówimy tutaj? O pisaniu settera i gettera magicznego dla czegoś, co i tak nie będzie użyte? Bo klasa mając składową publiczną odda nam ją od razu i odwołanie się do magii nie nastąpi nigdy? Dla mnie większy sens mają te funkcje tylko gdy chcemy się zająć wyłapywaniem błędów własnych, a nie posługiwanie tym w sposób nadmierny. To tak jak z mechanizmem wyjątków. Powstał by prościej obsługiwać sytuacje wyjątkowe, a ludzie używają tego do kontroli przepływu danych w aplikacji niczym wariant IF, który dodatkowo trudniej wysypać bo jest "inteligentniejszy". PS... Tak wiem... Pozwala utworzyć i odczytywać w locie obiektowi nieistniejące składowe choćby, ale IMHO takie posługiwanie się wynika ze zrypanego procesu projektowego. Źle zaprojektowana aplikacja po to sięgnie. Dobrze przemyślana nie potrzebuje takich łat. -------------------- Najpierw był manual... Jeśli tam nie zawarto słów mądrości to zapytaj wszechwiedzącego Google zadając mu własciwe pytania. A jeśli i on milczy to Twój problem nie istnieje :D
|
|
|
![]()
Post
#19
|
|
Grupa: Zarejestrowani Postów: 1 374 Pomógł: 149 Dołączył: 1.03.2006 Ostrzeżenie: (0%) ![]() ![]() |
Chyba jednak nie zdajecie sobie sprawy co mówicie. Metody __set i __get umożliwiają zapewnienie dodatkowej logiki w aplikacji tak samo jak "set*" i "get*". Co jeżeli mam 100 właściwości w klasie? 200 metod get i set? Strasznie słabe. Wolę sobie zrobić metodę magiczną __call w połączeniu __set i __get i mieć identyczna funkcjonalność w znaczniej bardziej efektywny sposób. Ale co Ci uniemożliwia wstawienie kodu, który umieściłbyś w __set() wstawić do jednej metody set i nie mieć ich 100?
Zadziała nawet jeśli nie istnieje taki parametr klasy, bo stworzy go w locie. I po co Ci funkcja magiczna? Nie twierdzę, że funkcje magiczne są zupełnie do bani. Jednak używanie ich wewnątrz klasy to totalny bezsens. Ten post edytował JoShiMa 25.02.2011, 13:46:31 -------------------- |
|
|
![]()
Post
#20
|
|
![]() Grupa: Zarejestrowani Postów: 6 476 Pomógł: 1306 Dołączył: 6.08.2006 Skąd: Kraków Ostrzeżenie: (0%) ![]() ![]() |
@Eby: Jak można porównywać return do echo? Poza tym ten przykład to też wiele z tematem wspólnego nie ma. Jak już to powinieneś porównać takie zapisy:
Chociaż osobiście wszystkie uważam za niezbyt trafne. @wookieb: Co do pierwszego listingu... jest on chyba niekompletny bo kompletnie nie trzyma się kupy - albo ja nie potrafię sobie wyobrazić co ten kod miałby robić (konkretniej metoda __set w przypadku gdy podajemy klucz inny niż "cache"). Poza tym już uwidacznia się tu pierwszy "wtf". Na metodę __set() spada obowiązek wykonywania wielu zadań - czy nie lepiej by było: I używać kodu normalnie, tj: Raczej nie przekonasz mnie, że interfejs drugiego rozwiązania jest lepszy... bo jak dla mnie to jest on okropny i podatny na błędy. Cytat A co gdybym dopisał opcję ustawiania flagi $useCache na false w przypadku usunięcia obiektu Cache? Dodać metodę odpowiedzialną za usuwanie cache, która po usunięciu zmieni flagę?Cytat Klasa to nie tablica, której przypisujemy po prostu wartości do właściwości. Służy do wykonywania konkretnych zadań w których mieści się kontrola nad wartościami w jej wnętrzu. Gdy pisałem o tablicach/kolekcjach miałem na myśli taką sytuację:Pomijając fakt o ile bardziej podatne na błędy i mniej elastyczne jest drugie rozwiązanie (ograniczone możliwości dla nazwania kluczy, problem gdy nazwa klucza jest w zmiennej) spójrzmy na całą różnicę pomiędzy użyciem obu rozwiązań:
Co do drugiego przypadku (z klasą Session). Znowu ten sam problem - dziesiątki IFów. Na pewno żaden z nas nie byłby szczęśliwy mając wykorzystywać tą klasę. Takie rozwiązanie dla mnie byłoby do zaakceptowania wyłącznie w przypadku konieczności zachowania wstecznej kompatybilności. Tj. zakładając, że mamy już kod, klasy, która ma publiczną właściwość "id" musimy dodać jeszcze opcję usuwania użytkownika gdy jest ona fałszem. Paskudne rozwiązanie ale jedno z niewielu jakie pozwala na zachowanie tej nieszczęsnej kompatybilności. |
|
|
![]() ![]() |
![]() |
Wersja Lo-Fi | Aktualny czas: 29.06.2025 - 12:44 |