wykorzystywałem ostatnio sesje do przechowywania obiektów i spostrzegłem bardzo ciekawe zachowanie PHP, tj. jeżeli zapiszę obiekt do sesji to przy jego dalszej modyfikacji niejawnie aktualizowany jest on w sesji. Czy ktoś jest w stanie wytłumaczyć jak działa ten mechanizm 'pod spodem'?
Przygotowałem paczkę która prezentuje to zagadnienie:
SessionRegistry.php
<?php class SessionRegistry{ private function __construct(){ } } } protected function get($name){ return NULL; } return $_SESSION[__CLASS__][$name]; } protected function set($name, $val){ $_SESSION[__CLASS__][$name] = $val; } protected function unregister($name){ } function SetManager(Manager $upload){ $this->set('manager', $upload); } function GetManager(){ return $this->get('manager'); } function UnregisterManager(){ $this->unregister('manager'); } function ManagerScreen(){ } }
Manager.php
<?php class Manager{ function __construct(){ } function hireWorkers($num=15){ $num = (int)$num; for($i=0; $i<$num; $i++){ $this->new[] = new Worker(); } } function SaveToSession(){ $Sess_reg = SessionRegistry::instance(); $Sess_reg->SetManager($this); } $Sess_reg = SessionRegistry::instance(); return $Sess_reg->GetManager(); } $Sess_reg = SessionRegistry::instance(); $Sess_reg->ManagerScreen(); } function filterWorkers(){ foreach($this->new as $worker){ $this->good[] = $worker; }else{ $this->bad[] = $worker; } } } function undoFilter(){ } } } class Worker{ private $id; function __construct(){ } }
set.php
<?php require_once 'loader.php'; $Manager = new Manager(); $Manager->hireWorkers(); $Manager->SaveToSession(); ?>
change.php
<?php require_once 'loader.php'; $Manager = Manager::LoadFromSession(); $Manager->filterWorkers(); //$Manager->undoFilter(); ?>
show.php
<pre> <?php require_once 'loader.php'; ?> </pre>
loader.php
<?php function __autoload($class){ require_once "{$class}.php"; } ?>
Przepływ zdarzeń:
1. Uruchamiam set.php
2. Uruchamiam show.php
3. Wynik print_r:
Kod
Manager Object
(
[new:Manager:private] => Array
(
[0] => Worker Object
(
[id:Worker:private] => 509b99e26056c
)
[1] => Worker Object
(
[id:Worker:private] => 509b99e26094d
)
[2] => Worker Object
(
[id:Worker:private] => 509b99e260d33
)
[3] => Worker Object
(
[id:Worker:private] => 509b99e261148
)
[4] => Worker Object
(
[id:Worker:private] => 509b99e261518
)
)
[good:Manager:private] => Array
(
)
[bad:Manager:private] => Array
(
)
)
(
[new:Manager:private] => Array
(
[0] => Worker Object
(
[id:Worker:private] => 509b99e26056c
)
[1] => Worker Object
(
[id:Worker:private] => 509b99e26094d
)
[2] => Worker Object
(
[id:Worker:private] => 509b99e260d33
)
[3] => Worker Object
(
[id:Worker:private] => 509b99e261148
)
[4] => Worker Object
(
[id:Worker:private] => 509b99e261518
)
)
[good:Manager:private] => Array
(
)
[bad:Manager:private] => Array
(
)
)
Jak widać jest wszystko co powinno być. Manager utworzył instancje Workerów, i zapisał się do sesji - wynikiem jest uzupełniona tablica new.
4. Uruchamiam change.php (zwróćcie uwagę, że nie ma tam wywołania SaveToSession)
5. Ponownie uruchamiam show.php i tym razem na ekranie pojawia się coś takiego:
Kod
Manager Object
(
[new:Manager:private] => Array
(
)
[good:Manager:private] => Array
(
[0] => Worker Object
(
[id:Worker:private] => 509b99e26094d
)
[1] => Worker Object
(
[id:Worker:private] => 509b99e260d33
)
[2] => Worker Object
(
[id:Worker:private] => 509b99e261d0e
)
)
[bad:Manager:private] => Array
(
[0] => Worker Object
(
[id:Worker:private] => 509b99e26056c
)
[1] => Worker Object
(
[id:Worker:private] => 509b99e261148
)
)
)
(
[new:Manager:private] => Array
(
)
[good:Manager:private] => Array
(
[0] => Worker Object
(
[id:Worker:private] => 509b99e26094d
)
[1] => Worker Object
(
[id:Worker:private] => 509b99e260d33
)
[2] => Worker Object
(
[id:Worker:private] => 509b99e261d0e
)
)
[bad:Manager:private] => Array
(
[0] => Worker Object
(
[id:Worker:private] => 509b99e26056c
)
[1] => Worker Object
(
[id:Worker:private] => 509b99e261148
)
)
)
Plik change.php zmienił obiekt, 'nie mówiąc nic o tym sesji', ale sesja 'sama zaktualizowała' jego stan... Czy nie powinno być przypadkiem tak, że sesja powinna utrzymywać 'pierwotny' stan obiektu? Bardzo proszę, w miarę możliwości, wytłumaczyć co się dzieje 'pod maską' tego przykładu.
Z góry serdecznie dziękuję,
Maciek