Ankündigung

Einklappen
Keine Ankündigung bisher.

Namespace Überschreibung?

Einklappen

Neue Werbung 2019

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

  • Namespace Überschreibung?

    Hallo,

    ich bastel mir zur Zeit ein eigenes Framework. Bitte nun keine Meinung darüber das ich das Rad neu erfinden will, ich mach das um zu lernen etc.

    Ich hänge aber zur Zeit an einem Problem was ich meiner Meinung nach nicht sauber gelöst bekomme.

    Hier ein kleiner Ausschnitt meiner Ordnerstruktur:

    Code:
    - application
    - - core
    - - - Request.class.php
    - core
    - - library
    - - - Request.class.php
    - basic.php
    Es gibt 2 Hauptordner. Einmal den "application" Ordner wo sich alle Application-Spezifische Dateien wie Controller, Models und View befinden. Und einmal den "Core" Ordner wo sich alle Framework-Dateien befinden die den Ablauf steuern etc.

    Nun möchte ich, wie man es in der Struktur erkennen kann, das man im Application Ordner den Core erweitern kann indem man z. B, die Request Klasse überschreibt und erweitert und anpasst.

    Die Klasse im Core Ordner sieht wie folgt aus:

    PHP-Code:
    namespace Core\Library;

    class 
    Request
    {

    Und die Klasse im Application Folder folgendermaßen:

    PHP-Code:
    namespace Application\Core;

    final class 
    Request extends \Core\Library\Request
    {


    Wenn ich nun also z. B. in der basic.php, welche sich im Core Verzeichnis befindet, die Request Klasse aufrufen möchte muss ich dieses wie folgt machen (Namespace der basic.php ist \Core):

    PHP-Code:
    new \Application\Core\Request(); 
    1. Problem ist das ich es unsauber finde das ich im Core Verzeichnis den Application Namespace benutzen muss.

    2. Es ist bei der aktuellen Lösung zwingend erforderlich das in dem Application Verzeichnis die Request Klasse vorhanden ist. Ich möchte allerdings eine Lösung finden das dies optional ist, sodass ich die Request.class.php im Application Verzeichnis nur erstellen muss wenn ich diese wirklich überschreiben will. Wenn ich die Datei nun löschen würde, versucht die basic.php nun weiterhin die Datei im Application Verzeichnis zu finden.

    Man könnte in der basic.php zwar \Core\Library\Request verwenden, wenn man dann allerdings den Core erweitern möchte und im Application Verzeichnis die Klasse überschreibt müsste man die basic.php anpassen, was ich vermeiden möchte, da sich diese im Core Verzeichniss befindet. Es sollte halt automatisch erkannt werden.

    PS: Ich nutze einen selbstentwickelten Autoloader der auch mit Namespaces umgehen kann. Eine Lösung dahingehend das der Autoloader erst versucht im Application Verzeichnis zu suchen sehe ich eher nicht, da die Request Klasse im Application Verzeichnis einen anderen Namen hat als die Request Klasse im Core Verzeichnis (wegen den Namespaces)

    Ich hoffe ich konnte mein Problem einigermaßen verständlich erklären und hoffe das jemand eine saubere Lösung dafür kennt.

    Gruß

  • #2
    Zitat von stayInside Beitrag anzeigen
    PS: Ich nutze einen selbstentwickelten Autoloader der auch mit Namespaces umgehen kann. Eine Lösung dahingehend das der Autoloader erst versucht im Application Verzeichnis zu suchen sehe ich eher nicht, da die Request Klasse im Application Verzeichnis einen anderen Namen hat als die Request Klasse im Core Verzeichnis (wegen den Namespaces
    Ist mMn aber die richtige Vorgehensweise. Dein Autoloader muss entscheiden, welche der beiden Dateien geladen werden soll. Dass die Klassen anders heißen, macht da eigentlich kein Problem - der Autoloader sucht ja primär nach Dateien.

    Zu 1. Wieso ist die basic.php überhaupt im core? Die Datei ist doch eindeutig Anwendungsspezifisch. Was soll die überhaupt machen?
    [URL="http://goo.gl/6Biyf"]Lerne Grundlagen[/URL] | [URL="http://sscce.org/"]Schreibe gute Beispiele[/URL] | [URL="http://goo.gl/f2jR7"]PDO > mysqli > mysql[/URL] | [URL="http://goo.gl/jvfSZ"]Versuch nicht, das Rad neu zu erfinden[/URL] | [URL="http://goo.gl/T2PU5"]Warum $foo[bar] böse ist[/URL] | [URL="http://goo.gl/rrfzO"]SQL Injections[/URL] | [URL="http://goo.gl/Q81WJ"]Hashes sind keine Verschlüsselungen![/URL] | [URL="http://goo.gl/2x0e2"]Dein E-Mail Regex ist falsch[/URL]

    Kommentar


    • #3
      also im Kohana framework exestiert das "Cascading File System"

      http://kohanaframework.org/3.3/guide/kohana/files

      es gibt ein Applications ordner, ein System ordner und Modules ordner der Autoloader behandelt klassen in Prioritäten.

      Application hat höchste Priorität,
      Danach Modules
      Danach System

      damit man mit den Module die System klassen erweitern kann die man mit der Application verändern kann.

      im grunde wird dabei der AutoLoader mit weiteren Pfaden gefüttert
      https://github.com/kohana/core/blob/.../Core.php#L492

      beim Aufruf einer methode wird geschaut ob die Klasse die Methode hat, wenn nicht dann wird eine Prioritätstufe tiefer geschaut. So braucht man zb nicht die Komplette klasse zu überschreiben sondern nur eine oder mehrere Methoden.

      Die pfade, mit vorhandenen methoden werden gecached(wenn cache aktiviert ist) dass das der Autoloader weniger durchläufe beim Aufruf hat.

      Vielleicht ist ja die Core klasse von Kohana Interessant für dich, dort werden zwar keine Namespaces verwendet aber Ziel ist der Gleiche

      MFG
      apt-get install npm -> npm install -g bower -> bower install <package> YOLO [URL]https://www.paypal.me/BlackScorp[/URL] | Mein Youtube PHP Kanal: [url]https://www.youtube.com/c/VitalijMik[/url]

      Kommentar


      • #4
        Zitat von ApoY2k Beitrag anzeigen
        Ist mMn aber die richtige Vorgehensweise. Dein Autoloader muss entscheiden, welche der beiden Dateien geladen werden soll. Dass die Klassen anders heißen, macht da eigentlich kein Problem - der Autoloader sucht ja primär nach Dateien.

        Zu 1. Wieso ist die basic.php überhaupt im core? Die Datei ist doch eindeutig Anwendungsspezifisch. Was soll die überhaupt machen?
        Okay das mit der basic.php muss ich mir nochmal überlegen. Hier mal die basic.php die zwar Anwendungsspezifische Einstellungen macht, allerdings über Config-Einstellungen:

        PHP-Code:
        <?php 

        namespace Core;

        use \
        Application\Core\Environment;
        use \
        Application\Core\Registry;
        use \
        Application\Core\Autoload;
        use \
        Application\Core\Helper;
        use \
        Application\Core\Session;
        use \
        Application\Core\Template;

        if (
        defined('SCRIPT') === false) die('The file cannot be called directly!');

        error_reporting(Environment :: get('ErrorLevel'));

        setlocale(LC_TIMERegistry :: get('TimeLanguage'));

        date_default_timezone_set(Registry :: get('TimeZone'));

        mb_http_output(Registry :: get('CharsetHTTPOutput'));
        mb_internal_encoding(Registry :: get('CharsetInternalEncoding'));
        mb_language(Registry :: get('CharsetLanguage'));

        /*
         * Autoloader instanziieren
         */
        require_once (Registry :: get('CoreLibraryPath') . 'Autoload.class.php');
        require_once (
        Registry :: get('ApplicationCorePath') . 'Autoload.class.php');

        /*
         * Dateiendung für den Autoloader festlegen
         */
        Autoload :: setExtension('.class.php');

        /*
         * Cacheverzeichnis für den Autoloader festlegen
         */
        Autoload :: setCacheFolder(Registry :: get('ApplicationTempCacheAutoloadPath'));

        Autoload :: setReloadCache(Registry :: get('ClassReloadCache'));

        /*
         * Verzeichnisse und Cachenamen für den Autoloader festlegen
         */
        Autoload :: register(Registry :: get('ApplicationCorePath'),         'Application\Core',         10);
        Autoload :: register(Registry :: get('ApplicationControllerPath'),     'Application\Controller',      20);
        Autoload :: register(Registry :: get('ApplicationModelPath'),         'Application\Model',        30);
        Autoload :: register(Registry :: get('ApplicationSparkPath'),         'Application\Spark',        40);

        Autoload :: register(Registry :: get('CoreLibraryPath'),             'Core\Library',                60);
        Autoload :: register(Registry :: get('CoreSparkPath'),                 'Core\Spark',                50);

        /*
         * Autoloader aktiviert
         */
        Autoload :: activate();

        Helper :: setReloadCache(Registry :: get('HelperReloadCache'));

        /*
         * Cacheverzeichnis für den Funktions-Autoloader festlegen
         */
        Helper :: setCacheFolder(Registry :: get('ApplicationTempCacheHelperPath'));

        /*
         * Verzeichnisse und Cachenamen für den Funktions-Autoloader festlegen
         */
        Helper :: register(Registry :: get('CoreHelperPath'),             'Core\Helper',             20);
        Helper :: register(Registry :: get('ApplicationHelperPath'),     'Application\Helper',     10);

        /*
         * Session initialisieren
         */
        Session :: setSessionFolder(Registry :: get('ApplicationTempSessionPath'));

        /*
         * Template instanziieren
         */
        $objTemplate Template :: getInstance();

        /*
         * Pfad zu den Template-Dateien setzen
         */
        $objTemplate->setTemplatePath(Registry :: get('ApplicationViewPath'));

        /*
         * Pfad zum Cache-Verzeichnis setzen
         */
        $objTemplate->setTemplateCachePath(Registry :: get('ApplicationTempCacheTemplatePath'));

        /*
         * Lokal wird das komprimieren der Templates deaktiviert
         */
        $objTemplate->setMinifyTemplates(Registry :: get('MinifyTemplates'));

        /*
         * Lokal werden Templates immer neu geparst
         */
        $objTemplate->setForceCompile(Registry :: get('ForceCompileTemplates'));

        if (
        Registry :: get('DatabaseUsage') === true &&
            
        file_exists(Registry :: get('ApplicationConfigPath') . 'database.conf.php') === true)
        {
            
        /*
             * Datenbankregister laden
             */
            
        require_once (Registry :: get('ApplicationConfigPath') . 'database.conf.php');
        }

        ?>
        Wenn ich z. B. in der basic.php (\Core Namespace) die "use" Anweisung entferne und man nun "new Request()" anruft, versucht er die \Core\Request anfzurufen. Ich müsste dann quasi im Autoloader erst die ganzen Namespaces entfernen und dann versuchen mit dem Application Namespace aufzurufen und dann, nochmal mit dem Core Namespace. Richtig verstanden?

        also im Kohana framework exestiert das "Cascading File System"....
        So soll es werden, ja

        Kommentar


        • #5
          Wieso nicht einfach die benutzenden Klassen explizit angeben? Gerade bei einem Framework erwarte ich maximale Kontrolle über die Anwendung. Sofern der Anwender z.B. die Request-Klasse überschreibt, sollte in eine zentralen Konfigurationsdatei angegeben werden können, dass nun diese Request-Klasse zu benutzen ist.

          Im Übrigen habe ich noch ein, zwei Fragen zu deiner Struktur: Wie handhabst du die Einbindung anderer Frameworks oder Bibliotheken, wie bspw. einer Mailer-Klasse? Außerdem interessiert mich, an welcher Stelle die Registry mit Daten gefüttert wird. Schließlich erfolgen fast ausschließen get()-Aufrufe in der basic.php.

          Kommentar


          • #6
            Als ungetesteten Ansatz werfe ich mal Namespace-Aliases in den Raum.
            Gggfls. wäre es möglich, damit eine "Zusammenfassung" zu einem Namespace zu machen, wobei ich da auf die Schnelle nichts über Prioritäten finden konnte.
            Vorstellen würde ich es mir im Grunde so, dass zunächst \Core\* per Alias in MyMergedLib\* und dann \MyApp\* ebenfalls (überschreibend) in \MyMergedLib\* geladen wird.
            Damit würdest du eben alles nur noch über MyMergedLib\* ansprechen.
            VokeIT GmbH & Co. KG - VokeIT-oss @ github

            Kommentar


            • #7
              Zitat von Trainmaster Beitrag anzeigen
              Wieso nicht einfach die benutzenden Klassen explizit angeben? Gerade bei einem Framework erwarte ich maximale Kontrolle über die Anwendung. Sofern der Anwender z.B. die Request-Klasse überschreibt, sollte in eine zentralen Konfigurationsdatei angegeben werden können, dass nun diese Request-Klasse zu benutzen ist.

              Im Übrigen habe ich noch ein, zwei Fragen zu deiner Struktur: Wie handhabst du die Einbindung anderer Frameworks oder Bibliotheken, wie bspw. einer Mailer-Klasse? Außerdem interessiert mich, an welcher Stelle die Registry mit Daten gefüttert wird. Schließlich erfolgen fast ausschließen get()-Aufrufe in der basic.php.
              Das mit der expliziten Angabe werde ich mir auf jeden Fall durch den Kopf gehen lassen.

              Es gibt im Application-Verzeichniss ein Unterverzeichnis namens "config" wo sich diverse feste Config-Dateien befinden (z. B. main.conf.php, environment.conf.php etc.) die halt fest vom Framework geladen werden. Geplant ist aber auch noch die Möglichkeit benutzerdefinierte Config Dateien zu laden. Ebenfalls geplant ist auch die Möglichkeit für jede Umgebung (Lokal, Preview, Online etc.) weitere Config Dateien zu laden.

              Hier mal 2 Beispiele von Config-Dateien (main.conf.php und environment.conf.php):

              PHP-Code:
              namespace Application\Config;

              use \
              Application\Core\Registry;

              if (
              defined('SCRIPT') === false) die('The file cannot be called directly!');

              Registry :: set('TimeLanguage', array('de_DE@euro''de_DE''deu_deu'));
              Registry :: set('TimeZone',     'Europe/Berlin');

              Registry :: set('CharsetHTTPOutput',        'UTF-8');
              Registry :: set('CharsetInternalEncoding',    'UTF-8');
              Registry :: set('CharsetLanguage',            'uni');

              Registry :: set('MinifyTemplates',             true);
              Registry :: set('ForceCompileTemplates',     true);

              Registry :: set('DatabaseUsage',            true);

              Registry :: set('ClassReloadCache',         true);
              Registry :: set('HelperReloadCache',         true); 
              PHP-Code:
              namespace Application\Config;

              use \
              Application\Core\Environment;

              if (
              defined('SCRIPT') === false) die('The file cannot be called directly!');

              /*
               * Production
               */
              Environment :: register('Production''', array
              (
                  
              'DisplayError'     => false,
                  
              'ErrorLevel'     => E_ALL E_STRICT,
                  
              'Log'            => true,
                  
              'Debug'         => true        
              ));

              /*
               * Preview
               */
              Environment :: register('Preview''', array
              (
                  
              'DisplayError'     => false,
                  
              'ErrorLevel'     => E_ALL E_STRICT,
                  
              'Log'            => true,
                  
              'Debug'         => true
              ));

              /*
               * Local
               */
              Environment :: register('Local', array('127.0.0.1''::1'), array
              (
                  
              'DisplayError'     => true,
                  
              'ErrorLevel'     => E_ALL E_STRICT,
                  
              'Log'            => true,
                  
              'Debug'         => true
              )); 
              Edit: Die Einbindung weiterer Bibliotheken wurde zur Zeit noch nicht umgesetzt ist aber in Planung. Dies wird denke ich über den üblichen Weg gehandhabt das man ein "vendor" Verzeichnis hat wo sich die Bibliotheken befinden. Wie man Diese dann einbindet steht noch in den Sternen.


              Zitat von G.Schuster Beitrag anzeigen
              Als ungetesteten Ansatz werfe ich mal Namespace-Aliases in den Raum.
              Gggfls. wäre es möglich, damit eine "Zusammenfassung" zu einem Namespace zu machen, wobei ich da auf die Schnelle nichts über Prioritäten finden konnte.
              Vorstellen würde ich es mir im Grunde so, dass zunächst \Core\* per Alias in MyMergedLib\* und dann \MyApp\* ebenfalls (überschreibend) in \MyMergedLib\* geladen wird.
              Damit würdest du eben alles nur noch über MyMergedLib\* ansprechen.
              Mir ist bislang keine Möglichkeit bekannt das PHP dies unterstützt. Leider.

              Kommentar


              • #8
                Tatsache, hat mich jetzt auch interessiert und hab's getestet: "Fatal error: Cannot use bar as merged because the name is already in use"
                Schade, das hätte das Problem elegant gelöst.
                VokeIT GmbH & Co. KG - VokeIT-oss @ github

                Kommentar


                • #9
                  Habe das ganze mal dahingehend umprogrammiert das der Autoloader die Entscheidungen trifft was geladen werden soll, allerdings ohne Erfolg, weil der Autoloader nicht weiss was genau er laden muss.

                  Angenommen die Dateien sehen wie folgt aus:

                  application/core/Request.class.php
                  PHP-Code:
                  namespace Application\Core;

                  class 
                  Request extends \Core\Library\Request
                  {

                  core/library/Request.class.php
                  PHP-Code:
                  namespace Core\Library;

                  class 
                  Request
                  {

                  Wenn eine Klasse geladen werden soll erhält der Autoloader folgende Klassennamen:

                  \Application\Core\Request
                  \Core\Library\Request

                  Wenn der Autoloader nun die Namespaces entfernt versucht er die Datei Request.class.php im Application Verzeichnis zu finden (mit Erfolg). Danach kommt das "... extends \Core\Library\Request" und versucht, weil die Namespaces entfernt werden, wieder die Request.class.php zu finden und findet diese wieder im Application Verzeichnis. Er versucht sich quasi mit sich selber zu extenden weil er nicht mehr weiss das der zweite Aufruf eigentlich im Core Verzeichnis gesucht werden soll anstatt im Application (weil Application ja bevorzugt werden soll).

                  Kommentar


                  • #10
                    denke, du müsstest deine Klassen die den richtigen code haben auf abstract setzen

                    PHP-Code:
                    namespace CoreLibrary;

                    abstract class 
                    Request
                    {

                    apt-get install npm -> npm install -g bower -> bower install <package> YOLO [URL]https://www.paypal.me/BlackScorp[/URL] | Mein Youtube PHP Kanal: [url]https://www.youtube.com/c/VitalijMik[/url]

                    Kommentar


                    • #11
                      Zitat von BlackScorp Beitrag anzeigen
                      denke, du müsstest deine Klassen die den richtigen code haben auf abstract setzen

                      PHP-Code:
                      namespace CoreLibrary;

                      abstract class 
                      Request
                      {

                      Jain. Drüber nach gedacht hatte ich, aber das gewünschte Verhalten soll ja so sein das die Request.class im Application Verzeichnis optional ist. Bedeutet also das wenn man den Core nicht erweitern will die Klasse Response nur im Core Verzeichnis existiert. Deswegen muss die Klasse auch aus dem Core instantiiert werden dürfen.

                      Kommentar


                      • #12
                        Und wenn man die Standard-Implementierung des Frameworks nutzen möchte?

                        Ich halte nicht viel von der Umsetzung des Autoloaders. Wenn ich einen qualifizierten bzw. vollständig qualifizierten Klassename angebe, erwarte ich auch, dass er mir die entsprechende Klasse lädt. Und nicht etwa, dass die Namespaces entfernt und nach Prioritäten aus verschiedenen Verzeichnissen geladen werden. Vor allem zwingst du damit eine feste Ordnerstruktur auf. Das eigentlich schöne an Frameworks mit gelungenen Autoloader-Implementierungen ist doch, dass man selbst die Ordnerstruktur der Applikation anders gestalten kann.

                        Kommentar


                        • #13
                          Warum machst du dir das so unnötig kompliziert? Wie Trainmaster schon richtig angedeutet hat, ist es viel einfacher und übersichtlicher, die zu benutzende(n) Klasse(n) direkt anzusprechen. Als Benutzer eines Frameworks muss ich mir doch selber darüber im Klaren sein, welche Request-Klasse ich nutzen möchte. Verwende ich die vorgegebene, so spreche ich diese explizit an. Verwende ich eine eigene Kreation, so wird eben diese direkt adressiert.

                          Kommentar


                          • #14
                            Zitat von stayInside Beitrag anzeigen
                            Jain. Drüber nach gedacht hatte ich, aber das gewünschte Verhalten soll ja so sein das die Request.class im Application Verzeichnis optional ist. Bedeutet also das wenn man den Core nicht erweitern will die Klasse Response nur im Core Verzeichnis existiert. Deswegen muss die Klasse auch aus dem Core instantiiert werden dürfen.
                            Im Kohana FW wird das so Realisiert, dass deine System klassen sich in einem FW Ordner befinden

                            https://github.com/kohana/core/blob/...na/Request.php
                            die zu überschreibenden klassen befinden sich davor

                            https://github.com/kohana/core/blob/...es/Request.php

                            wenn ich jetzt die Request klasse erweitern will, so erstelle ich eine Request klasse in Apppath oder modul path und extende diese von Kohana_Request
                            apt-get install npm -> npm install -g bower -> bower install <package> YOLO [URL]https://www.paypal.me/BlackScorp[/URL] | Mein Youtube PHP Kanal: [url]https://www.youtube.com/c/VitalijMik[/url]

                            Kommentar


                            • #15
                              So ähnlich machen es ja auch andere Frameworks ala CodeIgniter oder Fuel. Allerdings wird das ganze über den Klassennamen erreicht, was auch bei mir möglich wäre. Ich hingegen versuche es, sofern möglich, über Namespaces zu realisieren.

                              Kommentar

                              Lädt...
                              X