Ankündigung

Einklappen
Keine Ankündigung bisher.

Overloading und (mehrdimensionale) Arrays

Einklappen

Neue Werbung 2019

Einklappen
X
  • Filter
  • Zeit
  • Anzeigen
Alles löschen
neue Beiträge

  • Overloading und (mehrdimensionale) Arrays

    Hallo zusammen,

    ich nutze für ein Projekt das Registry Pattern in Kombination mit dem Singleton Pattern, um Variablen persistent abzulegen.
    Dazu ein Ausschnitt aus der entsprechenden Klasse SessionRegistry:
    PHP-Code:
    class SessionRegistry
    {
        protected static 
    $instance null;

        protected function 
    __construct()
        {
            
    session_start();
            if(!isset(
    $_SESSION['__registry']))
            {
                
    $_SESSION['__registry'] = array();
            }
        }

        private function 
    __clone()
        {
        }
        
        public static function 
    getInstance()
        {
            if(
    self::$instance === null)
            {
                
    self::$instance = new SessionRegistry();
            }
            return 
    self::$instance;
        }

        public function 
    __set($name$value)
        {
            
    $_SESSION['__registry'][$name] = $value;
        }
        
        public function 
    __get($name)
        {
            if(isset(
    $_SESSION['__registry'][$name]))
            {
                return 
    $_SESSION['__registry'][$name];            
            }
            return 
    null;
        }

        public function 
    __isset($name)
        {
            return isset(
    $_SESSION['__registry'][$name]);
        }
        
        public function 
    __unset($name)
        {
            unset(
    $_SESSION['__registry'][$name]);
        }

    Um von einer anderen Klasse auf die SessionRegistry zuzugreifen verwende ich im Konstruktor der Klasse
    PHP-Code:
    $this->SessionRegistry SessionRegistry::getInstance(); 
    und im Code dann
    PHP-Code:
    $this->SessionRegistry->foo $bar 
    bzw. dementsprechend auch
    PHP-Code:
    $foo $this->SessionRegistry->bar 
    Mein Problem taucht nun beim schreibenden Zugriff auf (mehrdimensionale) Arrays auf
    PHP-Code:
    // Aufruf
    $this->SessionRegistry->foo['bar'] = $baz
    // ergibt
    $_SESSION['__registry'][foo['bar']] = $baz
    was semantisch Humbug darstellt und in der Registry unter Schlüssel "foo['bar']" das angegebene "$baz" ablegt.

    Gibt es hierfür eine elegante Lösung? Leider stehe ich gerade auf dem Schlauch...
    Unelegant wäre es das komplette (mehrdimensionale) Array temporär auszulesen, zu modifizieren und wieder komplett zurückzuschreiben a la
    PHP-Code:
    $temp $this->SessionRegistry->foo;
    $temp['bar'] = $baz;
    $this->SessionRegistry->foo $temp 
    Grüßung und Bedankung
    tr8000


  • #2
    [quote=tr8000;532986]
    PHP-Code:
    $_SESSION['__registry'][foo['bar']] = $baz
    Also das da ist schon ma syntaktisch schlecht, würde notices werfen, weil es kein Konstante ist

    Du solltest das ganze mal so probieren:
    PHP-Code:
    $this->SessionRegistry->foo->bar $baz
    Nachtrag:
    Hmm wenn ich bissl drüber nachdenke und mich nicht irre, wird das glaube ich doch nicht gehen, da du in der Klasse ein Zuweisung in der Art machst: $session[$name]
    Du könntest versuchen mit der evil eval() funktion zu arbeiten, aber davon würde ich eher abraten.
    Oder du bastelst dir einen Iterator, der dann für dich an die richtige Stelle das Zeug rein schreibt
    "My software never has bugs, it just develops random features."
    "Real programmers don't comment. If it was hard to write, it should be hard to understand!"

    Kommentar


    • #3
      Zitat von tr8000 Beitrag anzeigen
      Mein Problem taucht nun beim schreibenden Zugriff auf (mehrdimensionale) Arrays auf
      PHP-Code:
      // Aufruf
      $this->SessionRegistry->foo['bar'] = $baz
      // ergibt
      $_SESSION['__registry'][foo['bar']] = $baz
      was semantisch Humbug darstellt und in der Registry unter Schlüssel "foo['bar']" das angegebene "$baz" ablegt.

      Gibt es hierfür eine elegante Lösung? Leider stehe ich gerade auf dem Schlauch...
      analog zur Definition eines Arrays:
      PHP-Code:
      $this->SessionRegistry->foo = array("bar" => $baz); 
      Ich sehe für die Anwendung der Klasse (also das trifft eigentlich jede Sessionklasse) noch ein kleines Problem … am Anfang des Skriptes muß die Session initialisiert werden, um die "header already sent" Warnung zu vermeiden (das darf dann natürlich nicht mit dem Klassenkonstruktor kollidieren, eine bereits initialisierte Session darf nicht nocheinmal gestartet werden).

      PS. IMHO, es reicht für eine Sessionklasse nach dem Singletonprinzip eine x-beliebige Triggervariable zu speichern. Dazu ist noch nicht einmal das Singleton Pattern notwendig, lediglich Mutatormethoden für diese Variable.

      Kommentar


      • #4
        Was hier passiert, ist dass mit __get das Array $_SESSION['__registry']['foo'] als Kopie (return by value) zurückgegeben und dann modifiziert wird. Eine direkte Modifikation des Arrays ist so nicht möglich, es sei denn man bekäme es hin, __get mit return by reference arbeiten zu lassen, was IIRC nicht möglich ist.

        Ein Workaround aus dem PHP-Manual (PHP: Magic Methods - Manual 1. Kommentar):

        Properties that are Arrays: attempting to set array values like "$a->test_array[] = 'asdf';" from outside this object will result in an "Indirect modification of overloaded property" notice and the operation completely ignored. You can't use '[]' for array value assignment in this context (with the exception only if you made __get() return by reference, in which case, it would work fine and bypass the __set() method altogether). You can work around this doing something like unioning the array instead:

        PHP-Code:
        <?php

        $a
        ->test_array[] = 'asdf'// notice given and ignored unless __get() was declared to return by reference
        $a->test_array += array(=> 'asdf'); // to add a key/value
        $a->test_array = array("key" => 'asdf') + $a->test_array// to overwrite a  key/value.

        ?>
        @fschmengler - @fschmengler - @schmengler
        PHP Blog - Magento Entwicklung - CSS Ribbon Generator

        Kommentar


        • #5
          In deinem Fall würde sich ein ArrayAccess lohnen (und die Probleme lösen ):

          PHP-Code:
          <?php

          use \ArrayAccess;
          use \
          Exception;

          class 
          SessionRegistry implements ArrayAccess
          {
              protected static 
          $instance null;
              
              protected function 
          __construct()
              {
                  if(
          header_sent())
                      throw new 
          Exception('zu spät ;)');
                      
                  if(!
          defined('SID') || empty(SID))
                      
          session_start();
                      
                  if(!
          is_array($_SESSION['__registry']))
                      
          $_SESSION['__registry'] = array();
              } 
              
              public static function 
          getInstance()
              {
                  if(
          self::$instance === null)
                      
          self::$instance = new self();
                      
                  return 
          self::$_instance;
              } 
              
              
          /**
              * variable zurückgeben
              *
              * @param    scalar      $name
              * @return   mixed
              */
              
          public function offsetGet($name)
              {
                  return isset(
          $_SESSION['__registry'][$name]) 
                      ? 
          $_SESSION['__registry'][$name]
                      : 
          null;
              }
              
              
          /**
              * variable in session aufnehmen oder überschreiben
              *
              * @param    scalar      $name
              * @param    mixed       $value
              * @return   mixed
              */
              
          public function offsetSet($name$value)
              {
                  return (
          $_SESSION['__registry'][$name] = $value);
              }
              
              
          /**
              * prüfen ob variable in session existiert
              *
              * @param    scalar      $name
              * @return   boolean
              */
              
          public function offsetExists($name)
              {
                  return isset(
          $_SESSION['__registry'][$name]);
              }
              
              
          /**
              * variable aus session entfernen
              *
              * @param    scalar      $name
              * @void
              */
              
          public function offsetUnset($name)
              {
                  unset(
          $_SESSION['__registry'][$name]);
              }
          }
          PHP-Code:
          $session SessionRegistry::getInstance();
          $session['foo'] = array();
          $session['foo']['bar'] = 1;

          print_r($_SESSION['__registry']) // Array ( [foo] => Array ( [bar] => 1 ) ) 

          Kommentar


          • #6
            Zitat von Murdoc Beitrag anzeigen
            In deinem Fall würde sich ein ArrayAccess lohnen
            falls die Klasse keine weiteren Methoden haben sollte, könnte man auch wieder zu $_SESSION zurückkehren …

            Kommentar


            • #7
              Bis auf den Unterschied, dass er mit der Klasse eigene setter und getter für $_SESSION['__registry'] hat. Aber da macht seine Registry-Klasse genauso wenig Sinn, bis auf "->" statt "[]".

              Nebenbei sei noch gesagt, dass man in $_SESSION auch Indexe anlegen kann, auf die man nicht über "->" zugreifen kann.
              PHP-Code:
              // $foo->ein-ungültiger-index
              $foo->__get('ein-ungültiger-index'); 
              Rein von der Performance her wäre ein direkter Zugriff auf $_SESSION eh besser, oder eben mit einem ArrayObject aus der SPL.

              Kommentar


              • #8
                Ich kann die Absicht schon verstehen, es geht quasi um ein Namespacing für bestimmte Variablenbereiche. Das praktische ist, dass man das Zugriffsobjekt via Type Hinting einfordern kann (bzw. die Schnittstelle sicherstellen).

                Trotzdem halten sich die Vorteile gegenüber $_SESSION sehr in Grenzen.
                --

                „Emoticons machen einen Beitrag etwas freundlicher. Deine wirken zwar fachlich richtig sein, aber meist ziemlich uninteressant.
                Wenn man nur Text sieht, haben viele junge Entwickler keine interesse, diese stumpfen Texte zu lesen.“


                --

                Kommentar


                • #9
                  [obsolet]

                  Kommentar


                  • #10
                    Kleines Update. Ich benutze seit längerem ein ähnliches Konstrukt (sozusagen „namespaced“ assoziierte Session-Teilstrukturen), um definierte Persistenzobjekte an Klassen übergeben zu können.
                    Nach einigen negativen Erfahrungen in der Vergangenheit hatte ich mich bis dato auf 1-dimensionale Strukturen beschränkt. Zumindest objektseitig. Also:

                    PHP-Code:
                    $container = new PersObject ('namespaceMyClass');
                    $container->store ('foo' 42);
                    $myClass = new myClass ($container); 
                    Letztens hatte ich Iterator or IteratorAggregate? - Fabien Potencier gelesen und daraufhin das Objekt damit ausgerüstet. Unproblematisch. Beschränkt sich aber auch nur auf foreach. Eben dachte ich - bauste ArrayAccess auch noch ein. Auch das kein Problem.

                    PHP-Code:
                    echo $container['foo'];
                    $container['bar'] = array (2); 
                    Und dann lief ich wieder in die alte Geschichte mit mehrdim. Datenstrukturen:

                    Jeder Set-Versuch der Art
                    PHP-Code:
                    $container['bar'][2] = 3
                    resultiert nämlich schön in:
                    Code:
                    Notice: Indirect modification of overloaded element of ... has no effect ... on line 28
                    Die Bugreports dazu ergehen sich in Geschwafel und Ausreden, warum das so gewollt ist etc. Mein Fazit - solch ein Verhalten ist unlogisch und ArrayAccess praktisch nicht nutzbar. Wer will sich schon auf 1-dimensionale Arrays zwangsbeschränken. Also baue ich den Schrumms gleich wieder aus. Dann bleibts wenigstens konsistent. Den Luxus eines superglobalen Arrays wird man mit Objekten wohl nicht erreichen.
                    --

                    „Emoticons machen einen Beitrag etwas freundlicher. Deine wirken zwar fachlich richtig sein, aber meist ziemlich uninteressant.
                    Wenn man nur Text sieht, haben viele junge Entwickler keine interesse, diese stumpfen Texte zu lesen.“


                    --

                    Kommentar


                    • #11
                      Zitat von nikosch Beitrag anzeigen
                      Den Luxus eines superglobalen Arrays wird man mit Objekten wohl nicht erreichen.
                      ich glaube auch nicht, daß Objekte dafür gedacht sind, ansonsten wären die SuperGlobals ja auch überflüssig.

                      Kommentar


                      • #12
                        Nennen wirs anders - den Luxus eines mehrdimensionalen Arrayzugriffs wird man mit einem Objekt wohl nicht erreichen.
                        --

                        „Emoticons machen einen Beitrag etwas freundlicher. Deine wirken zwar fachlich richtig sein, aber meist ziemlich uninteressant.
                        Wenn man nur Text sieht, haben viele junge Entwickler keine interesse, diese stumpfen Texte zu lesen.“


                        --

                        Kommentar


                        • #13
                          darauf können wir uns einigen.

                          Kommentar

                          Lädt...
                          X