Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: Dostęp destroktora do unset()
Forum PHP.pl > Forum > PHP > Object-oriented programming
Athlan
Realizując projekt przyszła mi potrzeba dopisania pewnej klasy do mojego frameworka. Mianowicie, ma ona przechwycić plik uploadowany z podanego pola i skopiować go do plików tymczasowych frameworka. Stamtąd może wyciągać informacje o nim. Po zuploadowaniu klasa może przyjąc plik w inne miejsce metodą publiczną copy(). Nie będę jednak opisywał działania klasy, ale przedstawię główne zadanie:

Skopiować plik do folderu plików tymczasowych framework ( /application/var/ ) przy konstruktorze i skasować go w destruktorze.

Ostatnio dość irytującą rzeczą stał się fakt, iż desruktor nie może użyć funkcji unlink() (usowania pliku). Gdy wypluję jego ścieżkę za pomocą echo(), wówczas zostanie ona wyświetlona, ba, mogę ją nawet usunąć z buforu funkcją unset(). Patrząc na te aspekty, można stwierdzić, że destruktor ma pełny dostęp do danych przed zniszczeniem instancji klasy. Ok, fajnie, pobierzmy sobie dla funkcji unlink() zmienną którą zwraca metoda $this->_temp() (ścieżka do pliku na którym pracuje sobie klasa. Po zakończeniu prac na pliku, trzeba go usunąć. Zamiast usunięcia pojawia się tajemniczy błąd:

Cytat
Fatal error: Exception thrown without a stack frame in Unknown on line 0


Klasa wygląda mniej więcej tak:

  1. <?php
  2.  
  3. final class Vfile
  4. {
  5. // ...
  6.  
  7. public function __destruct()
  8. {
  9. unlink($this->_temp());
  10. }
  11.  
  12. // ...
  13. }
  14.  
  15. ?>


gdyby wstawić echo(), wypluje nam scieżkę do pliku, ale nie widocznie php nie chce użyć funkcji unlink() w destruktorze.

Coś pominąłem, źle robie? A może destruktor wywoływany jest później niż zamykane są prawa dostępu do pliku (chociaż nielogiczne)? Czy jest jakiś haczyk na mój problem?

btw: to samo mam z obsługą sesji na plikach tekstowych, z bazą danych działa smile.gif

Problem rozwiązałem kopjując plik do /var/ mojego frameworka w konstruktorze, zbierając wszystkie informacje i usówając również w konstruktorze. Wszystkie metody zwracają poszczególne informacje... wobec tego destruktor pozostaje bezrobotny (i dobrze), gdyż nie musi usówac pliku, bo zostało to wykonane zaraz po wykonaniu kopii zapasowej przez framework z tempu serwera. Gdy metoda mojej klasy copy() zostanie poproszona o plik, ponownie skopjuje go z tempu serwera juz w docelowe miejsce. Myślę, że połowa z Was powie: "poi co framework kopiuje sobie plik do swojej własnej pamięci?". Szczeże mówiąc sam się zastanawiam tongue.gif może usunę to z mojej klasy tongue.gif

Ostatecznie jednak zdecydowałem się, że nie będę zasmiecał pamięci frameworka... a niech klasa sobie lata do tempu serwewa... Ostatecznie wygląda to tak


  1. <?php
  2.  
  3. final class Vfile
  4. {
  5. private $_sInstance = NULL;
  6. private $_aFilePost = array();
  7. private $_aFileData = array();
  8.  
  9. public function __construct($sPostField)
  10. {
  11. if(!defined("V_VAR"))
  12. throw new VfileException('V_VAR has no defined!');
  13.  
  14. $this->_sInstance = $sPostField;
  15. $this->_aFilePost = $_FILES[$sPostField];
  16.  
  17. $this->_aFileData = $this->_aFilePost;
  18. $this->_aFileData['extension'] = end(explode('.', $this->_aFileData['name']));
  19. $this->_aFileData['temp'] = $this->_aFilePost['tmp_name'];
  20. }
  21.  
  22. public static function posted($sPostField)
  23. {
  24. return (bool) (isset($_FILES[$sPostField]['tmp_name']));
  25. }
  26.  
  27. public function copy($sFilePatch, $sFileName = NULL)
  28. {
  29. $sFileName = ($sFileName) ? $sFileName : $this->name;
  30.  
  31. if(!($bResult = copy($this->temp, $sFilePatch . $sFileName)))
  32. throw new VfileException('I cannot load file "' . $sFileName . '" to directory "' . $sFilePatch . '"!');
  33.  
  34. return $bResult;
  35. }
  36.  
  37. public function __get($sInfoCardKey)
  38. {
  39. return (isset($this->_aFileData[$sInfoCardKey])) ? $this->_aFileData[$sInfoCardKey] : NULL;
  40. }
  41.  
  42. public function info()
  43. {
  44. return $this->_aFileData;
  45. }
  46. }
  47. ?>



Pozdrawiam, Athlan smile.gif
hwao
W destruktorze już nie ma dostępu do właściwości (są usunięte) - to też zależy... każdemu co innego wychodzi. W php destruktory to najbardziej "niezrozumiałe" zjawisko. smile.gif
Athlan
No tak @hwao, mielismy okazję je omówić na komunikatorze smile.gif co rozumiesz przez słowo "właściwości" ?

Jeżeli "właściwości" rozumiesz jako atrybuty, to owszem... destruktor ma do nich dostęp. Może na nich operowac itd. Zauwazyłem jednak, że destruktor ma pełne prawa do zapisu danych do bazy danych (zaużmy przy własnej obsłudze sesji) ale do praw plików nie ma wogóle dostępu. Gdy za bezę danych podstawiłem do zapisu file_put_contents() z zasetrializowaną tablicą sesji, wówczasz plik się tworzy... ale pusty, zupełnie jakby ładował do neigo NULL.

Sprawa ciekawa, czasem można powiedzieć - wkurzająca. Moim zdaniem destruktor powinien mieć pełne prawa do systemu plików, może napiszemy petycję do twórców php haha.gif ?
mariuszn3
W pierwszym przykładzie dosyć istotna jest jednak zawartość metody temp() jaki jest jej algorytm? Czy korzysta z innych obiektów? Ostatnio miałem problem z kolejnością wywoływania destruktorów zaaktualizowałem php (z 5.1 na 5.2) od razu problem zniknął - tak więc w pierwszej kolejności proponuję się upewnić, że masz ostatnią wersję php'a smile.gif
Athlan
Cytat(mariuszn3 @ 16.11.2006, 19:43:47 ) *
W pierwszym przykładzie dosyć istotna jest jednak zawartość metody temp() jaki jest jej algorytm?

Warto byłoby czytać posty dokładnie... pod skryptem jest napisane:
Cytat
gdyby wstawić echo(), wypluje nam scieżkę do pliku


Jak widać destruktory nie mają dostepu do ystemu plików, wszystkie operacje trzeba przekazać konstrutorowi, tak też zrobiłem

Pozdrawiam winksmiley.jpg
mariuszn3
Sorry nie doczytałem dokładnie.
Tak czy siak nie jest prawdą, że destruct'ory nie mają dostępu do operacji na plikach, niby dlaczego tak miałoby być? Tak jest w specyfikacji? Czy twierdzisz tak, bo w Twojej aplikacji coś nie zadziałało?
Napisz najprostszy możliwy test wywołujący unlink() w destruct'orze i zobaczysz, że zadziała - coś innego u Ciebie nie gra.
Z której wersji php korzystasz? To może mieć kluczowe znaczenie.
Athlan
Cytat
Czy twierdzisz tak, bo w Twojej aplikacji coś nie zadziałało?
Napisz najprostszy możliwy test wywołujący unlink() w destruct'orze i zobaczysz, że zadziała - coś innego u Ciebie nie gra.


Zazwyczaj jak mi coś nie działa tworzę testy. Specjalnie dla Ciebie zadedykowałem poniższy kod obrazujący mój pogląd, a raczej fakt istanienia błędu (jeżeli mogę tak to nazwać).

Używam php 5.2.0, pozwoliłem sobie stworzyć kod obrazujący moją teorię i okazało się, że mam rację:

  1. <?php
  2.  
  3. /**
  4.  * Test by Piotr 'Athlan' Pelczar
  5.  * 
  6.  * Klasa pokazuje jakie prawa dostępu do plików ma destruktor i konstruktor
  7.  * 
  8.  * NOTE:
  9.  * 
  10.  * specjalnie została użyta funkcja die() a nie wyjątek, gdyż
  11.  * w destruktorze nie mogą być łapane żadne wyjątki... a przerwanie jego
  12.  * pracy jest konieczne. Udowodnone jest to, że destruktor ma pełne prawa
  13.  * do atrybutu $this->_sFilePatch.
  14.  * 
  15.  * ATTENTION:
  16.  * 
  17.  * przed odpaleniem klasy nalezy stworzyć plik i nadać mu
  18.  * prawa chmod 777 o nazwie/ścieżce podanej w konstruktorze klasy.
  19.  * 
  20.  */
  21.  
  22. // budujemy klasę...
  23. class MyTest
  24. {
  25. private $_sFilePatch = null;
  26.  
  27. public function __construct($sFilePatch)
  28. {
  29. $this->_sFilePatch = $sFilePatch;
  30.  
  31. echo 'constructor said: '.$this->_sFilePatch.'<br />';
  32.  
  33. if(!file_exists($this->_sFilePatch) || !is_writable($this->_sFilePatch))
  34. die('constructor: no usable file');
  35. }
  36.  
  37. public function __destruct()
  38. {
  39. echo 'destructor said: '.$this->_sFilePatch.'<br />';
  40.  
  41. if(!file_exists($this->_sFilePatch) || !is_writable($this->_sFilePatch))
  42. die('destructor: no usable file');
  43.  
  44. unlink($this->_sFilePatch);
  45. }
  46. }
  47.  
  48. // ok odpalamy klasę...
  49. $oMyTest = new MyTest('./file.txt');
  50.  
  51. ?>


Otrzymałem nastepujący rezultat:

Kod
constructor said: ./file.txt
destructor said: ./file.txt
destructor: no usable file


Jak widać... konstruktor w pełni widzi plik (ma do niego dostęp), a destruktor (pomimo tego że używa odpowieniego atrybutu) pliku nie widzi... paradoksalne zjawisko prawda?
mariuszn3
Pierwsza sprawa - Twój test to nie jest idealnym wyizolowaniem problemu, u Ciebie może wejść w drogę parę innych bug'ów php (jeśli takowe są).. przez to nie możesz być pewien co naprawdę u Ciebie sprawia, że test daje wynik negatywny.
Myślę, że idealnym testem byłby następujący kod:
  1. <?php
  2. class MyTest {
  3.  public function __destruct() {
  4.  unlink('/var/www/test');
  5. }
  6. }
  7. // ok odpalamy klasę...
  8. $oMyTest = new MyTest();
  9. ?>

i nic poza tym (zwróć też uwagę na absolutną ścieżkę do pliku) jak to powyżej się wykrzaczy, możesz już z dużą pewnością przyjąć, że coś jest nie tak z dostępem do plików w destruktorze (ale warto to jeszcze potwierdzić na innym systemie z tą samą wersją php)

Odpalałem również Twój kod, zarówno pod windows'em i linux'em i wszystko działa tak jak powinno - plik jest kasowany..
Lecz kto wie, może faktycznie jest to bug php dopiero nie dawno naprawiony, bo zarówno pod windowsem jak i linuxem mam php (pobrane z dwa tygodnie temu) ze snapsów (wersja 5.2.1-dev).
Nie mam teraz możliwości sprawdzenia tego pod 5.2.0 Tak więc moja sugestia - pierw sprawdź czy brak absolutnej ścieżki do pliku nie ma na to wpływu, następnie albo zaktualizuj się do ostatniej dystrybucji dostępnej w snaps'ach lub jeśli nie masz takiej możliwości szukaj potwierdzenia swojej tezy na innym systemie z php 5.2.0
Athlan
A więc podałem i absolutną ścieżke pliku i plik nie jest kasowany...

Co do mojego testu... dałem go "aż" taki "wieki" bo chciałem udowodnić, że konstruktor widzi plik, a destruktor nie... poza tym destruktor ma dostęp do atrybutu, który określa ścieżkę do pliku. W bugtrack było o tym dosyc głośno:

http://bugs.php.net/bug.php?id=32412 - bug z php4
http://bugs.php.net/bug.php?id=30267 - bug z php 5.0.1

Ciekawa sprawa... warto to potestować, dzięki Ci @mariuszn3 że się zainteresowałeś... czekam na inne odpowiedzi pozostałych uzytkowników forum. Zapewne mają coś do dodania smile.gif

Pozdrawiam, Athlan smile.gif

--[edit]--

Jeżeli znajdę chwilkę, podejme sie dokładniejszych oględzin problemu: zapizywanie, czytanie z plików itd.
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-2025 Invision Power Services, Inc.