Jörg: Regex mal wieder (Parameter in Funktionsaufruf in Anführungszeichen setzen)

Hallo Forum,

Anlass für mein heutoges Post ist die Weiterentwicklung von php, bzw. meine hieraus resultierenden Problemchen.

Wir wissen also, dass ab php8 Indizes in arrays, die ohne anführungszeichen mitgegeben werden, konsequenterweise als Konstante behandelt werden und nicht mehr als String, so denn keine Konstante vorhanden. Ebenfalls wird es irgendwann (ich weiß nicht, ab wann, in php8 vermutlich noch nicht, aber irgendwann mal ganz sicher!) mal als fatal error ausgeworfen, wenn Parameter in Funktionsaufrufen nicht als String (in Anführungszeichen) übergeben werden.

Also my_function('param1',param2); ergibt heute noch ein warning, irgendwann aber mal einen fatal error.

Und hier habe ich in unzähligen Scripten unzählige Male "gesündigt", daher mein Post.

Ich würde gerne ein Script drüber laufen lassen, was mir das ausmerzt. Wäre es immer derselbe Fehler, hatte ich an sowas hier gedacht:

function dir_rekursiv($verzeichnis)
{
    $handle = opendir($verzeichnis);
    while($datei = readdir($handle)) {
        if($datei != "." && $datei != "..") {
            if(is_dir($verzeichnis.$datei)) // Wenn Verzeichniseintrag ein Verzeichnis ist 
            {
                // Erneuter Funktionsaufruf, um das aktuelle Verzeichnis auszulesen
                dir_rekursiv($verzeichnis.$datei.'/');
            } else {

                if(strstr($verzeichnis.$datei,".php")) {
                    $name = explode(".",$verzeichnis.$datei);

                    if($datei != "replace.php") {   // diese Datei
                        $dateiinhalt = file_get_contents("".$verzeichnis.$datei."");

                        // replace
                        $dateiinhalt = file_get_contents("".$verzeichnis.$datei."");
                        file_put_contents("".$verzeichnis.$datei."",str_replace('test','test123',$dateiinhalt));
                    }
                }
            }
        }
    }
    closedir($handle);
}
dir_rekursiv('mypath');
echo("fertig");

Einfach Austausch von 'test' in 'test123' in jeder Zeile, die gefunden wird, bezogen auf ein komplettes Verzeichnis. Habe es jetzt nicht laufen lassen, aber das sollte so funktionieren, wenn ich keine flüchtigen Fehler eingebaut habe.

Ich suche aber ja keine feststehenden Begriffe, sondern etwas anders.

Meine Funktionsaufrufe sind immer nach folgendem Prinzip:

my_funktion($myVariable,myString)

Und natürlich ist myString ab und zu mal korrekterweise in Anführungszeichen (mal einfache, mal doppelte) gesetzt und meistens nicht.

Wie bringe ich also meinem Script bei, dieses myString immer in Anführungszeichen zu setzen, falls das noch nicht der Fall ist?

