2010-07-06 13 views
10

Właśnie przeczytałem o zmiennej unset poprzez php manual.zmienna unset w php

Instrukcja php mówi „rozbrojony() niszczy podanych zmiennych”

Ten def wydaje się idealne, aż natknąłem zmiennej statycznej ... „Jeśli zmienna statyczna jest wyłączony(), wewnątrz funkcja, unset(), niszczy zmienną tylko w kontekście reszty funkcji, po czym następuje przywrócenie poprzedniej wartości zmiennej. "

Ta definicja nie wydaje się dla mnie dobra, najmniej, ponieważ "zniszczyć zmienną" oznacza, że ​​zmienna nie jest już a skojarzone z tą lokalizacją w pamięci.

Czy ktokolwiek uważa, że ​​lepsza definicja byłaby "unset() czyni zmienną poza bieżącym zasięgiem"? Mam na myśli, zamiast wskazywać na całe życie, lepiej użyć tutaj zakresu słów?

+0

To nie jest dobre pytanie dla SO. Możesz oznaczyć takie rzeczy na listach dyskusyjnych PHP lub czymkolwiek, ale nie ma tu żadnej wartości. Czego można oczekiwać od odpowiedzi? Czy jesteś zadowolony, gdy mówię * Tak *? ;) –

+1

felix, jestem tylko początkującym, jeśli powiesz "tak", to na pewno pobudzę moją pewność siebie i jeśli powiesz "nie", to na pewno czegoś się nauczysz, ale od teraz będę się tym zajmować. Czemu – Tarun

Odpowiedz

13

Rozważmy funkcję:

function foo() { 
    static $bar; 
    $bar++; 
    unset($bar); 
} 
foo(); //static $bar is 1 
foo(); //static $bar is 2 

Funkcja kompiluje do:

 
function name: foo 
number of ops: 11 
compiled vars: !0 = $bar 
line  # * op       fetch   ext return operands 
--------------------------------------------------------------------------------- 
    2  0 > EXT_NOP             
    4  1  EXT_STMT             
     2  FETCH_W      static    $0  'bar' 
     3  ASSIGN_REF            !0, $0 
    5  4  EXT_STMT             
     5  POST_INC           ~1  !0 
     6  FREE              ~1 
    6  7  EXT_STMT             
     8  UNSET_VAR            !0 
    7  9  EXT_STMT             
     10 > RETURN             null 

Zmienna rzeczywiście istnieje poza każdym wywołaniu funkcji do foo(), a na każdym połączeniu, to naciągane i odniesienie do jest przypisany do $bar.W rzeczywistości, to jest bardzo podobne do tego:

function foo() { 
    global $bar; 
    $bar++; 
    unset($bar); 
} 

Po wywołaniu unset(), ty psujesz tylko utworzoną odniesienia, a nie wartością bazową.

nie potwierdzają, ale to, co ja myślę, że dzieje się to:

  • Podstawowym reprezentacja variabe (The zval) są przechowywane tak, że jego licznik odniesienia 1.
  • Po wywołaniu foo(), symbol $bar jest powiązany z tym obiektem zala, jego licznik odwołań jest zwiększany do 2 i ustawiana jest flaga odniesienia.
  • Po wywołaniu unset, liczba zliczeń referencyjnych zmniejszyła się do 1, flaga odniesienia prawdopodobnie zniknie, a symbol $bar zostanie usunięty.

Zobacz reference count basics.

+0

dziękuję za cenne informacje – Tarun

+3

@artefactor Jestem ciekawa, jak to wygenerowałeś położyć? – MANCHUCK

+0

@ Artefakto, czy to wyjście dla HHVM lub ZE? – Pacerier

9

Wewnątrz funkcji, nazwy zmiennych odnoszące się do zmiennych statycznych są właśnie tymi .. odniesieniami. W efekcie unset niszczy referencję.

+0

