MB: PHP Variablen übergabe in welcher Form sinnvoll?

Hallo Community,

wo ist es sinnvoll:

$var = "Blabla $variable";

oder

$var = 'Blabla ' .$variable;

oder

public function __construct(..., $variable, ...) { ... }
$var = "Blabla {$this->variable}

Es kam auch schon vor das ich {$this->var_1}{$this->var_2}{$this->var_3} (z.B.: für die dynamische Pfadangaben) verwende musste.

Struktur, Platzsparung usw. sind mir wichtig deswegen meine Frage.

Grüße MB

  1. Tach!

    wo ist es sinnvoll:

    $var = "Blabla $variable";
    

    oder

    $var = 'Blabla ' .$variable;
    

    oder

    public function __construct(..., $variable, ...) { ... }
    $var = "Blabla {$this->variable}
    

    Ein weiteres "oder" geht mit sprintf().

    Die Antwort ist, es gibt kein generelles "sinnvoll". Suche für den speziellen Anwendungsfall Argumente für oder gegen bestimmte Vorgehensweisen und entscheide dann nach der Abwägung.

    dedlfix.

    1. Hallo dedlfix,

      Die Antwort ist, es gibt kein generelles "sinnvoll". Suche für den speziellen Anwendungsfall Argumente für oder gegen bestimmte Vorgehensweisen und entscheide dann nach der Abwägung.

      Also nehme ich an das es kein geheimes erfolgsrezept gibt. Wollte das abklären. Danke Dir.

      Gruß MB

  2. Moin!

    Nicht sinnvoll ist aber:

    echo "Blabla $variable";
    
    echo 'Blabla ' .$variable;
    

    sondern:

    echo 'Blabla ', $variable;
    

    Jörg Reinholz

    1. Moin Jörg,

      echo 'Blabla ', $variable;
      

      das habe ich bei dir gesehen. Mir ist das bisher nie untergekommen. welchen Grund hat es das man das mit komma trennt und mit einem hochkomma und nicht zwei hochkommata. Und warum n komma und kein Punkt?

      Ist mir schleiherhaft.

      Grüße MB.

      1. Moin!

        das habe ich bei dir gesehen. Mir ist das bisher nie untergekommen. welchen Grund hat es das man das mit komma trennt und mit einem hochkomma und nicht zwei hochkommata. Und warum n komma und kein Punkt?

        'dies' statt "das"

        • Inherhalb von 'hochkomma' untersucht PHP nicht, ob es darin Variablen zu ersetzen gibt. 'Hochkomma' statt "doublequota" ist also schneller.
        • echo kann selbst die Ausgaben kombinieren (Liste mit Komma). Es macht also keinen Sinn und verursacht unsinnig Kosten bezüglich Speicher und Rechenzeit wenn man erst den String zusammenzubaut und dann im selben Schritt ausgibt.

        Das mögen nicht signifikante Verbesserungen sein, aber ein belasteter Webserver führt sowas am Tag auch ein paar Millionen oder gar Milliarden mal aus.

        Jörg Reinholz

          • Inherhalb von 'hochkomma' untersucht PHP nicht, ob es darin Variablen zu ersetzen gibt. 'Hochkomma' statt "doublequota" ist also schneller.
          • echo kann selbst die Ausgaben kombinieren (Liste mit Komma). Es macht also keinen Sinn und verursacht unsinnig Kosten bezüglich Speicher und Rechenzeit wenn man erst den String zusammenzubaut und dann im selben Schritt ausgibt.

          Die Rückschlüsse auf die Performance sind heute nicht mehr gültig (falls sie das überhaupt je waren). Auf http://www.phpbench.com/ gibt es ein paar Benchmarks die diesem Mythos zumindest die Luft aus den Segeln nehmen sollten. Zudem ist es sehr ineffektiv, von vornerein zu versuchen effizienten Quelltext zu schreiben, weil man die Flaschenhälse nur sehr schwer bis gar nicht vorausahnen kann. Ihre hackermäßige Natur führt zudem häufig zu schlechterer Lesbarkeit und Wartbarkeit der Programme. Wobei ich diesen letzten Punkt hier nicht sehe.

          1. Hallo,

            Zudem ist es sehr ineffektiv, von vornerein zu versuchen effizienten Quelltext zu schreiben, weil man die Flaschenhälse nur sehr schwer bis gar nicht vorausahnen kann.

            naja, man kann die wirklich relevanten Flaschenhälse zwar oft nicht vorausahnen, aber doch oft Dinge vermeiden, die schon allein nach gesundem Menschenverstand schlecht für die Performance sein müssen. Das sind dann zwar oft Beiträge, die einzeln betrachtet im Rauschen untergehen, aber das läppert sich auch. Zumal ...

            Ihre hackermäßige Natur führt zudem häufig zu schlechterer Lesbarkeit und Wartbarkeit der Programme.

            ... ich in genau diesem Punkt entschieden widerspreche. Nach meiner Erfahrung ist Programmcode, der bewusst auf optimale Performance getrimmt ist, meistens sogar besser lesbar und verständlich, weil er "straightforward" ist, weil er ohne Umschweife auf den Punkt kommt.

            Allerdings: Dieser Eindruck von mir fußt vor allem auf C-Code. Inwiefern das auch für PHP gilt, kann ich nicht sagen, weil ich da noch nicht so sehr darauf geachtet habe.

            So long,
             Martin

            1. Ihre hackermäßige Natur führt zudem häufig zu schlechterer Lesbarkeit und Wartbarkeit der Programme.

              ... ich in genau diesem Punkt entschieden widerspreche. Nach meiner Erfahrung ist Programmcode, der bewusst auf optimale Performance getrimmt ist, meistens sogar besser lesbar und verständlich, weil er "straightforward" ist, weil er ohne Umschweife auf den Punkt kommt.

              Ein Hack ist für mich ein programmiertechnischer Trick, der nicht auf Wissen über das zu lösende Problem selbst beruht, sondern auf zusätzlichem Wissen über die Programmiersprache oder Ausführungsumgebung. Beispiele dafür sind Wissen über Speicherlayout, Callstack-Size, Strictness etc. Idealtypischerweise würde ich beispielsweise eine Funktion zur Berechnung der Fibonacci-Zahlen auf rekursive Weise implementieren, und damit meinen Programmcode sehr nahe an der mathematischen Definition ausrichten. Allerdings weiß ich, dass JavaScript noch keine Unterstützung für endrekursive Funktionsaufrufe hat und ich somit schnell einen Stackoverflow produzieren könnte. Um dem Stackoverflow zu entfliehen setze ich also stattdessen auf eine prozedurale Implementierung oder auf Trampolining. Damit obfuskiere ich aber die Intention meines ursprünglichen Programmtextes, weil dieser nun haufenweise Quelltext enthält, der qualitativ nichts zur Lösung des Problems beiträgt. Ich entschuldige mich für das synthetische Beispiel, aber ich denke damit kann ich meine Definition eines Hacks sehr gut veranschaulichen.

              Diese Charakteristik ist es auch, die C den Ruf eingebracht hat sehr schnell und resourcensparend zu sein. C setzt exzessiv auf die manuellen Optimierungsfähigkeiten der Programmierer und bietet ihm dafür sehr viele lowlevel Routinen an, um bspw. direkten Einfluss auf das Speicherlayout nehmen zu können. Per se ist C nämlich eine eher langsame Sprache, zumindest in dem Sinne, dass der Compiler vergleichsweise wenig Möglichkeiten hat automatisiert Optimierungspotenzial zu erkennen und auszuschöpfen.

              1. Hallo,

                Ihre hackermäßige Natur führt zudem häufig zu schlechterer Lesbarkeit und Wartbarkeit der Programme.

                ... ich in genau diesem Punkt entschieden widerspreche. Nach meiner Erfahrung ist Programmcode, der bewusst auf optimale Performance getrimmt ist, meistens sogar besser lesbar und verständlich, weil er "straightforward" ist, weil er ohne Umschweife auf den Punkt kommt.

                Ein Hack ist für mich ...

                Moment, da reden wir von unterschiedlichen Dingen. Ich stimme dir zu, was die Charakterisierung von Hacks angeht. Aber unter "ihre hackermäßige Natur" verstehe ich etwas ganz anderes - nämlich eine sehr zielstrebige, kompakte und meist schlecht bis gar nicht dokumentierte Art zu programmieren.

                Diese Charakteristik ist es auch, die C den Ruf eingebracht hat sehr schnell und resourcensparend zu sein. C setzt exzessiv auf die manuellen Optimierungsfähigkeiten der Programmierer und bietet ihm dafür sehr viele lowlevel Routinen an, um bspw. direkten Einfluss auf das Speicherlayout nehmen zu können.

                Stimmt, aber all das ist transparent und klar dokumentiert und damit weit vom Begriff "Hack" entfernt.

                Per se ist C nämlich eine eher langsame Sprache, zumindest in dem Sinne, dass der Compiler vergleichsweise wenig Möglichkeiten hat automatisiert Optimierungspotenzial zu erkennen und auszuschöpfen.

                Einige Compiler können das allerdings beeindruckend gut. Ich habe mir vor 15..20 Jahren oft beim Debuggen den Assembler-Code angesehen, den damals der Borland-C-Compiler produziert hat, und war gelegentlich beeindruckt von den Optimierungen, die der an meinem Code noch vorgenommen hat.

                So long,
                 Martin

                1. Hallo,

                  Ihre hackermäßige Natur führt zudem häufig zu schlechterer Lesbarkeit und Wartbarkeit der Programme.

                  ... ich in genau diesem Punkt entschieden widerspreche. Nach meiner Erfahrung ist Programmcode, der bewusst auf optimale Performance getrimmt ist, meistens sogar besser lesbar und verständlich, weil er "straightforward" ist, weil er ohne Umschweife auf den Punkt kommt.

                  Ein Hack ist für mich ...

                  Moment, da reden wir von unterschiedlichen Dingen. Ich stimme dir zu, was die Charakterisierung von Hacks angeht. Aber unter "ihre hackermäßige Natur" verstehe ich etwas ganz anderes - nämlich eine sehr zielstrebige, kompakte und meist schlecht bis gar nicht dokumentierte Art zu programmieren.

                  Mir ist leider keine bessere Eindeutschung des englischen Adjektivs "hackish" eingefallen, vielleicht hätte ich es einfach benutzen sollen. Performance-Tweaks die ich im Voraus auf Verdacht einbaue sind meistens eben sehr "hackish", in dem zuvor genannten Sinne, dass sie von einer idealisierten Implementierung abrücken und einen Aspekt der Programmiersprache ausnutzen, der hoffentlich zu erhöhter Performance führt.

                  Diese Charakteristik ist es auch, die C den Ruf eingebracht hat sehr schnell und resourcensparend zu sein. C setzt exzessiv auf die manuellen Optimierungsfähigkeiten der Programmierer und bietet ihm dafür sehr viele lowlevel Routinen an, um bspw. direkten Einfluss auf das Speicherlayout nehmen zu können.

                  Stimmt, aber all das ist transparent und klar dokumentiert und damit weit vom Begriff "Hack" entfernt.

                  Hacks sind sogar meistens sehr gut dokumentiert, anders wäre ihre Einsatz häufig gar nicht zu rechtfertigen. Das sehe ich deshalb nicht als Auschlusskriterium.

                  Per se ist C nämlich eine eher langsame Sprache, zumindest in dem Sinne, dass der Compiler vergleichsweise wenig Möglichkeiten hat automatisiert Optimierungspotenzial zu erkennen und auszuschöpfen.

                  Einige Compiler können das allerdings beeindruckend gut. Ich habe mir vor 15..20 Jahren oft beim Debuggen den Assembler-Code angesehen, den damals der Borland-C-Compiler produziert hat, und war gelegentlich beeindruckt von den Optimierungen, die der an meinem Code noch vorgenommen hat.

                  Meine Relativierung bezog sich auf das theoretische Potenzial, dass den Compilern höherer aber eben auch restriktiverer Programmiersprachen innewohnt. Haskell hat zum Beispiel durch die Vermeidung von Nebenwirkungen sehr weit fortgeschrittene Möglichkeiten den Programmablauf zu variieren: Dadurch können sehr starke Parallelisierungseffekte erzielt werden oder Teilprogramme auf Verdacht schon vor ihrer Nutzung ausgewertet werden. Das ist allein aufgrund der Semantik von C in keinem vergleichbaren Maße möglich. Dafür geht ein Haskell-Programmierer einen starken Tradeoff zu Lasten der Vorhersehbarkeit der Performance seiner Programme ein, während ein C-Programmierer die Auswirkungen einzelner Programmabschnitte relativ einfach abschätzen kann. Und natürlich ist der C-Compiler einer der am weitesten entwickelten Compiler der Welt, der auch von einem starken ökonomischen Interesse voran getrieben wird. Ich habe den C-Compiler und die Optimierungsstrategien, die er implementiert, in keiner Weise herunterspielen wollen, weil ich sie im Detail ja auch gar nicht kenne. Ich habe vorrangig den Aspekt automatisierbarer Performanceoptimierung als Alternative zu manuellen Optimierungstechniken ins Spiel bringen wollen. Das ist mir nun hoffentlich besser gelungen.

          2. Moin!

            Die Rückschlüsse auf die Performance sind heute nicht mehr gültig (falls sie das überhaupt je waren). Auf http://www.phpbench.com/ gibt es ein paar Benchmarks die diesem Mythos zumindest die Luft aus den Segeln nehmen sollten.

            Tatsächlich!

            Ich habe mal selbst "gebenchmarkt". Die folgenden Ergebnisse mögen naturgemäß situationsbedingt leicht schwanken, sind aber von der Reihenfolge her reproduzierbar.

            Skript:

            <?php
            $a = 'aaaaaaa';
            $b = 'bbbbbbb';
            $c = 'ccccccc';
            $d = 'ddddddd';
            
            define('M', 1000000);
            define('NL', "\n");
            
            ob_start();
            $s = microtime(true);
            for ($i=0; $i<M; $i++) {
                echo $i, ' : ', $a, $b, $c, $d, NL;
            }
            ob_end_clean();
            echo 'Komma: ', ( microtime(true) - $s), 's', NL;
            
            ob_start();
            $s = microtime(true);
            for ($i=0; $i<M; $i++) {
                echo $i . ' : ' . $a . $b . $c . $d . NL;
            }
            ob_end_clean();
            echo 'Punkt: ', (microtime(true) - $s), 's', NL;
            
            ob_start();
            $s = microtime(true);
            for ($i=0; $i<M; $i++) {
                echo "$i : $a $b $c $d\n";
            }
            ob_end_clean();
            echo 'String:' , (microtime(true) - $s) , 's', NL;
            

            Tests:

            1. PHP 5.5.9-1ubuntu4.14 (cli) (built: Oct 28 2015 01:34:46)

            fastix@trainer:/tmp$ php test.php 
            Komma: 0.57300615310669s
            Punkt: 0.59544205665588s
            String:0.53846502304077s
            

            2. HipHop VM 3.11.1 (rel) (hhvm)

            fastix@trainer:/tmp$ hhvm test.php
            Komma: 0.33236718177795s
            Punkt: 0.21430087089539s
            String:0.26826691627502s
            

            3. PHP 7.0.3-3+deb.sury.org~trusty+1 (cli) ( NTS ) auf einem Raspberry 2b+
            Bitte beachten: Ein Armel ist definitiv langsamer als ein Intel oder AMD. Dafür zieht der aber auch nur ganz wenig Strom.

            trainer@home:/tmp$ php /tmp/test.php 
            Komma: 2.8800621032715s
            Punkt: 3.3124830722809s
            String:2.4350960254669s
            

            Ich bin tatsächlich überrascht, dass unter hhvm der concatenierte String $i . ' : ' . $a . $b . $c . $d . NL so schnell ist. Ganz überrascht hat mich dann php 5.5.9 und php7 mit dem schnellen "Stringbuilder" "$i : $a $b $c $d\n".

            Jörg Reinholz

      2. Hallo,

        echo 'Blabla ', $variable;
        

        lass mich der Reihe nach erklären:

        mit einem hochkomma und nicht zwei hochkommata

        Wird ein String in PHP mit "double quotes" geschrieben, dann werden Steuerzeichen interpretiert und Variablen-Ersetzungen vorgenommen. Strings in 'single quotes' werden nicht weiter interpretiert. Man erspart der CPU also ein bisschen unnötige Arbeit.

        Und warum n komma und kein Punkt?

        Weil die echo-Anweisung mehrere durch Komma getrennte Werte ausgeben kann. Wenn du die zwei Strings mit einem Punkt dazwischen notierst, werden sie erst zu einem String zusammengefügt und dann mit echo ausgegeben; mit dem Komma "spart" man sich das Zusammenbauen der beiden Strings zu einem.

        So long,
         Martin

      3. Tach!

        welchen Grund hat es das man das mit komma trennt und mit einem hochkomma und nicht zwei hochkommata. Und warum n komma und kein Punkt?

        Das PHP-Handbuch beschreibt auch die Anweisung echo. Der Punkt verknüpft zwei Strings (allgemeiner Stringverkettungsoperator), mit Komma trennt man mehrere Ausgabewerte, wenn man dem echo mehrere übergeben möchte.

        Eine Stringverkettung erstellt erst einen neuen String, der dann vom echo ausgegeben wird. Bei mehreren Parametern entfällt der Zwischenschritt.

        dedlfix.

  3. Immer wieder und nochmal: Trenne fest eingebaute Literale so weit wie möglich vom Programmcode. So heißt die Antwort auf die Frage nach der Art und Weise von Stringverkettung nicht Stringverkettung oder Listenkontext von echo sondern Templatesystem.

    Und die Antwort auf die Frage fest eingebauter Literale heißt Auslagern.

    1. nabend pl,

      Trenne fest eingebaute Literale so weit wie möglich vom Programmcode

      sorry. "fest eingebaute Literale" verstehe ich einen "Iterator". oder foreach-Schleifen? Ich nehme an du verwendest Begriffe von Methoden und Modellen die ich möglicherweise angewand habe, den Begriff aber nicht kenne.

      Klär mich auf.

      Grüße MB

      1. Hallo,

        Trenne fest eingebaute Literale so weit wie möglich vom Programmcode

        sorry. "fest eingebaute Literale" verstehe ich einen "Iterator". oder foreach-Schleifen?

        nein, ganz andere Baustelle. "Literal" ist bei manchen Software-Designern ein anderer Ausdruck für eine Konstante. Beispiel:

        $url = 'http://example.org/some/bogus/data';
        

        Hier wäre der explizit als Konstante ausgeschriebene String 'http://example.org/some/bogus/data' ein Literal. Und solche Konstanten möchte man oft vom eigentlichen Programmcode trennen, wenn es nicht um Konstanten geht, die unmittelbar mit dem Code an sich zu tun haben.

        So long,
         Martin

        1. aaah, ok. Besten Dank.

          Nebenbei: Eine $varible an oberster Code-Ebene, wenn ichs richtig verstanden habe, ist Global. Komstanten muss man doch mit define( 'VARIABLE', 'http://...' ); angeben damit sie überall verfügbar sind, oder?

          Grüße MB

          1. Moin!

            aaah, ok. Besten Dank.

            Nebenbei: Eine $varible an oberster Code-Ebene, wenn ichs richtig verstanden habe, ist Global. Komstanten muss man doch mit define( 'VARIABLE', 'http://...' ); angeben damit sie überall verfügbar sind, oder?

            Ja, und beides will man vermeiden, weil man seinen Code unabhängig vom Vorhandensein globaler Effekte/Werte konstruieren will.

            Dein Code sollte sich nicht darauf verlassen, dass irgendeine globale Konstante definiert ist oder eine globale Variable existiert und einen bestimmten nutzbaren Wert hat. Denn es gibt nur zwei Szenarien:

            1. Entweder ist dein Code auch als einziger verantwortlich für das Erstellen der Variablen oder Konstante. Dann kann man sie ganz simpel als Klassenkonstante oder private Property in die Klasse/Instanz ziehen. Das reduziert die Abhängigkeit von externen Zuständen und erleichtert das Testen.
            2. Oder externer Code stellt die Konstenten oder Variablen her. Dann hast du mindestens ein nicht offensichtliches Reihenfolgeproblem, d.h. irgendwer muss wissen, in welcher Reihenfolge Code auszuführen ist. Man kann ihn nicht mehr beliebig umstrukturieren, die Wartbarkeit leidet, ebenso die Testbarkeit.

            Mit anderen Worten: Es ist zwar nicht das Ende der Welt, wird aber langfristig mit Sicherheit weh tun.

            Grüße Sven

          2. Moin!

            Nebenbei: Eine $varible an oberster Code-Ebene, wenn ichs richtig verstanden habe, ist Global.

            Äh. Nein. Variablen sind in PHP immer local.

            Zu globalen Variablen hast Du neulich erst was von mir gelesen.

            Komstanten muss man doch mit define( 'VARIABLE', 'http://...' ); angeben damit sie überall verfügbar sind, oder?

            Damit baut man diese zusammen und Konstanten sind global.

            Jörg Reinholz

            1. Moin!

              Nebenbei: Eine $varible an oberster Code-Ebene, wenn ichs richtig verstanden habe, ist Global. Äh. Nein. Variablen sind in PHP immer local.

              Das ist schlicht falsch.

              Zu globalen Variablen hast Du neulich erst was von mir gelesen.

              Dieser Code dort erklärt nichts und benutzt die globale Variable über das $GLOBALS-Array - das ist nur EINE Variante, an globale Variablen heranzukommen, die andere wäre mit "global $varname" in der Funktion. Beide Varianten sind gleich schlecht im Hinblick auf die Tatsache, dass globale Variablen benutzt werden.

              Komstanten muss man doch mit define( 'VARIABLE', 'http://...' ); angeben damit sie überall verfügbar sind, oder?

              Damit baut man diese zusammen und Konstanten sind global.

              ... in dem Sinne, dass man sie ohne Zusatzaktion direkt verwenden kann. Globale Konstanten sollte man trotzdem eher vermeiden.

              Grüße Sven

              1. Moin!

                Beide Varianten sind gleich schlecht im Hinblick auf die Tatsache, dass globale Variablen

                Die Syntax mit global habe ich angeblich bereits vergessen, da ich diese niemals benutze.

                Globale Konstanten sollte man trotzdem eher vermeiden.

                Nana. Also $GLOBAL['config']['sonstwas'] nicht. Konstanten nicht ... wie will denn der Herr eine Konfiguration an seine Funktionen übergeben? Soll etwa jedes Objekt die Konfigurationsdatei lesen und was machst Du bei einem, sagen wir mal schlankem, funktionalen 100-Zeiler? Den mit Objekten auf 300 Zeilen aufblasen?

                Jörg Reinholz

                1. Tach!

                  Globale Konstanten sollte man trotzdem eher vermeiden.

                  Nana. Also $GLOBAL['config']['sonstwas'] nicht. Konstanten nicht ... wie will denn der Herr eine Konfiguration an seine Funktionen übergeben?

                  Eben so, übergeben. Nicht holen, denn das ist nicht die Aufgabe der Funktion. Sie braucht die Daten aber zum arbeiten. Und damit die Funktion universell ist und nicht von sonstwo definierten Werten abhängig ist, übergibt man alles was benotigt wird explizit.

                  Soll etwa jedes Objekt die Konfigurationsdatei lesen und was machst Du bei einem, sagen wir mal schlankem, funktionalen 100-Zeiler? Den mit Objekten auf 300 Zeilen aufblasen?

                  Es kommt nicht auf die Anzahl der Zeilen an, sondern auf die Übersichtlichkeit, die Wartbarkeit und mitunter auch auf die Testbarkeit (im TDD-Sinne). Bei kleinen Projekten kann man vom "Ideal" abweichen. Bei größeren wird es essentiell, dass man nicht ständig im Hinterkopf behalten muss, wer denn nun alles auf eine bestimmte Stelle hingreift, und wie man diese nicht verändern darf, damit noch alles funktioniert. Deshalb verwendet man da am besten Dependency Injection - Abhängigkeiten werden übergeben.

                  dedlfix.

                2. Moin!

                  Beide Varianten sind gleich schlecht im Hinblick auf die Tatsache, dass globale Variablen

                  Die Syntax mit global habe ich angeblich bereits vergessen, da ich diese niemals benutze.

                  Globale Konstanten sollte man trotzdem eher vermeiden.

                  Nana. Also $GLOBAL['config']['sonstwas'] nicht. Konstanten nicht ... wie will denn der Herr eine Konfiguration an seine Funktionen übergeben?

                  Dann hättest du den zweiten Fall vorliegen, den Sven eben beschrieben hat. Du hättest ein Problem oder zumindest eine temporale Abhängigkeit geschaffen: Der Erfolg der Funktion ist davon abhängig, dass die Konfiguration vorher geladen wurde. Ich konstruiere mal ein kleines Beispiel: Es gibt drei Dateien: foo.php, case1.php, case2.php. foo.php soll eine wichtige Funktion in unserer Anwendung enthalten, die auf Datenbankzugriff angewiesen ist. case1.php und case2.php rufen diese Funktion jeweils auf, ein Mal auf gutmütige Weise und ein Mal absichtlich falsch:

                  // foo.php
                  function logToDatabase () {
                    global $config;
                    $db = $condig->db;
                    // mach etwas mit sinnvolles mit der Datenbank
                  }
                  
                  // case1.php
                  require('foo.php');
                  $config = loadConfiguration();
                  logToDatabase(); // Alles gut
                  
                  // case2.php
                  require('foo.php');
                  logToDatabase(); // Übler Anwendungscrash
                  $config = loadConfiguration(); 
                  

                  Die Tükke hierbei ist, dass du zum Zeitpunkt der Definition der Funktion nicht vorausahnen kannst, dass das Laden der Konfiguration und der der Aufruf der Funktion in der richtigen Reihenfolge geschieht. Damit hägt der Erfolgsfall der Funktion implizit von der aurfrufenden Stelle ab. Du könntest in der Funktion nun natürlich abfangen, ob die Konfiguration schon geladen ist und dem Entwickler an dieser Stelle einen hilfreichen Hinweis hinterlassen.

                  // foo.php
                  function logToDatabase () {
                    global $config;
                    if (! $config->db instanceof PDO) {
                      throw new Exception("Keine aktive Datenbankverbindung! Globale Konfiugration schon geladen?");
                    } else {
                      // mach etwas mit sinnvolles mit der Datenbank
                    }
                  }
                  
                  // case1.php
                  require('foo.php');
                  $config = loadConfiguration();
                  logToDatabase(); // Alles Top
                  
                  // case2.php
                  require('foo.php');
                  logToDatabase(); // Mööp! Fehler
                  $config = loadConfiguration();
                  

                  Damit vereitelst du auch, dass das Programm in ungelenkte Bahnen gerät. Man sieht aber auch, dass dieser Ansatz die ursprüngliche Funktion deutlich aufbläht, und wenn das nun in jeder Funktion gemacht werden muss, die Datenbankzugriff oder eine andere globale Einstellung benötigt, dann führt das zu stark fragmentiertem Kontrollfluss innerhalb der Anwendung. Eine heute weit verbreitere Lösung ist es daher, die Kontrolle über die Einhaltung der Reihenfolge an die aufrufende Stelle abzutreten. Bei Funktionen kann das auf sehr einfache Art geschehen, indem man ihnen einen zusätzlichen Parameter gibt. Die Abhängigkeit, die vorher implizit war, ist nun explizit.

                  // foo.php
                  function logToDatabase (PDO $db) {
                    // mach etwas mit sinnvolles mit der Datenbank
                  }
                  
                  // case1.php
                  require('foo.php');
                  $config = loadConfiguration();
                  logToDatabase($config->db);     // Alles Top
                  
                  // case2.php
                  require('foo.php');
                  logToDatabase();                // Mööp! Fehler schon vor der Laufzeit
                  $config = loadConfiguration();
                  

                  Diese Variante ist noch weniger fehleranfällig als die vorherige: In den ersten beiden Fällen kann der Fehler erst zur Laufzeit entdeckt werden, wenn die Funktion logToDatabase() tatsächlich aufgerufen wird. In diesem letzten Beispiel kann der Fehler schon vor der eigentlichen Laufzeit durch statische Programmanalyse entdeckt werden, die heutige Buildtools und IDEs standardmäßig durchführen.

                  Eine positive Nebenwirkung ist, dass die Funktion logToDatabase() generischer ist als zuvor und nun auch mit anderen Datenbanken aufgerufen werden kann. Man profitiert also zusätzlich von erhöhter Wiederverwendbarkeit. Auf der anderen Seite kann diese erhöhte Flexibilität natürlich zum Nervtöter und erneuter Fehlerquelle werden, wenn sie unerwünscht ist und jedesmal wieder mit dem selben zusätzlichen Parameter aufgerufen werden muss. Dagegen könnte man an geeigneter Stelle eine neue Funktion erzeugen, die intern die ursprüngliche Funktion mit entsprechenden Vorbelegungen aufruft. Das könnte dann etwa so aussehen:

                  // foo.php
                  function logToDatabase (PDO $db) {
                    // mach etwas mit sinnvolles mit der Datenbank
                  }
                  
                  // case1.php
                  require('foo.php');
                  $config = loadConfiguration();
                  $logToProduction = function () use ($config) {
                    logToDatabase($config->db);
                  }
                  $logToProduction();
                  
                3. Moin!

                  Globale Konstanten sollte man trotzdem eher vermeiden.

                  Nana. Also $GLOBAL['config']['sonstwas'] nicht. Konstanten nicht ... wie will denn der Herr eine Konfiguration an seine Funktionen übergeben? Soll etwa jedes Objekt die Konfigurationsdatei lesen und was machst Du bei einem, sagen wir mal schlankem, funktionalen 100-Zeiler? Den mit Objekten auf 300 Zeilen aufblasen?

                  Punkt 1: Du meinst "prozedural", nicht "funktional". Bei funktionalen Programmiersprachen sind die Funktionsargumente Funktionen, ebenso wie die Funktionsergebnisse. Sowas schreibt man mit PHP eher nicht.

                  Punkt 2: Objektorientierter Code kriegt die individuellen Parameter für eine Instanz im Konstruktor übergeben. Es ist Aufgabe der Dependency Injection, die da rein zu tun. Das bedeutet, dass es beim Bootstrapping der Applikation eine Phase gibt, in der die Konfiguration eingelesen und passend aufbereitet wird, dabei ein DI-Container entsteht, und dann war es das mit Konfiguration.

                  Ja, das erzeugt mehr Codezeilen. Es erlaubt aber auch vernünftiges Testen und die Wiederverwendbarkeit des Codes.

                  Grüße Sven

                4. Nana. Also $GLOBAL['config']['sonstwas'] nicht. Konstanten nicht ... wie will denn der Herr eine Konfiguration an seine Funktionen übergeben?

                  Ne. Die ganze Konfiguration steckt für wahlfreien Zugriff in der Instanz, welche die Methoden aufruft. Wahlfreier Zugriff heißt z.B. Referenz auf ein Array.

                  Soll etwa jedes Objekt die Konfigurationsdatei lesen und was machst Du bei einem, sagen wir mal schlankem, funktionalen 100-Zeiler? Den mit Objekten auf 300 Zeilen aufblasen?

                  Es gibt nur ein Objekt. Das nimmt den Request entgegen und baut die Response zusammen. Alles was es dazu braucht, bringt es selbst mit, z.B. die Konfiguration. Und die wird schon eingelesen noch bevor das Request/Response-Objekt erstellt wird. Sie, die Konfiguration steht in jeder Methode zur Verfügung noch bevor eine Methode aufgerufen wird.

                  Machs besser ;)

                  1. Eure Bewertung ist gar dümmlich. So wie beschrieben kann ich mit einem xmlrpc die Konfiguration einer ganzen Domäne abfragen. Von solchen und anderen Entwicklerwerkzeugen (Unit-Tests, Mocking) könne Andere nur träumen. Oder auch nicht, weil sie überhaupt gar keinen Plan haben.

                    Hochachtungsvoll, pl

                    1. Tach!

                      Eure Bewertung ist gar dümmlich. So wie beschrieben kann ich mit einem xmlrpc die Konfiguration einer ganzen Domäne abfragen. Von solchen und anderen Entwicklerwerkzeugen (Unit-Tests, Mocking) könne Andere nur träumen. Oder auch nicht, weil sie überhaupt gar keinen Plan haben.

                      Wenn du lediglich die Arbeitsweise deines Closed-Source-Frameworks beschreibst, dann schreib das dazu und formulier deine Antworten nicht allgemeingültig.

                      dedlfix.

                      1. Die Idee, die ich beschrieben habe ist hier aus dem Forum.

                    2. Von solchen und anderen Entwicklerwerkzeugen (Unit-Tests, Mocking) könne Andere nur träumen. Oder auch nicht, weil sie überhaupt gar keinen Plan haben.

                      Wenn du Unit-Testing schon selbst ins Gefecht führst, dann erkläre doch wenigstens wieso dein Ansatz deiner Meinung nach so gut testbar sein sollte. Gut zum Testen geeignet sind überschaubare, unabhängige Module, die Funktionalitäten streng nach dem Single responsibility principle voneinander trennen. Deine Lösungsschilderung liest sich eher wie das Gegenteil davon. Ich zitiere mal, Hervorhebung stammt von mir:

                      Es gibt nur ein Objekt. Das nimmt den Request entgegen und baut die Response zusammen. Alles was es dazu braucht, bringt es selbst mit, z.B. die Konfiguration.

                      Die anderen drei Antworten unter diesem Thread laufen alle auf Dependency-Injection hinaus. Das ermöglicht es Module in Isolation zu testen, weil Abhängigkeiten bei Bedarf von der Testumgebung eingefügt werden können. An dieser Stelle würde dann auch das Mocking ins Spiel kommen, nämlich genau dann, wenn die Initialisierung einer vollfunktionsfähigen Abhängigkeit zu aufwendig für den Test wäre. Dann fügt man häufig einen Mock ein, eine Art Attrappe, die nur das Minimum tut, um die zu testende Einheit zufrieden zu stellen.

            2. Nebenbei: Eine $varible an oberster Code-Ebene, wenn ichs richtig verstanden habe, ist Global. Äh. Nein. Variablen sind in PHP immer local.

              Ach ja stimmt. Wie Dumm von mir.

              Komstanten muss man doch mit define( 'VARIABLE', 'http://...' ); angeben damit sie überall verfügbar sind, oder?

              Damit baut man diese zusammen und Konstanten sind global.

              Das du das näher erleutern?

              Gruß MB

              1. Moin!

                Komstanten muss man doch mit define( 'VARIABLE', 'http://...' ); angeben damit sie überall verfügbar sind, oder? Damit baut man diese zusammen und Konstanten sind global. Das du das näher erleutern?

                Sogar ohne Worte:

                <?php
                define ( 'Foo', 'Bar' );
                jeah();
                
                function jeah() {
                   echo 'Wir gehen in die ', Foo, '!';
                }
                

                Jörg Reinholz

        2. Tach!

          "Literal" ist bei manchen Software-Designern ein anderer Ausdruck für eine Konstante.

          Nicht ganz, eine Konstante ist etwas, das auf einen konstanten Wert verweist. Quasi eine Variable, deren Wert man nicht mehr verändern kann. Ein Literal hingegen ist die Darstellung eines bestimmten Wertes im Programmcode.

          Beispiel:

          define('FOO', 'bar');
          define('QUX', 42);
          

          'FOO', 'bar' und 'QUX' sind String-Literale und die 42 ist ein Integer-Literal. Nach dem Ausführen der Funktion define() existieren dann die beiden Konstanten FOO und QUX, diesmal ohne Anführungszeichen, weil das nun die Bezeichner sind, die auf die Werte bar und 42 verweisen. Dass 'FOO' und 'QUX' (mit Anführungszeichen) String-Literale sind, liegt daran, dass man eine Konstante in PHP nur mit einem Funktionsaufruf erstellen kann und diese Funktion den Namen der Konstante als String übergeben bekommen möchte. Das kann dann ein String-Literal sein oder auch eine Variable oder ein Ausdruck, der einen String zusammensetzt.

          define('FOO', 'bar' . 'qux');
          

          Hier ist 'bar' ist ein Stringliteral, genauso wie 'qux' ('FOO' ebenfalls) und der Ausdruck 'bar' . 'qux' ergibt den Wert barqux.

          dedlfix.

          1. Hallo,

            "Literal" ist bei manchen Software-Designern ein anderer Ausdruck für eine Konstante.

            Nicht ganz, eine Konstante ist etwas, das auf einen konstanten Wert verweist. Quasi eine Variable, deren Wert man nicht mehr verändern kann.

            was du meinst, ist eine benannte oder symbolische Konstante.

            Ein Literal hingegen ist die Darstellung eines bestimmten Wertes im Programmcode.

            Ja, und da dieser Wert unveränderlich ist, eben auch eine Konstante. Eine anonyme Konstante.

            So long,
             Martin

            1. Moin!

              was du meinst, ist eine benannte oder symbolische Konstante.

              Ein Literal hingegen ist die Darstellung eines bestimmten Wertes im Programmcode.

              Ja, und da dieser Wert unveränderlich ist, eben auch eine Konstante. Eine anonyme Konstante.

              Ist doch akademisch.

              "Als Literal (lateinisch littera ‚Buchstabe‘) bezeichnet man in Programmiersprachen eine Zeichenfolge, die zur direkten Darstellung der Werte von Basistypen (z. B. Ganzzahlen, Gleitkommazahlen, Zeichenketten) definiert bzw. zulässig ist."

              Offensichtlich kann jedes gegenständliche oder nichtgegenständliche Ob- oder Subjekt mehrere Namen haben. Ich z.B. heiße Jörg, Reinholz, fastix, ... - und jeder Name ist richtig.

              Jörg Reinholz