Witaj Gościu! ( Zaloguj | Rejestruj )

Forum PHP.pl

> PHP aktualizuje zserializowany w sesji obiekt
macq
post
Post #1





Grupa: Zarejestrowani
Postów: 11
Pomógł: 0
Dołączył: 8.11.2012

Ostrzeżenie: (0%)
-----


Witam,

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
  1. <?php
  2. class SessionRegistry{
  3. private static $instance;
  4.  
  5. private function __construct(){
  6.  
  7. }
  8.  
  9. static function instance(){
  10. if(!isset(static::$instance)){
  11. static::$instance = new self();
  12. }
  13.  
  14. return static::$instance;
  15. }
  16.  
  17. protected function get($name){
  18. if(!isset($_SESSION[__CLASS__][$name])){
  19. return NULL;
  20. }
  21.  
  22. return $_SESSION[__CLASS__][$name];
  23. }
  24.  
  25. protected function set($name, $val){
  26. $_SESSION[__CLASS__][$name] = $val;
  27. }
  28.  
  29. protected function unregister($name){
  30. unset($_SESSION[__CLASS__][$name]);
  31. }
  32.  
  33.  
  34. function SetManager(Manager $upload){
  35. $this->set('manager', $upload);
  36. }
  37.  
  38. function GetManager(){
  39. return $this->get('manager');
  40. }
  41.  
  42. function UnregisterManager(){
  43. $this->unregister('manager');
  44. }
  45.  
  46. function ManagerScreen(){
  47. return print_r($_SESSION[__CLASS__]['manager']);
  48. }
  49.  
  50. }
  51.  




Manager.php
  1. <?php
  2. class Manager{
  3. private $new = array();
  4. private $good = array();
  5. private $bad = array();
  6.  
  7.  
  8. function __construct(){
  9.  
  10. }
  11.  
  12. function hireWorkers($num=15){
  13. $num = (int)$num;
  14. for($i=0; $i<$num; $i++){
  15. $this->new[] = new Worker();
  16. }
  17. }
  18.  
  19.  
  20. function SaveToSession(){
  21. $Sess_reg = SessionRegistry::instance();
  22. $Sess_reg->SetManager($this);
  23. }
  24.  
  25. static function LoadFromSession(){
  26. $Sess_reg = SessionRegistry::instance();
  27. return $Sess_reg->GetManager();
  28. }
  29.  
  30.  
  31. static function SessionScreen(){
  32. $Sess_reg = SessionRegistry::instance();
  33. $Sess_reg->ManagerScreen();
  34. }
  35.  
  36.  
  37. function filterWorkers(){
  38. foreach($this->new as $worker){
  39. if(rand(0, 1) == 1){
  40. $this->good[] = $worker;
  41. }else{
  42. $this->bad[] = $worker;
  43. }
  44. }
  45.  
  46. $this->new = array();
  47. }
  48.  
  49. function undoFilter(){
  50. $this->new = array_merge($this->good, $this->bad);
  51. $this->good = array();
  52. $this->bad = array();
  53. }
  54.  
  55. function reset(){
  56. $this->new = array();
  57. $this->good = array();
  58. $this->bad = array();
  59. }
  60.  
  61. }
  62.  
  63.  
  64. class Worker{
  65. private $id;
  66.  
  67. function __construct(){
  68. $this->id = uniqid();
  69. }
  70. }




set.php
  1. <?php
  2. require_once 'loader.php';
  3.  
  4.  
  5. $Manager = new Manager();
  6.  
  7. $Manager->hireWorkers();
  8. $Manager->SaveToSession();
  9.  
  10. ?>




change.php
  1. <?php
  2. require_once 'loader.php';
  3.  
  4.  
  5.  
  6. $Manager = Manager::LoadFromSession();
  7.  
  8. $Manager->filterWorkers();
  9. //$Manager->undoFilter();
  10. ?>




show.php
  1. <pre>
  2. <?php
  3. require_once 'loader.php';
  4.  
  5.  
  6. print_r(Manager::SessionScreen());
  7.  
  8.  
  9. ?>
  10. </pre>




loader.php
  1. <?php
  2. function __autoload($class){
  3. require_once "{$class}.php";
  4. }
  5.  
  6. ?>






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
        (
        )

)

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
                )

        )

)


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

Ten post edytował macq 8.11.2012, 13:29:03
Go to the top of the page
+Quote Post
 
Start new topic
Odpowiedzi (1 - 2)
nospor
post
Post #2





Grupa: Moderatorzy
Postów: 36 557
Pomógł: 6315
Dołączył: 27.12.2004




Obiekty przekazywane są przez referencje. Czyli jak ty z sesji pobierasz obiekt to tak naprawdę pobierasz jego referencję i wszelkie zmiany jakie robisz na tym obiekcie dotyczą zmian u źródła, czyli w tym przypadku w obiekcie zapisanym w sesji smile.gif

Jeśli chcesz pobrać klon obiektu, to musisz go poprostu sklonować przy użyciu CLONE

ps: a na przyszłość nie generuj aż 15 próbek by nam coś pokazać. 3 wystarczą - nie trzeba wówczas pół godziny scrollować posta... wink.gif


--------------------

"Myśl, myśl, myśl..." - Kubuś Puchatek || "Manual, manual, manual..." - Kubuś Programista
"Szukaj, szukaj, szukaj..." - Kubuś Odkrywca || "Debuguj, debuguj, debuguj..." - Kubuś Developer

Go to the top of the page
+Quote Post
macq
post
Post #3





Grupa: Zarejestrowani
Postów: 11
Pomógł: 0
Dołączył: 8.11.2012

Ostrzeżenie: (0%)
-----


Dzięki nospor za info!

Właśnie rzuciłem okiem do pliku sesji po stronie serwera i w sumie po jego zawartości można było wydedukować sposób zachowania tego mechanizmu... ale to już wpadło mi do głowy dopiero po Twoim poście wink.gif


Jeszcze raz wielkie dzięki wink.gif

PS. Co do próbek - sorry, już tego błędu nie powtórzę wink.gif Troszkę się już nawet zreflektowałem!

Pozdrawiam serdecznie,
Maciek

Go to the top of the page
+Quote Post

Reply to this topicStart new topic
1 Użytkowników czyta ten temat (1 Gości i 0 Anonimowych użytkowników)
0 Zarejestrowanych:

 



RSS Aktualny czas: 20.08.2025 - 00:06