miałeś zamiar powiedzieć zadeklaruj zmienną statyczną jako (rozważ wewnątrz fn) static $ a = 2; $ b = $ a + 2; // tutaj $ a staje się referncem zmiennej statycznej $ a ;? Nie udało mi się uzyskać punktu sir – Tarun

+0

Dla zmiennych statycznych, miejsce na stercie jest przydzielane dla wartości danych, a miejsce na stosie jest przydzielane dla łącza referencyjnego. Podczas wyłączania odniesienia tylko obszar lokalnego stosu jest niszczony/odzyskiwany/unieważniany. – Zak

+0

thankz zak dla przydatnych informacji – Tarun

3

unset (self :: $ somethingstatic); spowoduje błąd krytyczny, ponieważ zmienna jest statyczna (zawsze tam, nie można jej anulować).

dokumentacja odnosi się konkretnie do zmiennych statycznych zdefiniowanych wewnątrz funkcji, należy rozważyć:

function t($stage) 
{ 
    static $shell = 23; 
    switch($stage) { 
    case 1: 
     $shell++; 
     break; 
    case 2: 
     unset($shell); 
     break; 
    case 3: 
     $shell--; 
    break; 
    } 
    echo $shell; 
} 

ponieważ $ powłoka jest zmienna statyczna, to zawsze istnieje (statyczny), więc każdy inny czas wspomnieć $ powłokę, która jest po prostu odniesienie - gdy je wyzerujesz, niwelujesz odniesienie (pomyśl o odłączeniu dowiązania symbolicznego) - zmienna statyczna jest jednak nadal obecna (to znaczy co oznacza "statyczny").

więc jeśli wywołanie funkcji powyższy t (1) ogłosi 24, t (2) będzie echo nic, a t (3) będzie (słusznie) echo 23 :)

żadnej pomocy?

+0

i wld uwielbiam mówić "w dowolnym innym czasie, gdy wspominasz o powłoce $ $, która jest po prostu referencją:" ale AFAIK ..w pamięci php jest alokowana nawet dla odniesienia ?? popraw mnie – Tarun

+0

thankz nathan i din, t Wiem, że ustawiam wyłączenie właściwości statycznej, daję błąd – Tarun

+0

Ta odpowiedź sprawiła, że ​​było dla mnie bardziej zrozumiałe –

0

Cóż, to, co robi unset(), powoduje wyczyszczenie pamięci skojarzonej z nazwą zmiennej.

Jednak w przypadku zmiennych statycznych można sobie wyobrazić, że dzieje się to oddzielając zmienną statyczną od zakresu funkcji, a za każdym razem, gdy wywołuje się funkcję, automatycznie otrzymuje się kopię tej zmiennej.

Co oznacza, że ​​jeśli unset jest zmienną statyczną, to w rzeczywistości jest to tylko unset tej kopii, więc gdy funkcja zostanie wywołana ponownie, "odbiera" nową kopię.

+0

co jest nie tak, jeśli tylko wizualizuję, że unset() wykopię zmienną poza zakres, teraz, gdy wyczyści memorię związaną ze zmienną, czy nie, zależy to od czas życia zmiennej. – Tarun

+0

cóż, problem z tym, co mówisz, polega na tym, że zmienna "static" nie jest * w * zakresie funkcji i dlatego przechodzi z połączenia na połączenie. OTOH, jesteś na dobrej drodze, jeśli uważasz, że jest to kopia tej statycznej zmiennej, którą "wykopujesz poza zasięg" –

1

Jeśli nie mylę się, punktem jest wyzerowanie zmiennej statycznej. Z różnych powodów może to być przydatne, dodatkowo zwolniłoby to trochę pamięci. Na przykład:

unset($some_static_var_or_property_holding_a_big_object); 

Chociaż nie możemy achive to dokładnie tak, jak jest, w niektórych przypadkach może być wystarczający, aby to zrobić:

$some_static_var_or_property_holding_a_big_object = null; 

Byłoby to zwolnić pamięć (chyba) i pozwoli nam niszczyć obiekt, którego już nie chcemy (mam nadzieję, że nie będę wyłączony z tematu).