Professor Hase: Kann man PHP Header Angabe und Namespace Festlegung includen?

Hallo!

Ich lagere Informationen wie Error Reporting, Internal Encoding, Zeitzonenfestlegung, usw. in eine externe Datei init.inc.php aus. Die eigentlichen PHP Ressourcen beginnen somit mit require_once(init.inc.php); … was auch wunderbar funktioniert.

Meine Frage: Funktioniert das auch mit der Festlegung eines Namespaces und dem obligatorischen header('content-type:text/html; charset=UTF-8'); ??

Kann ich das auch in mein ausgelagertes Skript schreiben oder MÜSSEN die Namespace Festlegung und die Headerangabe in der Ressource stehen, die dann auch in Folge zur Ausgabe einer HTML Seite zum Client geht?

Danke für eine evt. Antwort oder einen Hinweis!

Professor Hase

  1. Hallo Professor,

    Header-Festlegungen gehen definitiv.

    Namespaces? Was meinst Du? PHP Namespaces? Ein namespace-Statement gilt meines Wissens nur für die Elemente der Datei, in der es steht.

    Rolf

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

      Danke für die Antwort!

      Habe in der Zwischenzeit weiter herumgetestet. Also wenn das namespace Foo; im ausgelagerten Skript steht, das dann per require_once(); eingefügt wird, funktionieren meine Klassen (Methoden) auch dann, wenn in dieser Ressource die Namespace Angabe weggelassen wird.

      Also spricht das doch eher dafür, dass die Festlegung in der ausgelagerten Datei genügt, oder?

      Professor Hase

      1. Hallo Professor,

        im Allgemeinen nicht. Gerade bei mir lokal mit PHP 7.1 probiert:

        <?php
        namespace Foo;
        
        include "file2.inc";
        
        function hallo() {
           echo "Foo - Hallo\n";
        }
        
        hallo();
        welt();
        

        und file2.inc:

        <?php
        
        namespace Bar;
        
        function welt() {
           echo "Bar - Welt\n";
        }
        

        Starte ich file1.php, findet er die welt-Funktion nicht (er würde nach \Foo\welt suchen). Bar\welt sucht nach \Foo\Bar\welt und geht auch schief. Ich muss sie schon als \Bar\welt() aufrufen.

        Es gibt ein paar Regeln nach denen PHP Namespaces durchsucht, vielleicht greift eine von denen bei Dir. Oder Du hast den Namespace mit use importiert.

        Rolf

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

          Bei Deinem Beispiel hast Du ja einen weiteren Namespace für die eigentliche Ressource eingeführt.

          So hatte ich das nicht gemeint. Um bei Deinem Beispiel zu bleiben: Im Skript file2.inc steht namespace Bar; und in der Ressource, die die Ausgabe bildet, steht nur include "file2.inc"; - also OHNE irgend eine Namespace Angabe.

          So hatte ich das gemeint. Und das funktioniert offenbar.

          Professor Hase

          PS: Bei mir ist grade eine Folgefrage aufgetaucht: Sehe ich das richtig, dass die Angabe declare(strict_types = 1); zu Beginn eines Skripts lediglich dazu dient, dass ältere PHP Versionen, die mit diesem Feature nichts anfangen können, keine Probleme bereiten und die entsprechenden Hints ignorieren? Weil wenn ich bei einem PHP 7 Skript bei einer Funktion den Typ der zu übergebenen Variablen und/oder den der Ausgabe festlege, kommen bei Nichtbeachtung auf jeden Fall Fehlermeldungen. Unabhängig davon, ob declare(strict_types = 1); angegeben wurde oder nicht.

          1. Hallo Professor,

            <?php
            include "file2.inc";
            
            function hallo() {
               echo "noname - Hallo\n";
            }
            
            hallo();
            welt();
            

            und file2.inc:

            <?php
            namespace Bar;
            
            function welt() {
               echo "Bar - Welt\n";
            }
            

            funktioniert auch nicht. In dem Fall würde in file1.php nach \welt gesucht, statt nach \Bar\welt.

            Es ist etwas anderes, wenn es so aussieht:

            <?php
            namespace Foo;
            
            include "file2.inc";
            
            function hallo() {
               echo "Foo - Hallo\n";
            }
            
            hallo();
            welt();
            

            und file2.inc:

            <?php
            function welt() {
               echo "noname - Welt\n";
            }
            

            Jetzt ist welt im Root-Namespace und der Aufruf erfolgt aus dem Foo-Namespace heraus. Und dann sucht PHP. Zuerst nach \Foo\welt, und dann automatisch auch nach \welt.

            Rolf

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

              Ich weiß jetzt, wo mein Denkfehler war und wieso ich deshalb alles falsch interpretiert hatte! Meine Ausgangs-Situation war:

              file2.inc:

              <?php
              
              Namespace Foo
              
              Class Bar
                {
                  ...
                }
              
              $irgendwas = New Bar;
              
              ?>
              

              seite.php:

              <?php
              
              require_once(file2.inc);
              
              $test = $irgendwas -> methode_xyz();
              
              ?>
              

              Da bringt $test ein Ergebnis. Klar! Die Instanz $irgendwas wurde ja in file2.inc gebildet, also im Foo Namensraum. Das hatte ich nicht bedacht und deshalb fälschlicherweise den Eindruck, es funktioniert auch ohne eine Namensraum Angabe in seite.php. Den Denkfehler sehe ich jetzt auch auf 2 weitere Arten: Im PHP Manual habe ich die Konstante NAMESPACE gefunden. Die ergibt auf file2.inc 'Foo', auf Seite seite.php ist sie inhaltslos. Klar, weil eben kein Namensraum vorhanden ist. Selbst, wenn der im includeten Skript da ist. Und der 2. Beweis für meinen Trugschluss ist, dass eine weitere Klasse, die erstmalig in seite.php aufgerufen wird, selbst aber auch eine Namespace Angabe hat, zu einem Fehler führt. Die Klasse wird nicht gefunden.

              Conclusio: Die Angabe von Namespace muss explizit auf der Seite erfolgen, auf der der Namensraum gelten soll. Wird eine andere Datei mit Namensraum includet, dann wird dieser nicht (!!) automatisch übernommen, während die Angabe

              header('content-type:text/html; charset=UTF-8');
              

              in file2.inc stehen kann und dann auch für seite.php gilt. Vorausgesetzt natürlich, dass es bis zu dieser Zeile weder in file2.inc, noch in seite.php eine Ausgabe Richtung Client gegeben hat.

              Danke für Deine Hilfe! Somit ist meine diesbezügliche Frage beantwortet!

              Professor Hase

              PS: Bzgl. der anderen Sache mit den strict_types hat mir Dedlfix schon geantwortet, wie ich gerade sehe. Damit werde ich mich jetzt seperat beschäftigen.

          2. Tach!

            PS: Bei mir ist grade eine Folgefrage aufgetaucht: Sehe ich das richtig, dass die Angabe declare(strict_types = 1); zu Beginn eines Skripts lediglich dazu dient, dass ältere PHP Versionen, die mit diesem Feature nichts anfangen können, keine Probleme bereiten und die entsprechenden Hints ignorieren?

            Ich vermute, dass du das nicht richtig siehst. Ältere Versionen haben in der Regel keine Ahnung davon, was in zukünftigen Versionen hinzugefügt wurde. Neue Elemente sehen sie deshalb als Sysntaxfehler an. Es sei denn, sie waren damals auch schon als reserviert bekannt, waren gültige Syntax, und wurden lediglich ignoriert. Neue Deklarationen können also nur neue Versionen steuern.

            Weil wenn ich bei einem PHP 7 Skript bei einer Funktion den Typ der zu übergebenen Variablen und/oder den der Ausgabe festlege, kommen bei Nichtbeachtung auf jeden Fall Fehlermeldungen. Unabhängig davon, ob declare(strict_types = 1); angegeben wurde oder nicht.

            Das sollte nicht der Fall sein. Ich hab das mit jenen Beispielen in der PHP Sandbox probiert, und komme zu den dort aufgeführten Ergebnissen.

            dedlfix.

            1. Hi Dedlfix!

              Danke für Deine Antwort! Auf der von Dir verlinkten Seite war ich heute auch schon. Meine falsche Annahme mit den älteren PHP Versionen hatte ich wohl durch ein zu schnelles Lesen des Englischen Textes dort.

              Ältere Versionen haben in der Regel keine Ahnung davon, was in zukünftigen Versionen hinzugefügt wurde. Neue Elemente sehen sie deshalb als Sysntaxfehler an.

              Das ist eigentlich logisch, natürlich! Danke! Ich verstehe die Sache trotzdem nicht. Dort steht:

              Developers can turn strict types on by placing the declare(strict_types=1); method at the top of a PHP file. This implementation means that PHP will 'ignore' type hints and return types unless the declare(strict_types=1); statement appears at the top of the file.

              Und das mit dem "ignore" stimmt so einfach nicht. Zumindest nicht in jedem Fall. Nehmen wir das Beispiel auf der genannten Seite:

              function bar(int $foo): string
              	{
              		return $foo;
              	}
              $result_1 = bar(123);
              

              Das gibt den String '123' zurück. Da wird also gar nichts ignoriert! Da wird umgewandelt. Aber zumindest kommt keine Fehlermeldung. Die kommt, wie auf der Seite richtigerweise steht, erst, wenn man das

              declare(strict_types=1);
              

              davor setzt. Dann kommt ein "Uncaught TypeError: Return value of bar() must be of the type string ..." zurück. OK, jetzt wandle ich die Funktion etwas um:

              function foo(string $bar): int
              	{
              		return $bar;
              	}
              $result_2 = foo('test');
              

              Und hier kommt nun sofort eine Fehlermeldung! Auch ohne, dass ich den Strict Type Modus explizit aktiviere! Das Resultat liefert sofort ein "Uncaught TypeError: Return value of foo() must be of the type int ..."!

              Es ist mir wirklich absolut unverständlich, warum es hier 2 verschiedene Reaktionen gibt beim Verarbeiten des Skripts. Und ich frage mich weiterhin, wozu das Aktivieren des Strict Type Modus nun gut sein soll, wenn der Alarm auch ohne die Zeile losgeht. (Zumindest bei Beispiel 2.)

              Zusammengefasst:

              1.) Wieso gibt es hier bei 2 gleich falschen Typenverwendungen unterschiedliches Error-Verhalten?

              2.) Warum wird in Beispiel 1 der Integer zu einem String umgewandelt, wenn der Modus nicht aktiviert ist? Wenn doch angeblich dann alles "ignoriert" wird!

              3.) Also was bringt die Modus-Aktivierung dann wirklich?

              Professor Hase

              PS: Ich bin anscheinend zu dämlich für dieses Forum! Ich schaffe es nicht, ein Syntax Highlighting des Codes in den Postings hinzubekommen! Die "Erklärung" auf der Hilfeseite ist sowas von unverständlich! Das ist nicht sehr intuitiv gelöst! 😕

              Edit Rolf B: Jetzt stimmt's 😀 Hinter das einleitende ~~~ muss ein php

              1. Tach!

                Developers can turn strict types on by placing the declare(strict_types=1); method at the top of a PHP file. This implementation means that PHP will 'ignore' type hints and return types unless the declare(strict_types=1); statement appears at the top of the file.

                Und das mit dem "ignore" stimmt so einfach nicht. Zumindest nicht in jedem Fall. Nehmen wir das Beispiel auf der genannten Seite:

                function bar(int $foo): string
                	{
                		return $foo;
                	}
                $result_1 = bar(123);
                

                Das gibt den String '123' zurück. Da wird also gar nichts ignoriert! Da wird umgewandelt. Aber zumindest kommt keine Fehlermeldung.

                PHP ignoriert die Typen, also setzt sie nicht strikt durch und macht einfach eine Typumwandlung entsprechend der angegebenen Type Hints.

                function foo(string $bar): int
                	{
                		return $bar;
                	}
                $result_2 = foo('test');
                

                Und hier kommt nun sofort eine Fehlermeldung! Auch ohne, dass ich den Strict Type Modus explizit aktiviere! Das Resultat liefert sofort ein "Uncaught TypeError: Return value of foo() must be of the type int ..."!

                Ja, bei 'test', aber nicht bei 123 oder '123'. Und bei '123test' kommt auch nur eine Notice.

                Mit Type Hints ist PHP wohl etwas strenger, was das Kovertieren in andere Typen angeht als bei Umwandlungen ohne Type Hints. Beispielsweise lässt sich echo (int)'test'; fehlermeldungslos ausführen, und das Ergebnis ist 0.

                Es ist mir wirklich absolut unverständlich, warum es hier 2 verschiedene Reaktionen gibt beim Verarbeiten des Skripts. Und ich frage mich weiterhin, wozu das Aktivieren des Strict Type Modus nun gut sein soll, wenn der Alarm auch ohne die Zeile losgeht. (Zumindest bei Beispiel 2.)

                Wenn du den Strict Mode aktivierst, wandelt PHP nicht selbständig die Typen.

                dedlfix.

              2. Hallo Professor Hase,

                Ich schaffe es nicht, ein Syntax Highlighting des Codes in den Postings hinzubekommen! Die "Erklärung" auf der Hilfeseite ist sowas von unverständlich! Das ist nicht sehr intuitiv gelöst! 😕

                Das Problem könnte sein, dass die Vorschau nur für eine bestimmte Auswahl an Sprachen (HTML, CSS und JavaScript) ein Syntax-Highlighting vornimmt, da in der Vorschau nur für diese Sprachen Regeln geladen werden und es für dich daher so wirkt, als würde die Syntax-Hervorhebung nicht funktionieren. Dafür funktioniert dann aber das Rendern der Vorschau auch ohne Anfragen an den Server.

                Mittels:

                ~~~php
                <?php
                echo "test";
                ?>
                ~~~
                

                Solltest du das Gewünschte erreichen:

                <?php
                echo "test";
                ?>
                

                Gruß
                Julius

                1. <?php
                    $test = $this -> checkSyntaxHighlighting;
                    $antwort = ($test) ? 'Danke Julius!' : 'Geht noch immer nicht!';
                    echo $antwort;
                  ?>