Jörg

  1. Hallo Jörg,

    ich würde definitiv keinem REGEX Replace über meinen Sourcecode laufen lassen. Die Chance, dass Du einen Fehl-Match hast, ist ziemlich hoch.

    Ich würde die PHP Sourcen auf deine Entwicklermaschine laden - es sind hoffentlich nicht tausende - und über jede einzelne PHP -l laufen lassen (der eingebaute PHP Syntaxchecker und Linter). Und dann werte die Fehlermeldungen aus.

    Oder nimm Visual Studio Code (verwende eine Version mit PHP Unterstützung; ich weiß grad nicht ob man das explizit selektieren oder als Extension nachinstallieren muss) und verwende das eingebaute Intelephense (Intellisense für PHP), um die Fehler zu finden. Stell aber die richtige PHP Version in den Settings ein (unter Extensions / PHP).

    Oder füge PHPCS (PHP Code Sniffer) als Code Quality Tool hinzu.

    Rolf

    --
    sumpsi - posui - obstruxi
    1. Hallo Rolf,

      ich würde definitiv keinem REGEX Replace über meinen Sourcecode laufen lassen. Die Chance, dass Du einen Fehl-Match hast, ist ziemlich hoch.

      Ich weiß. Aber es sind definitiv zu viele Scripte, die betroffen sind. Da kann ich manuell nicht ran.

      Kann ich die Gefahr eingrenzen, wenn ich den Funktionsnamen sowie den Parameter kenne und einbaue?

      Bsp: Funktionsname ist immer: myFunction
      Parameter2 ist immer: int, string, float, int_null, int_allow_negative oder bool

      Oder würde es etwas bringen, all diese Begriffe mit Konstanten in meinem Programm zu hinterlegen?

      define ( 'int', 'int' );

      Aber dann würde myFunction($test,int) ja immer noch falsch sein, oder?

      Jörg

      1. Hallo Jörg,

        du könntest auch einfach Konstanten definieren.

        define("int", "int"); define("string", "string"); ... define("bool", "bool");

        Damit wäre die Fehlermeldung weg. Problematisch sehe ich aber, dass Du dann Konstanten definierst, die anderswo Bedeutung haben, z.B. als Typdeklaration:

        function foo(string $a, int $b) { ... }
        

        PHP kriegt das zwar auseinander sortiert, aber man weiß ja nicht, was in PHP 8.1 und höher noch kommt. Diese Konstanten sollte man als potenzielle reservierte Worte meiden. Die PHP 8.1 Upgrade Infos sagen dazu nichts, aber PHP 9 wird's bestimmt auch mal geben.

        Ich habe ein bisschen gespielt:

        $pattern = '/\b(my_function\b\s*\(.*?,\s*)(int|string|float|int_null|int_allow_negative|bool)(\s*\))/m';
        $dst = preg_replace_callback($pattern, "replacer", $src);
        
        echo "\n---\nErgebnis:\n$dst\n";
        
        function replacer($matches) {
            $result = $matches[1] . "J_XXX_" . strtoupper($matches[2]) . $matches[3];
            echo $
            return $result;
        }
        

        Ich verwende einen Replace-Callback, um den Namen der Konstanten Großbuchstaben umzuwandeln. Das ist guter Brauch in PHP. Du solltest dann per define Konstanten wie J_XXX_INT oder J_XXX_INT_ALLOW_NEGATIVE festlegen und diese verwenden, niemals aber die realen Codewerte. Diese müssen für den Anwender von my_function "geheim" bleiben, und es müssen dann auch keine Strings sein, eine Zahl reicht auch. Für XXX verwende ein Kürzel, das zum Thema passt. J_ steht für ... tada - Jörg 😉. Wenn my_function ein Wertevalidator für Datentypen ist, dann z.B. J_VALIDATE_INT etc.

        Statt int_null und int_allow_negative solltest Du im Folgeschritt überlegen, ob man daraus nicht mehr als eine Konstante macht, die addiert werden. Sowas wie bei den E_... Werten für error_reporting

        J_XXX_INT kann z.B. 1 sein J_XXX_FLOAT kann 2 sein J_XXX_BOOL kann 3 sein J_XXX_STRING kann 4 sein

        Verwende so bspw. die Bits 0 bis 14 für Codenummern und mach bei einer höheren Zweierpotenz weiter:

        J_XXX_ALLOW_NULL könnte 32768 sein (Bit 15) J_XXX_ALLOW_NEGATIVE könnte 65536 sein (Bit 16)

        Du kannst dann den Parameter (nennen wir ihn $validationRule) in seine Bitfelder zerlegen:

        function my_function($wert, $validationRule) {
           $type = $validationRule & 32767;   // 32768 - 1: Bits 0 - 14
           $allowNull = $validationRule & 32768; // Bit 15
           $allowMinus = $validationRule & 65536; // Bit 16
           ...
        }
        

        Der Aufruf könnte dann so aussehen:

        my_function($someValue, J_XXX_INT | J_XXX_ALLOW_NULL);
        

        Diesen Schritt kannst Du mit dem Editor lösen - Dateiübergreifender Search & Replace von J_XXX_INT_NULL auf J_XXX_INT | J_XXX_ALLOW_NULL.

        Hoffe, das half.
        Rolf

        --
        sumpsi - posui - obstruxi
        1. Hallo Rolf,

          Ich habe ein bisschen gespielt:

          $pattern = '/\b(my_function\b\s*\(.*?,\s*)(int|string|float|int_null|int_allow_negative|bool)(\s*\))/m';
          $dst = preg_replace_callback($pattern, "replacer", $src);
          
          echo "\n---\nErgebnis:\n$dst\n";
          
          function replacer($matches) {
              $result = $matches[1] . "J_XXX_" . strtoupper($matches[2]) . $matches[3];
              echo $
              return $result;
          }
          

          Ich verwende einen Replace-Callback, um den Namen der Konstanten Großbuchstaben umzuwandeln.

          Sekunde, aber wenn wir eh eine Regex drüber jagen, dann müsste es doch ebenso einfach und/oder riskant sein, daraus sowas wie

          myFunction($ganzEgal,'J_XXX_float')

          zu machen. Dann könnte ich mir sparen, Konstanten daraus zu machen?

          Oder habe ich was missverstanden?

          Jörg

          1. Hallo Jörg,

            Das kannst du auch machen, aber Konstanten, vor allem mit numerischen Werten, haben den Vorteil, dass ein Tippfehler zu Warnung oder Error führt.

            Rolf

            --
            sumpsi - posui - obstruxi
            1. Hallo Jörg,

              Das kannst du auch machen, aber Konstanten, vor allem mit numerischen Werten, haben den Vorteil, dass ein Tippfehler zu Warnung oder Error führt.

              Hallo Rolf,

              aber diesbzgl. stehen mir doch in der Funktion selber bis hin zu einer Warnung per email eh sämtliche Optionen offen?

              Gruß, Jörg

              1. Hallo Jörg,

                Ich sage nicht, dass du Konstanten definieren musst.

                Eine nicht definierte Konstante (also: Tippfehler) kann aber bereits die IDE feststellen. Oder sie kann Werte vorschlagen.

                Rolf

                --
                sumpsi - posui - obstruxi
                1. Hallo Rolf,

                  Eine nicht definierte Konstante (also: Tippfehler) kann aber bereits die IDE feststellen. Oder sie kann Werte vorschlagen.

                  Ok, das stimmt.

                  Ehrlich gesagt, komme ich mit Deinem Codeschnipsel noch nicht klar. Soll ich den 1:1 in meine Funktion einsetzen?

                  Ich verstehe auch nicht ganz, wie deine Funktion "replacer" aufgerufen wird.

                  Kannst du mir das vielleicht noch erklären?

                  Jörg

                  1. Hallo Jörg,

                    mein Codeschnipsel soll veranschaulichen, wie man mit preg_replace_callback alle Regex-Vorkommen in einem String verarbeitet. Dieser String ist eine komplette php Datei, die Du mit readfile file_get_contents bspw. eingelesen hast. Darauf könntest du dann meinen Codeschnipsel anwenden, ggf. sinnvoll für deine Belange angepasst, und dann haust Du die Quelldatei wieder raus.

                    TESTE DAS AUF EINER KOPIE DEINER SOURCEN

                    MACH EIN BACKUP VON DEINEM SOURCE, BEVOR DU DEN ERSTEN ECHTEN LAUF MACHST!

                    PRÜFE DAS ERGEBNIS SEHR GENAU, BEVOR DU ES AKZEPTIERST

                    Für die Prüfung empfehle ich ein Tool, das ganze Verzeichnisbäume textuell vergleichen kann. Meins ist kdiff3 0.98 - allerdings seit 7 Jahren ungepflegt. Für neuere Versionen finde ich keinen Windows Build, brauchte ich bisher auch nicht. Es gibt sicherlich auch andere Tools für diesen Zweck.

                    Die Regex matcht deine Funktionsaufrufe, und wie es bei Regexen so ist, gibt es nicht nur den eigentlichen Match "von vorn bis hinten", sondern auch eine Match Group für jeden Klammerausdruck.

                    Die Regex ist

                    /\b(my_function\b\s*\(.*?,\s*)
                    (int|string|float|int_null|int_allow_negative|bool)
                    (\s*\))/m
                    

                    Ich habe bewusst an den Klammern die Zeilenumbrüche gemacht. Die Regex-Mustersymbole erkläre ich jetzt nicht, den Roman dazu findest Du hier.

                    Die erste Klammergruppe matcht my_function(..., also alles von my_function bis zum Komma, das 1. und 2. Parameter trennt. Vor der Klammer und hinter dem Komma darf noch beliebig Leerraum stehen. Die Regex funktioniert nicht, wenn dein 1. Parameter ein komplizierterer Ausdruck ist, der selbst Kommas enthält (z.B. ein Funktionsaufruf). Eine Regex kann kein vollständiger Codeparser sein. Wenn Du das benötigst, brauchst Du sowas wie das hier. Careful, there be dragons inside...

                    Die zweite Klammergruppe ist eine Auflistung von möglichen Konstanten, von int bis bool. Sie matcht exakt die Schreibweise, weil bei den Optionen kein i dabei ist - ich hoffe, das passt für Dich.

                    Die dritte Klappergruppe ist dann wieder Leerraum und eine rechte Klammer.

                    Also: die Zeile
                    my_function ( $hugo, int );
                    erzeugt einen Match (0) und drei Teilgruppen (1-3):

                    0: my_function ( $hugo, int ) (korrekt, kein Semikolon)
                    1: my_function ( $hugo,
                    2: int
                    3: )

                    Und genau diese vier Teile bekommt die Callback-Funktion als Array mit genau diesen Indizes übergeben. Sie konstruiert daraus dann das, was den gesamten Match ersetzen soll, und gibt es zurück.

                    Die wird von preg_replace_callback automatisch aufgerufen, für jeden Match, den sie findet. Der Name der Callback-Funktion wird preg_replace_callback als 2. Parameter mitgeben, als String. Es gibt auch andere Möglichkeiten dafür, das findet man unter "Callable" im PHP Handbuch.

                    Die Replacer-Funktion hat nur einen Zweck: sie soll deine Konstanten so umbauen, dass sie zu Konstanten nach PHP Muster werden, also ein gemeinsames Präfix für die Konstantengruppe und dann ein Schlüsselbegriff, und alles in Großbuchstaben.

                    Wenn Du das nicht willst, kannst Du das mit dem Callback auch lassen und einfach preg_replace mit einem Replace-Pattern wie "$1'%2'%3" verwenden, oder '$1"%2"%3' wenn es doppelte Anführungszeichen werden sollen. Dadurch wird die zweite Matchgruppe einfach in Hochkommas oder Anführungszeichen gesetzt.

                    Rolf

                    --
                    sumpsi - posui - obstruxi
                    1. Hallo Rolf,

                      Dieser String ist eine komplette php Datei, die Du mit readfile bspw. eingelesen hast.

                      nein, das glaube ich nicht. Denn readfile() liest den Dateiinhalt und gibt ihn direkt auf stdout aus, also in der Regel an den HTTP-Client. Vielleicht hast du eher an get_file_contents() gedacht.

                      May the Schwartz be with you
                       Martin

                      --
                      Theorie ist, wenn eigentlich jeder weiß, wie's gehen müsste, und es geht doch nicht.
                      Praxis ist, wenn's geht, obwohl es keiner so richtig versteht.
                      Bei uns sind Theorie und Praxis vereint: Nichts geht, und keiner weiß, warum.
                      1. Hallo Martin,

                        ups. Fixed.

                        Schönen Gruß an Dark Helmet

                        Rolf

                        --
                        sumpsi - posui - obstruxi
                    2. Hallo Rolf,

                      mein Codeschnipsel soll veranschaulichen, wie man mit preg_replace_callback alle Regex-Vorkommen in einem String verarbeitet. Dieser String ist eine komplette php Datei, die Du mit readfile file_get_contents bspw. eingelesen hast. Darauf könntest du dann meinen Codeschnipsel anwenden, ggf. sinnvoll für deine Belange angepasst, und dann haust Du die Quelldatei wieder raus.

                      Ok, jetzt hab ichs.

                      Für die Prüfung empfehle ich ein Tool, das ganze Verzeichnisbäume textuell vergleichen kann. Meins ist kdiff3 0.98 - allerdings seit 7 Jahren ungepflegt.

                      Ja, ich selber nutze das auch (ist glaub ich in mercurial eingebaut) beim Dateienvergleich, ansonsten nutze ich noch viel lieber csdiff, was aber auch ein Uralttool ist.

                      Also: die Zeile
                      my_function ( $hugo, int );
                      erzeugt einen Match (0) und drei Teilgruppen (1-3):

                      0: my_function ( $hugo, int ) (korrekt, kein Semikolon)
                      1: my_function ( $hugo,
                      2: int
                      3: )

                      Und genau diese vier Teile bekommt die Callback-Funktion als Array mit genau diesen Indizes übergeben. Sie konstruiert daraus dann das, was den gesamten Match ersetzen soll, und gibt es zurück.

                      Die wird von preg_replace_callback automatisch aufgerufen, für jeden Match, den sie findet. Der Name der Callback-Funktion wird preg_replace_callback als 2. Parameter mitgeben, als String. Es gibt auch andere Möglichkeiten dafür, das findet man unter "Callable" im PHP Handbuch.

                      Ok, die Regex hatte ich verstanden, aber ich hatte nicht verstanden, wo der Funktionsaufruf stattfand. Jetzt weiß ichs, es ist der Parameter.

                      Die Replacer-Funktion hat nur einen Zweck: sie soll deine Konstanten so umbauen, dass sie zu Konstanten nach PHP Muster werden, also ein gemeinsames Präfix für die Konstantengruppe und dann ein Schlüsselbegriff, und alles in Großbuchstaben.

                      Wenn Du das nicht willst, kannst Du das mit dem Callback auch lassen und einfach preg_replace mit einem Replace-Pattern wie "$1'%2'%3" verwenden, oder '$1"%2"%3' wenn es doppelte Anführungszeichen werden sollen. Dadurch wird die zweite Matchgruppe einfach in Hochkommas oder Anführungszeichen gesetzt.

                      Vielen dank für die erklärung. 👍 Ohne sie hätte ich zwar den Code gehabt, der hätte mir aber nicht so viel gebracht, weil ich gar nicht gewußt hätte, was er genau warum so macht.

                      Jörg

  2. Tach!

    function dir_rekursiv($verzeichnis)
    

    Ein RecursiveDirectoryIterator existiert.

    dedlfix.

  3. Wir wissen also, dass ab php8 Indizes in arrays, die ohne anführungszeichen mitgegeben werden, konsequenterweise als Konstante behandelt werden und nicht mehr als String, so denn keine Konstante vorhanden. Ebenfalls wird es irgendwann (ich weiß nicht, ab wann, in php8 vermutlich noch nicht, aber irgendwann mal ganz sicher!) mal als fatal error ausgeworfen, wenn Parameter in Funktionsaufrufen nicht als String (in Anführungszeichen) übergeben werden.

    Ich würde gerne ein Script drüber laufen lassen, was mir das ausmerzt. Wäre es immer derselbe Fehler, hatte ich an sowas hier gedacht:

    Hab ich verworfen.

    Das Skript müsste zwischen

    <?php
    define('foo', 'Hoppla');
    $bar['Hoppla'] = 'Da bin ich.';
    echo $bar[foo];
    

    (verteilt auf mehrere includierte Dateien...)

    und dem stumpfen

    <?php
    $bar['Hoppla'] = 'Da bin ich.';
    echo $bar[Hoppla];
    

    unterscheiden können.

    Das geht nicht ohne Durchlauf, Auswerten des Fehlerkanals/Logfiles, konkretem Ansprung auf die Stelle. Das hat aber wieder eigene Fehlerquellen ($_GET, $_POST, $_SERVER, $_FILES, ...). Und ich möchte nicht dabei sein, wenn da was automatisch ersetzt wurde. Die Fehlersuche kann dann echt aufwendig werden - sofern die Fehler überhaupt bemerkt werden.

    Da stellt man sich besser, man liest gleich nur im error-Log und behebt das Step-By-Step

  4. Moin zusammen,

    my_funktion($myVariable,myString)
    

    Und natürlich ist myString ab und zu mal korrekterweise in Anführungszeichen (mal einfache, mal doppelte) gesetzt und meistens nicht.

    nur der Neugierde halber: Es war (ist) erlaubt in PHP (< 8) Stringparameter „nicht als Strings“ zu übergeben? Wer ist denn damals auf diese verwirrende Idee gekommen?

    Viele Grüße
    Robert

    1. Hi Robert,

      nur der Neugierde halber: Es war (ist) erlaubt in PHP (< 8) Stringparameter „nicht als Strings“ zu übergeben? Wer ist denn damals auf diese verwirrende Idee gekommen?

      Naja, das war und ist ja nicht nur hier der Fall. In vielen Anwendungen wird versucht, bei einem Fehler des Anwenders bestmöglich nachzuempfinden, was er denn eigentlich wollte. Gib nur mal in der Suchmaschine Deiner Wahl einen fehlerhaft geschriebenen Suchbegriff ein. Und die php-Entwickler dachten sich wohl, dass, so keine Konstante vorhanden, ein String dem am nächsten käme, was der User wollen würde. Ob z.b. bei einem int-Parameter in einen int konvertiert wird, weiß ich nicht. Könnte man aber leicht herausfinden.

      Inzwischen ist man seitens der php-Entwickler ja auch anderer mein ung und stellt zukkzessive um, wirft also all diese Dinge aus php raus.

      Jörg

      1. Hallo Jörg,

        Und die php-Entwickler dachten sich wohl...

        Ich nehme an, dass sich Rasmus Lerdorf zu der Zeit, wo er die Personal Home Page Tools bzw. den Forms Interpreter baute, hauptsächlich Gedanken um Bequemlichkeit gemacht hat. Als er zusammen mit Andi und Zeev PHP3 entwickelte, schien es schon Konstanten zu geben, aber die PHP 3 Doku, die ich kenne, weiß nichts von define(). Dafür finde ich erst in PHP 4, also 1999, einen Beleg. Angesichts der diversen antiken Unsäglichkeiten von PHP dürfte die Annahme fundiert sein, dass Sauberkeit kein priorisiertes Kriterium für den Sprachentwurf war.

        Ob z.b. bei einem int-Parameter in einen int konvertiert wird, weiß ich nicht. Könnte man aber leicht herausfinden.

        Ab PHP 7.0: wenn das Argument in ein int konvertierbar ist, dann ja. Ansonsten wird ein TypeError geworfen. Bis PHP 5.6: PHP möchte ein Objekt einer Klasse namens "int" sehen und wirft einen "Catchable fatal error", wenn es was anderes bekommt. Falls man auf die dumme Idee gekommen ist, sowas wirklich zu tun, fliegt der Code mit PHP 7 auf die Nase: "Cannot use 'int' as class name as it is reserved".

        Sandbox

        Rolf

        --
        sumpsi - posui - obstruxi
      2. Moin Jörg,

        nur der Neugierde halber: Es war (ist) erlaubt in PHP (< 8) Stringparameter „nicht als Strings“ zu übergeben? Wer ist denn damals auf diese verwirrende Idee gekommen?

        Naja, das war und ist ja nicht nur hier der Fall. In vielen Anwendungen wird versucht, bei einem Fehler des Anwenders bestmöglich nachzuempfinden, was er denn eigentlich wollte. Gib nur mal in der Suchmaschine Deiner Wahl einen fehlerhaft geschriebenen Suchbegriff ein.

        Vielleicht denke ich da als programmierender Physiker zu „schräg“ (oder gerade aus), aber ich finde solche Uneindeutigkeiten gerade beim Lernen einer Programmiersprache immer sehr verwirrend und fehlerträchtig. Beispiel: Warum ist

        echo Moin;
        

        erlaubt und gibt (neben der Notice) Moin aus, während

        echo Moin Moin;
        

        ein Syntaxfehler ist? Und was muss der Neuling feststellen, wenn er einen String verwenden möchte, den es aber schon als Namen einer Konstante gibt?

        function quiz($answer) {
            echo 'Is PHP a programming language? – ', $answer, "\n";
        }
        
        quiz(true);
        

        Bei der Suchmaschine habe ich wenigstens die Wahl auch nach der „Falschschreibung“ suchen zu lassen.

        Und die php-Entwickler dachten sich wohl, dass, so keine Konstante vorhanden, ein String dem am nächsten käme, was der User wollen würde.

        Oder es ist eine Altlast aus der Anfangszeit der Sprache 😉

        Viele Grüße
        Robert

        1. Hallo Robert,

          wenn Du eine Notice bekommst, solltest Du dringend dein PHP updaten. Das ist nämlich mit PHP 7 zur Warning geworden, und ab PHP 8 zum Error.

          define("Moin", "Hallo");
          echo Moin Moin;
          

          ist aber auch vor PHP 7 schon ein Syntaxfehler, weil die Konstante einfach 1:1 durch den definierten Wert ersetzt und zu

          echo "Hallo" "Hallo";
          

          wird. Es hat ja niemand behauptet, dass echo Moin; sinnvoller Code in PHP gewesen wäre. Damit wird man auch keine Altlasten haben. Das passiert eher bei assoziativen Arrays; ich hatte vor Jahren ein Altprojekt auf PHP, das konsequent $arr[name] statt $arr['name'] verwendete. In Tausenden von Zeilen…

          Frust fact: Beim String Parsing ist die Notation ohne Anführungszeichen nach wie vor legal. Aber nur in der simple syntax. Die complex syntax will es mit Anführungszeichen:

          $x = [ "foo" => 42 ];
          echo "Die Antwort ist $x[foo]";
          echo "Die Antwort ist { $x['foo'] }";
          

          Und es ist nicht nur legal, es ist auch noch Pflicht. Beide Echos sind falsch:

          $x = [ "foo" => 42 ];
          echo "Die Antwort ist $x['foo']";
          echo "Die Antwort ist { $x[foo] }";
          

          Rolf

          --
          sumpsi - posui - obstruxi
          1. Moin Rolf,

            wenn Du eine Notice bekommst, solltest Du dringend dein PHP updaten. Das ist nämlich mit PHP 7 zur Warning geworden, und ab PHP 8 zum Error.

            Ist schon etwas mehr als eine „Notice“ 😉

            define("Moin", "Hallo");
            echo Moin Moin;
            

            ist aber auch vor PHP 7 schon ein Syntaxfehler, weil die Konstante einfach 1:1 durch den definierten Wert ersetzt und zu

            echo "Hallo" "Hallo";
            

            wird.

            Das ist genau die Regel, die ich meine: Ein einzelnes Wort wird zum String, mehrere nicht. Da merkt man sich doch lieber die Regel, dass Strings immer in einfache oder doppelte Quotes gehören.

            Es hat ja niemand behauptet, dass echo Moin; sinnvoller Code in PHP gewesen wäre.

            Wenn meine Webseite in Friesland laufen soll …

            Viele Grüße
            Robert