Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: Destruktor traci bibliotekę
Forum PHP.pl > Forum > PHP > Object-oriented programming
Marcstee
Witam.

Mam pewien problem z destruktorem. Problem wygląda następująco:

Wywołuje się front_controller i w nim są ładowane klasy z biblioteki. Potem akcja rozgrywa się w modelu. Tam wszystko pięknie działa wszystkie klasy są dostępne. Potem tworzę w nim nowy obiekt klasy X. wywołuję funkcję publiczną tego obiektu i kończę akcje. W destruktorze klasy X jest wykonywana pewna funkcja która wymaga innych klas z biblioteki. Jednak destruktor ten już ich nie widzi. Metoda wywoływana na tym obiekcie może być nawet pusta a i tak straci się biblioteka (ale tylko w obrębie tej klasy). Gdy po prostu stworze obiekt klasy X i nie wywołam na nim żadnej metody to w destruktorze dalej dostępne są klasy z biblioteki.

Na prawdę nie wiem jaki może być tego powód. Bardzo proszę o jakieś porady.
wookieb
A mógłbyś sypnąć trochę kodem ponieważ trudno Cię do końca zrozumieć albo ja dziś jestem zaćmiony.
Marcstee
wchodzimy na stronę -> wywoływany jest front_controller w którym ładowana jest cała biblioteka (require_once).
dalej akcja przekazywana jest do modelu. W modelu są różne akcje. Jedna z nich to:
  1. ...
  2. $obiektX = new xclass();
  3. ...

W obiekcie X w destruktorze jest pewna akcja:
  1. ...
  2. function __destruct(){
  3. klasaZBiblioteki::jakasFunkcjaStatycznaNaPrzyklad();
  4. }
  5. ...

Jeżeli nie wywołam na $obiektX żadnej metody tej klasy to jest wszystko ok i działa. Jednak gdy użyje jakieś:
  1. ...
  2. $obiektX->doSomething();
  3. ...

To destruktor już nie zadziała prawidłowo bo nie będzie widział już 'klasaZBiblioteki'.
wookieb
Ok. Czyli dostajesz błąd że nie ma klasy "klasaZBiblioteki" tak?
Opowiedz jeszcze jaki masz proces autoładowania klas, czyli jak wygląda twój __autoload.
Jak narazie wydaje mi sie, że albo akcja wywołuje zmiane katalogu roboczego (chdir) albo include_path (set_include_path), co może powodować właśnie taki problem.
Albo jeżeli to php 5.3 to zmieniany jest namespace
Marcstee
autoload jedzie po calym lib'ie i ładuje wszystkie klasy pokolei.
a akcja doSomething() może być nawet pusta (samo return true) a i tak ten sam problem będzie.
PHP5.2.11
to po prostu wygląda tak, jakby obiektX jeżeli wywołuje się na nim jakaś metoda to usuwa się na samym końcu po bibliotece. A gdy nie użyje się niczego na nim, że usuwa się pierwszy kiedy jeszcze wszystko jest
wookieb
Pokaż kod swojej xclass oraz podaj komunikat błędu jaki otrzymujesz.
Marcstee
Ta xclass to moze byc nawet samo:
  1. class xclass
  2. {
  3. function __destruct(){
  4. klasaZBiblioteki::jakasFunkcjaStatycznaNaPrzyklad();
  5. }
  6. public function doSomething() {
  7. }
  8. }

a mimo to będzie błąd. A błąd jest, że nie może załadować odpowiedniej klasy.
wookieb
Czy błąd nadal będzie występować jak zrobisz coś takiego pod koniec skryptu?
  1. $twoj_obiekt_xclass->__destruct();
  2. unset($twoj_obiekt_xclass);


Jeżeli tak będzie problem rozwiązęsz jeżeli dołączysz potrzebną bibliotekę na samym początku pliku definiującego podaną klasę.
Marcstee
No tak, jak dołączę ją w pliku xclassy to działa. Ale chciałbym wiedzieć dlaczego? Co powoduje, biblioteka się nagle traci?
wookieb
Na zakończenie skryptu wywoływane są wszystkie destruktory istniejących obiektów, co powoduje też zmianę katalogu roboczego. Dlatego twój autoloader nie był w stanie znaleźć potrzebnej klasy.
Marcstee
Mhm ale to nie tłumaczy jednej rzeczy. Dlaczego gdy nie wywołam metody doSomething() to destruktor znajduje odpowiednią klasę?
wookieb
Nie wiem dlaczego używam php 5.3.2 a tam jest lepszy GC, wiec moze to wynikac z wersji php. Po prostu gc mógł uznać, że obiekt będzie ci niepotrzebny wcześniej i destruktor wykonał się wcześniej.
Marcstee
Mhm... czyli należy przypuszczać, że skoro z obiektem nic się nie robi będzie on wcześniej usunięty, niż jakby były na nim wykonywane operacje. Ok. A czy są może jakieś źródła gdzie można by poszerzyć wiedzę na ten temat? Bo myślę, że warto się tym zainteresować a nie mam pojęcia jak tego poszukać.
wookieb
Szczerze mówiąc to nie wiem dokładnie gdzie znajdziesz to o czym rozmawiamy ale poczytałbym tutaj
http://pl.php.net/manual/en/features.gc.php

Oraz ciekawostka
http://paul-m-jones.com/archives/262
Marcstee
Hmmm ciekawy temat powiem. Zrobilem kilka testów i oto wyniki:
  1. <?php
  2. class Foo
  3. {
  4. public $var = 'xxsdcadscadscasdcsdcasdcasx';
  5.  
  6. public function foo_function(){}
  7. }
  8.  
  9.  
  10. $foo = new Foo();
  11. $foo->foo_function();
  12.  
  13. unset ($foo);
  14.  
  15. ?>


gdy odpalimy ten plik wynik będzie (u mnie) taki:
  1. 87048
  2. 87368
  3. 87136


gdy jednak zakomentujemy $foo->foo_function();
to wynik już będzie taki:
  1. 86784
  2. 87016
  3. 86784


Ciekawe jest to, że w 1 wypadku pamieć jak widać nie do końca została zwolniona. Test wykonany w PHP 5.2.11. Wersja 5.3.0 już zwalnia całkowicie pamięć.

Natomiast co do omawianego problemu to nie znalazłem jednoznacznej odpowiedzi, jednak wydaje mi się ( w oparciu o to co przeczytałem), że jest to spowodowane tym, że jak obiekt jest stworzony ale nie używany w żaden sposób to jest on szybciej likwidowany. Gdy jednak coś z nim robimy PHP czeka do samego końca bo może jeszcze coś z nim się stać i dlatego był kasowany później co powodowało te problemy.
To jest wersja lo-fi głównej zawartości. Aby zobaczyć pełną wersję z większą zawartością, obrazkami i formatowaniem proszę kliknij tutaj.
Invision Power Board © 2001-2024 Invision Power Services, Inc.