Ankündigung

Einklappen
Keine Ankündigung bisher.

Config Klasse (Singleton Registry)

Einklappen

Neue Werbung 2019

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

  • Config Klasse (Singleton Registry)

    Hallo zusammen,

    ich bin dabei eine Config Klasse zu erstellen, die in meiner Anwendung wichtige Einstellungen verwalten soll.
    Da ich mich erst seit kurzem mit PHP/OOP beschäftige, würde ich gerne bereits jetzt eure Meinungen dazu hören, ob ich so weiter machen kann.

    Konkret geht es mir um folgende Fragen:

    - Gibt es in diesem Fall Gründe, die gegen ein Singleton- und/oder Registry-Pattern sprechen?
    Die beiden Pattern werden v.a. in Kombination immer öfter als schlecht dargestellt. Aber leider bleiben die Leute meistens eine Begründung schuldig.

    - Mehr Performance durch static? http://forum.adventure-php-framework...=5&t=337#p2881
    Wenn man sonst im Internet zu Performance-Unterschieden zwischen static und object sucht, ergeben die Tests meisten keinen oder kaum einen Unterschied. Weshalb macht das beim APF so einen großen Unterschied?


    Config.php
    PHP-Code:
    class Config
    {
        private 
    $CONFIG = array();
        private 
    $environment;
        private static 
    $instance;


        
    /**
         * getInstance - Creates a new Singleton instance
         */
        
    static public function getInstance() {
            if (!isset(
    self::$instance)) {
                
    self::$instance = new self();
            }
            return 
    self::$instance;
        }

        private function 
    __construct() {}

        private function 
    __clone() {}

        
    /**
         * Adds a key->value pair to the registry
         */
        
    public function set($key$value$namespace 'general') {
            
    $this->CONFIG[$namespace][$key] = $value;
        }

        
    /**
         * Retrieves a key->value pair from the registry
         */
        
    public function get($key$namespace 'general') {
            return 
    $this->CONFIG[$namespace][$key];
        }

        public function 
    loadIni($file) {
            
    $this->CONFIG parse_ini_file($filetrue);
        }

        public function 
    setEnvironment($env) {
            
    $this->environment $env;
        }

        public function 
    printConfig() {
            
    var_dump($this->CONFIG);
        }



    index.php
    PHP-Code:
    /**
     * Configuration Setup
     */
    include 'system/Config.php';

    $config Config::getInstance();
    $config->setEnvironment('DEVELOPMENT');
    $config->loadIni('/application/config/config.php');

    // Configuration Test
    $config->set('base_url''localhost');
    echo 
    $config->get('base_url'); // Output: localhost 
    Freundliche Grüße,
    John

  • #2
    Also rein von der Logik her ist das Registry Pattern besser geeignet (immerhin speicherst du ja was) (kann man auch abstract/static implementieren). Aufpassen solltest du aber bei loadIni() (überschreibt alle bisherigen Werte) und $namespace (Verwechslungsgefahr mit dem Namespace-Feature von PHP 5.3)

    Kommentar


    • #3
      Solche Threads gibt es hier andauernd:

      - http://www.php.de/php-einsteiger/686...ew-object.html

      Gibt es in diesem Fall Gründe, die gegen ein Singleton- und/oder Registry-Pattern sprechen?
      Jain. Sie verschleiern Abhängigkeiten, was ungünstig etwa für das Schreiben von Tests oder die Wiederverwendbarkeit des Codes sein kann. Singletons sind im Grunde globale Objekte.

      Keine Ahnung, was im APF-Thread getestet wurde. Hier ein anderer Benchmark:

      PHP-Code:
      <?php

      header
      ('content-type: text/plain');

          class 
      BenchmarkTest
          
      {
            protected 
      $test 'Hallo Welt';

            public function 
      getTest ()
            {
              return 
      $this->test;
            }
          }

          class 
      BenchmarkStaticTest
          
      {
            protected static 
      $test 'Hallo Welt';

            public static function 
      getTest ()
            {
              return 
      self::$test;
            }
          }

      function 
      a($n)
      {
          
      $o = new BenchmarkTest();    

          for (
      $i 0$i $n$i++) {

              
      $test1 $o->getTest();
              
      $test2 $o->getTest();
              
      $test3 $o->getTest();
          }
      }

      function 
      b($n)
      {
          for (
      $i 0$i $n$i++) {
              
      $test1 BenchmarkStaticTest::getTest();
              
      $test2 BenchmarkStaticTest::getTest();
              
      $test3 BenchmarkStaticTest::getTest();
          }
      }

      $n 100000;

      $start microtime(true);
      a($n);
      echo 
      '#1 ',  microtime(true) - $start"\n";

      $start microtime(true);
      b($n);
      echo 
      '#2 ',  microtime(true) - $start"\n";



      // Und noch mal umgekehrt

      $start microtime(true);
      b($n);
      echo 
      '#3 ',  microtime(true) - $start"\n";

      $start microtime(true);
      a($n);
      echo 
      '#4 ',  microtime(true) - $start"\n";
      Code:
      #1 0.255469083786
      #2 0.219408988953
      #3 0.221840143204
      #4 0.182775020599

      Kommentar


      • #4
        Besser als $namespace wäre $section. Section ist auch der geläufige Begriff für Abshcnitte innerhalb von Ini-Dateien (zumindest ist er mir als solches bekannt).

        Ob Singleton oder Registry ist eine Frage der Anforderung.

        Ob static oder nicht ebenfalls. Ich verwende derzeit eine Implementierung die eine komplette static-Registry nicht ermöglicht da ich keinen globalen Zugriff zulassen möchte.

        PHP-Code:
              $test2 Singleton::getInstance ('BenchmarkTest')->getTest (); 
        Das sieht mir nach einer Methode aus um generisch das Singleton zu holen. Jedenfalls ist nicht direkt in "Benchmarktest" eine getInstance() Methode vorhanden wie üblich. Das könnnt ggf. erklären wieso es so lange duaert bis das Objekt an Ort und Stelle geholt ist. Das da eine Klasse mit direkter statischer Implementierung ohne den ganzen Schnickschnack durm herum deutlich schneller ist, sollte logishc sein.

        Code:
        » SingletonDirect          2.9893109798 s
        » SingletonInstanceUnset   1.3286020756 s
        » SingletonInstanceNoUnset 1.2515478134 s
        » Static                   0.4081959724 s
        Diese Ergebnisse bekräftigen diese Aussage da im SingletonDirect Test für jeden Funktionsaufruf von getTest() das Objekt neu geholt wird. Test #2 und #3 haben Unterschiede im gewöhnlichem Toleranzbereich.
        "Alles im Universum funktioniert, wenn du nur weißt wie du es anwenden musst".

        Kommentar


        • #5
          Besten Dank für eure Hinweise, verwende nun $section und arbeite an einer eigenen array_merge Funktion (habe multidemensionale Arrays wegen Sections in meinen Ini-Dateien)
          Auf das Singleton und das Registry Pattern möchte ich später nochmal zurück kommen.

          Hab aber kurz mal deinen Test @mermshaus laufen lassen, mit folgendem interessanten Ergebnis:
          Code:
          Object #1 0.24319982528687
          Static #1 0.56252098083496
          Static #2 0.50020503997803
          Object #2 0.24293899536133
          Object mehr als doppelt so schnell?
          Habe nichts am Test geändert.

          System: PHP Version 5.3.1 auf lokalem XAMPP.

          Kommentar


          • #6
            Zitat von JohnT Beitrag anzeigen
            Besten Dank für eure Hinweise, verwende nun $section und arbeite an einer eigenen array_merge Funktion
            Warum rbauchst du eine eigene array_merge Funktion? Auch Mehrdimensionale Arrays lassen sich zusammenfassen...
            "Alles im Universum funktioniert, wenn du nur weißt wie du es anwenden musst".

            Kommentar


            • #7
              Zitat von Dark Guardian Beitrag anzeigen
              Warum rbauchst du eine eigene array_merge Funktion? Auch Mehrdimensionale Arrays lassen sich zusammenfassen...
              Ein Config-Array schaut bei mir nach dem Parsen der INI-Datei z.B. so aus:
              Code:
              Config Object
              (
                  [CONFIG:Config:private] => Array
                      (
                          [general] => Array
                              (
                                  [general_var] => Not recommended
                              )
              
                          [production] => Array
                              (
                                  [base_url] => 
                                  [database.host] => localhost
                                  [database.username] => root
                                  [database.password] => 
                                  [database.name] => 
                              )
              
                          [development:production] => Array
                              (
                                  [database.name] => test
                              )
              
                      )
              
                  [environment:Config:private] => DEVELOPMENT
              )
              [general], [production] etc. sind Sections in der INI. Wenn ich nun eine zweite INI-Datei über array_merge() kombiniere, die zwar neue Einstellungen aber die gleichen Sections enthält, werden trotzdem alle Einstellungen einer Section überschrieben.
              Und array_merge_recursive() kombiniert Eigenschaften mit gleichem Namen zu einem neuen Array, statt sie einfach zu überschreiben.
              If the input arrays have the same string keys, then the values for these keys are merged together into an array [...]
              http://php.net/manual/en/function.ar...-recursive.php

              Im ZF gab es mal das gleiche Problem: http://zendframework.com/issues/browse/ZF-998

              Kommentar


              • #8
                Zitat von JohnT Beitrag anzeigen
                [general], [production] etc. sind Sections in der INI. Wenn ich nun eine zweite INI-Datei über array_merge() kombiniere, die zwar neue Einstellungen aber die gleichen Sections enthält, werden trotzdem alle Einstellungen einer Section überschrieben.
                Und array_merge_recursive() kombiniert Eigenschaften mit gleichem Namen zu einem neuen Array, statt sie einfach zu überschreiben.
                Dann reichen die nativen Funktionen ja aus.

                Bzw. anders gesagt: rein technisch gesehen wäre es doch sowieso sinnfrei 2 Configs zu laden bei der sich Einstellungen überschrieben können. Da wäre es eher angebracht eine neue Objektinstanz der Klasse Config zu bilden.

                Oder du übergibst an array_merge als erstes die neuen Config Werte und als zweites die alten, dann überschreiben die alten die neuen, falls es doppelte gibt.
                "Alles im Universum funktioniert, wenn du nur weißt wie du es anwenden musst".

                Kommentar


                • #9
                  Zitat von Dark Guardian Beitrag anzeigen
                  Dann reichen die nativen Funktionen ja aus.
                  Leider nicht. Schau mal folgenden Test an:
                  PHP-Code:
                  $original_array = array(
                      
                  'id' => 1,
                      
                  'general' => array(
                          
                  'some_var' => 'Something',
                          
                  'override' => 'This is old content',
                      )
                  );
                  $new_array = array(
                      
                  'id' => 2,
                      
                  'general' => array(
                          
                  'override' => 'This is new content',
                      ),
                      
                  'new_section' => array(
                          
                  'some_var' => 'Something',
                          
                  'new_var' => 'New section content',
                      )
                  ); 
                  Ausgabe mit array_merge($original_array, $new_array):
                  PHP-Code:
                  Array
                  (
                      [
                  id] => 2
                      
                  [general] => Array
                          (
                              [
                  override] => This is new content
                          
                  )
                      [
                  new_section] => Array
                          (
                              [
                  some_var] => Something
                              
                  [new_var] => New section content
                          
                  )
                  )
                  // Komplette Section(s) werden überschrieben: [general] => some_var fehlt 
                  Ausgabe mit array_merge_recursive($original_array, $new_array):
                  PHP-Code:
                  Array
                  (
                      [
                  id] => Array
                          (
                              [
                  0] => 1
                              
                  [1] => 2
                          
                  )
                      [
                  general] => Array
                          (
                              [
                  some_var] => Something
                              
                  [override] => Array
                                  (
                                      [
                  0] => This is old content
                                      
                  [1] => This is new content
                                  
                  )

                          )
                      [
                  new_section] => Array
                          (
                              [
                  some_var] => Something
                              
                  [new_var] => New section content
                          
                  )
                  )
                  // Eigenschaften mit gleichem Namen werden zu neuem Array zusammengeführt 

                  Zitat von Dark Guardian Beitrag anzeigen
                  Bzw. anders gesagt: rein technisch gesehen wäre es doch sowieso sinnfrei 2 Configs zu laden bei der sich Einstellungen überschrieben können.
                  Was natürlich auch wieder stimmt. Aber es wäre zumindest möglich...

                  Aber wir schweifen ab

                  Kommentar


                  • #10
                    Zitat von Dark Guardian Beitrag anzeigen
                    Ich verwende derzeit eine Implementierung die eine komplette static-Registry nicht ermöglicht da ich keinen globalen Zugriff zulassen möchte.
                    Aber wie erfolgt dann dein Zugriff auf die Eigenschaften? Kannst du vielleicht ein bisschen Code deiner Registry und den Zugriff darauf posten, wäre super.

                    Kommentar


                    • #11
                      Zitat von JohnT Beitrag anzeigen
                      Aber wie erfolgt dann dein Zugriff auf die Eigenschaften? Kannst du vielleicht ein bisschen Code deiner Registry und den Zugriff darauf posten, wäre super.
                      Meine Registry ist ein gewöhnliches Objekt welches als Membervariable inh einem Systemobjekt eingebettet vorliegt.

                      Der Hintergrund ist das ich strukturiert Daten "irgendwo" ablegen können möchte, jedoch den Zugriff beschränken will.

                      Als Beispiel besitzt die Systemklasse eine Methode um Objekte für Konfigurationsparameter zu erzeugen. Diese werden zeitgleich in der Registry abgelegt und bei einjer erneuten Anforderung der gleichen Konfigurationsdatei wird das gleiche Objekt zurückgegeben. So habe ich die gleiche Funktionalität wie bei einem Singleton.

                      Andersherum, wenn ich nun ein Modul habe welches zwingend eine zweite Instanz der gleichen Konfigurationsdatei benötigt (z.B. um unmodifizierte Werte zu erhalten wie sie in der Datei vorliegen) bleibt der Aufruf über den new-Operator möglich. Bei einem Singleton wäre dies nicht möglich bzw. ich müsste ggf. bereits gemachte Änderungen an dem Objekt mit alten Daten überschreiben.

                      Und meine Klassen welche über das Systemobjekt erzeugt und gespeichert werden bleiben von meiner Registry Implementierung unabhängig. Ich könnte beispielsweiße die Registry static hinterlegen und in den Konstruktoren meiner Objekte den Eintrag vornehmen - aber diese wären dann alle explizit von der Registry Klasse abhängig was unschön ist.

                      Du siehst... die Implementierung ist sehr speziell und von dem gewöhnlichem Registry Konzept abweichend. Aber es erfüllt noch am besten meine Anforderungen an die Flexibilität.

                      Was die array_merge Implementierung angeht hast du Recht.

                      PHP-Code:
                      var_dump(array_merge($new_array$original_array)); 
                      Es funktioniert mit neuen Sections, aber nicht mit neuen Werten in bestehenden Sections.
                      "Alles im Universum funktioniert, wenn du nur weißt wie du es anwenden musst".

                      Kommentar


                      • #12
                        Zitat von Dark Guardian Beitrag anzeigen
                        Du siehst... die Implementierung ist sehr speziell und von dem gewöhnlichem Registry Konzept abweichend. Aber es erfüllt noch am besten meine Anforderungen an die Flexibilität.
                        Danke für die Ausführungen, ich denke ich verstehe. Das ganze entspricht der Factory Method, wobei deine Systemklasse die Factory ist, oder?

                        Kommentar


                        • #13
                          Zitat von JohnT Beitrag anzeigen
                          Danke für die Ausführungen, ich denke ich verstehe. Das ganze entspricht der Factory Method, wobei deine Systemklasse die Factory ist, oder?
                          Ja das Factory-Pattern ist hier wohl das Zutreffenste und eben gepaart mit einer Registry
                          "Alles im Universum funktioniert, wenn du nur weißt wie du es anwenden musst".

                          Kommentar

                          Lädt...
                          X