Ankündigung

Einklappen
Keine Ankündigung bisher.

Meine Autoload Klasse

Einklappen

Neue Werbung 2019

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

  • Meine Autoload Klasse

    Hallo,

    zur Zeit entwickel ich mein eigenes Framework. Dies dient überwiegend zum lernen, soll später aber auch als Grundlage für Projekte dienen.

    Da ich soeben meine Autoload-Klasse fertiggestellt habe (bisschen Doku und Fehler abfangen fehlt noch) möchte ich diese gerne mal öffentlich zur Diskussion stellen.

    Hier die Aufgaben die die Klasse erfüllen sollte:

    - Soll die Dateien automatisch in bestimmten Ordnern suchen und einbinden

    - Damit bei großen Ordner nicht jedesmal der Ordner durchsucht werden muss soll eine Cache Datei erstellt werden mit allen Klassenpfaden

    - Der Cache soll sich automatisch aktualisieren wenn eine neu erstellte Klasse aufgerufen wird

    PHP-Code:
    <?php

    /*
     * Verhindert das die Datei direkt aufgerufen werden kann
     */
    if (defined('SCRIPT') === false) die('The file can not be called directly!');

    final class 
    Autoload
    {
        
    /**
         * Beschreibung
         *
         * @static
         *
         * @var Autoload
         */
        
    private static $objInstance;

        
    /**
         * Beschreibung
         *
         * @var string
         */
        
    private $strExtension;

        
    /**
         * Beschreibung
         *
         * @var string
         */
        
    private $strCachePath;

        
    /**
         * Beschreibung
         *
         * @var array
         */
        
    private $arrRegister = array();

        
    /**
         * Beschreibung
         *
         * @var array
         */
        
    private $arrClassRegister = array();

        
    /**
         * Autoload::__clone()
         *
         * Beschreibung
         *
         * @author xxx
         *
         * @access private
         *
         * @final
         *
         * @return void
         */
        
    private final function __clone() {}

        
    /**
         * Autoload::__construct()
         *
         * Beschreibung
         *
         * @author xxx
         *
         * @access private
         *
         * @final
         *
         * @return void
         */
        
    private final function __construct() {}

        
    /**
         * Autoload::getInstance()
         *
         * Beschreibung
         *
         * @author xxx
         *
         * @access public
         *
         * @static
         * @final
         *
         * @return Autoload
         */
        
    public static final function getInstance()
        {
            if (
    is_object(self :: $objInstance) === false)
            {
                
    self :: $objInstance = new Autoload();
            }

            return (
    self :: $objInstance);
        }

        
    /**
         * Autpload::activate()
         *
         * Beschreibung
         *
         * @author xxx
         *
         * @access public
         *
         * @static
         * @final
         *
         * @return void
         */
        
    public function activate()
        {
            
    spl_autoload_register(array
            (
                
    $this,
                
    'load'
            
    ));
        }

        
    /**
         * Autpload::setExtension()
         *
         * Beschreibung
         *
         * @author xxx
         *
         * @access public
         *
         * @final
         *
         * @param string $strExtension
         *
         * @return void
         */
        
    public final function setExtension($strExtension)
        {
            
    $this->strExtension $strExtension;

            
    spl_autoload_extensions($strExtension);
        }

        
    /**
         * Autoload::setCacheFolder()
         *
         * Beschreibung
         *
         * @author xxx
         *
         * @access public
         *
         * @final
         *
         * @param string $strFolderPath
         *
         * @return boolean Bestätigung ob der Ordner gefunden werden konnte
         */
        
    public final function setCacheFolder($strFolderPath$blnCreateFolder true)
        {
            
    /*
             * Der Ordner ist nicht vorhanden und wird, wenn gewünscht, erstellt
             */
            
    if (is_dir($strFolderPath) === false &&
                
    $blnCreateFolder === true)
            {
                
    mkdir($strFolderPath0755true);
            }

            
    /*
             * Es konnte kein Ordner erstellt oder gefunden werden
             */
            
    if (is_dir($strFolderPath) === false)
            {
                return (
    false);
            }

            
    $this->strCachePath $strFolderPath;

            return (
    true);
        }

        
    /**
         * Autoload::register()
         *
         * Beschreibung
         *
         * @author xxx
         *
         * @access public
         *
         * @final
         *
         * @param string     $strPath
         * @param string     $strCacheName
         * @param boolean     $blnForceLoad
         *
         * @return void
         */
        
    public final function register($strPath$strCacheName null$blnForceLoad false)
        {
            
    /*
             * Der übergebene Ordner existiert nicht
             */
            
    if (is_dir($strPath) === false)
            {
                
    /*
                 * TODO: hier passiert noch was?
                 */
            
    }

            
    /*
             * Es wurde kein Cache-Name gewählt
             */
            
    if (empty($strCacheName) === true)
            {
                
    $strCacheName sha1($strCacheName);
            }

            
    /*
             * Der Cache-Name enthält ungültige Zeichen
             */
            
    if ((boolean) preg_match('#[^a-zA-Z0-9]#si'$strCacheName) === true)
            {
                
    /*
                 * TODO: hier passiert noch was?
                 */
            
    }

            
    /*
             * Der Pfad wird in der Registry gespeichert
             */
            
    $this->arrRegister[$strCacheName] = $strPath;

            
    /*
             * Es gibt bereits eine Cache-Datei zu diesem Name (Cache-Verzeichnis muss gesetzt sein) sofern das neu schreiben des Caches nicht erzwungen wird
             */
            
    if (empty($this->strCachePath) === false &&
                
    file_exists($this->strCachePath $strCacheName '.cache.php') &&
                
    $blnForceLoad === false)
            {
                return;
            }

            
    /*
             * Alle Dateien mit der entsprechenden Dateiendung im Ordner ermitteln
             */
            
    $objDirectory        = new RecursiveDirectoryIterator($strPath);
            
    $objIterator        = new RecursiveIteratorIterator($objDirectory);
            
    $objRegexIterator    = new RegexIterator($objIterator'#^.+' preg_quote($this->strExtension'#') . '$#si'RecursiveRegexIterator :: GET_MATCH);

            
    /*
             * Wenn der Cache aktiviert ist oder der Cache aktiviert und erzwungen wird
             */
            
    if (empty($this->strCachePath) === false ||
                (empty(
    $this->strCachePath) === false && $blnForceLoad === true))
            {
                
    $this->writeCache($strCacheName$objRegexIterator);
            }
            else
            {
                
    $this->writeClassRegisterFromIterator($objRegexIterator);
            }
        }

        
    /**
         * Autoload::loadCache()
         *
         * Beschreibung
         *
         * @author xxx
         *
         * @access private
         *
         * @final
         *
         * @return void
         */
        
    private final function loadCache()
        {
            
    /*
             * Cache-Dateien ermitteln
             */
            
    $objDirectory        = new RecursiveDirectoryIterator($this->strCachePath);
            
    $objIterator        = new RecursiveIteratorIterator($objDirectory);
            
    $objRegexIterator   = new RegexIterator($objIterator'#^.*' preg_quote('.cache.php''#') . '$#si'RecursiveRegexIterator :: GET_MATCH);

            foreach (
    $objRegexIterator as $arrCacheFilePath)
            {
                if (
    file_exists($arrCacheFilePath[0]) === true)
                {
                    include (
    $arrCacheFilePath[0]);

                    
    $arrCache = (array) unserialize($arrCache);

                    
    $this->writeClassRegisterFromCache($arrCache);
                }
            }
        }

        
    /**
         * Autoload::writeCache()
         *
         * Beschreibung
         *
         * @author xxx
         *
         * @access private
         *
         * @final
         *
         * @param string $strCacheName
         * @param RegexIterator $objRegexIterator
         *
         * @return void
         */
        
    private final function writeCache($strCacheNameRegexIterator $objRegexIterator)
        {
            
    $strCacheFile $this->strCachePath $strCacheName '.cache.php';

            
    $resHandle fopen($strCacheFile'w+');

            
    /*
             * Es konnte kein Stream zur Datei aufgebaut werden
             */
            
    if (is_resource($resHandle) === false)
            {
                
    /*
                 * TODO: hier passiert noch was?
                 */
            
    }

            
    /*
             * Die Datei kann nicht geschrieben werden
             */
            
    if (is_writeable($strCacheFile) === false)
            {
                
    /*
                 * TODO: hier passiert noch was?
                 */
            
    }

            
    $arrCache = array();

            foreach (
    $objRegexIterator as $arrPath)
            {
                
    $strBasename basename($arrPath[0]);
                
    $strBasename mb_substr($strBasename0mb_stripos($strBasename'.'));

                
    $arrCache[$strBasename] = $arrPath[0];
            }

            
    fputs($resHandle'<?php $arrCache = \'' .serialize($arrCache) . '\'; ?>');

            
    fclose($resHandle);
        }

        
    /**
         * Autoload::writeClassRegisterFromIterator()
         *
         * Beschreibung
         *
         * @author xxx
         *
         * @access private
         *
         * @final
         *
         * @param RegexIterator $objRegexIterator
         *
         * @return void
         */
        
    private final function writeClassRegisterFromIterator(RegexIterator $objRegexIterator)
        {
            foreach (
    $objRegexIterator as $arrPath)
            {
                
    /*
                 * Der Klassenname wird aus dem Pfad ermittelt
                 */
                
    $strBasename basename($arrPath[0]);
                
    $strBasename mb_substr($strBasename0mb_stripos($strBasename'.'));

                
    $this->arrClassRegister[$strBasename] = $arrPath[0];
            }
        }

        
    /**
         * Autoload::writeClassRegisterFromCache()
         *
         * Beschreibung
         *
         * @author xxx
         *
         * @access private
         *
         * @final
         *
         * @param array $arrCache
         *
         * @return void
         */
        
    private final function writeClassRegisterFromCache(array $arrCache)
        {
            foreach (
    $arrCache as $strClassName => $strClassPath)
            {
                
    $this->arrClassRegister[$strClassName] = $strClassPath;
            }
        }

        
    /**
         * Autoload::load()
         *
         * Beschreibung
         *
         * @author xxx
         *
         * @access private
         *
         * @final
         *
         * @param string     $strClass
         * @param boolean     $blnRecursive
         *
         * @return boolean
         */
        
    private final function load($strClass$blnRecursive false)
        {
            
    /*
             * Wenn ein Cache-Verzeichnis gesetzt ist wird versucht der Cache zu laden
             */
            
    if (empty($this->strCachePath) === false &&
                empty(
    $this->arrClassRegister) === true)
            {
                
    $this->loadCache();
            }

            
    /*
             * Die Datei mit dem Klassennamen existiert
             */
            
    if (empty($this->arrClassRegister[$strClass]) === false &&
                
    file_exists($this->arrClassRegister[$strClass]) === true)
            {
                require_once (
    $this->arrClassRegister[$strClass]);
            }

            
    /*
             * Es wird einmal versucht die Klasse zu ermitteln indem der Cache aktualisiert wird
             */
            
    else if ($blnRecursive === false)
            {
                foreach (
    $this->arrRegister as $strCache => $strCachePath)
                {
                    
    $this->register($strCachePath$strCachetrue);
                }

                return (
    $this->load($strClasstrue));
            }

            
    /*
             * Die Klasse existiert in dieser Datei nicht
             */
            
    if (class_exists($strClassfalse) === false)
            {
                
    trigger_error('Möp');

                return (
    false);
            }

            return (
    true);
        }
    }

    ?>
    Hier mal ein Beispiel wie man die Klasse benutzt:

    PHP-Code:
    $objAutoload Autoload :: getInstance();

    /*
     * Dateiendung für den Autoloader festlegen
     */
    $objAutoload->setExtension('.class.php');

    /*
     * Cacheverzeichnis für den Autloader festlegen
     */
    $objAutoload->setCacheFolder(Registry :: get('CacheAutoloadPath'));

    /*
     * Verzeichnisse und Cachenamen für den Autoloader festlegen
     */
    $objAutoload->register(Registry :: get('CoreLibraryPath'),                'CoreLibrary');
    $objAutoload->register(Registry :: get('CoreInterfacePath'),            'CoreInterface');
    $objAutoload->register(Registry :: get('ApplicationControllerPath'),    'ApplicationController');

    /*
     * Autoloader aktivieren
     */
    $objAutoload->activate(); 
    So, dann sagt mal eure Meinung, egal ob positiv oder negativ.

  • #2
    Hallo,

    ich würde kein trigger_error() verwenden, sondern eine Exception werfen. Ansonsten möchte ich den Code nicht beurteilen, da ich das Autoloading-Konzept für absoluten Schwachsinn halte. Es verstümmelt Klassen-Namen zwingt flache Strukturen auf und verhindert damit jedwede Freiheit hinsichtlich vernünftiger Strukturiering von Quellcode.
    Viele Grüße,
    Dr.E.

    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    1. Think about software design [B]before[/B] you start to write code!
    2. Discuss and review it together with [B]experts[/B]!
    3. Choose [B]good[/B] tools (-> [URL="http://adventure-php-framework.org/Seite/088-Why-APF"]Adventure PHP Framework (APF)[/URL][URL="http://adventure-php-framework.org"][/URL])!
    4. Write [I][B]clean and reusable[/B][/I] software only!
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    Kommentar


    • #3
      Moin Dr. E.,

      ich versuche seit einiger Zeit meine Anwendungen komplett objektorientiert umzusetzen und lade meine Klassen auch via Autoloader (SPL) in die Anwendung. Könntest Du mir bitte nachfolgendes Statement ein wenig erläutern?

      Zitat von dr.e. Beitrag anzeigen
      ...Es verstümmelt Klassen-Namen zwingt flache Strukturen auf und verhindert damit jedwede Freiheit hinsichtlich vernünftiger Strukturiering von Quellcode...
      Ich bedanke mich.

      Kommentar


      • #4
        Zitat von dr.e. Beitrag anzeigen
        Hallo,

        ich würde kein trigger_error() verwenden, sondern eine Exception werfen. Ansonsten möchte ich den Code nicht beurteilen, da ich das Autoloading-Konzept für absoluten Schwachsinn halte. Es verstümmelt Klassen-Namen zwingt flache Strukturen auf und verhindert damit jedwede Freiheit hinsichtlich vernünftiger Strukturiering von Quellcode.
        Hallo Doc,

        könntest du das vieleicht etwas nähe begründen? Würde mich mal interessieren warum du so denkst und was du für die bessere Alternative hältst.

        Danke dir. Gruß Litter
        Aus dem Dynamo Lande kommen wir. Trinken immer reichlich kühles Bier. Und dann sind wir alle voll, die Stimmung ist so toll. Aus dem Dynamo Lande kommen wir.
        [URL]http://www.lit-web.de[/URL]

        Kommentar


        • #5
          Ein paar Kleinigkeiten, die mir aufgefallen sind:

          1. final function in final class - nicht schlimm aber irgendwie doppelt gemoppelt

          2. warum der explizite Aufruf von activate()? Ich würde dies im Konstruktor machen, denn du wirst den Autoloader wohl kaum instantiieren wenn du nicht beabsichtigst, ihn zu verwenden.

          3.
          PHP-Code:
                  /*
                   * Es wurde kein Cache-Name gewählt
                   */
                  
          if (empty($strCacheName) === true)
                  {
                      
          $strCacheName sha1($strCacheName);
                  } 
          Ergibt so keinen Sinn, ich nehme an, du meinst sha1($strPath)? Außerdem: empty() gibt immer boolean zurück, === true kannst du dir also sparen.

          4. Allgemein ist die Verwendung von === begrüßenswert aber mit deinem === true in den if-Statements übertreibst du es IMHO. Besonders schön sieht man das hier:
          PHP-Code:
          if ((boolean) preg_match('#[^a-zA-Z0-9]#si'$strCacheName) === true
          preg_match gibt immer entweder 1 oder 0 zurück, was wunderbar ohne weiteres als boolean true oder false interpretiert wird, du castest aber erst noch um unbedingt einen echten boolean zu haben und hängst dann noch ein völlig renundantes === true dran. Selbst in Java wäre das übertrieben

          5. vielleicht Geschmackssache aber bei solchen Cache-Files finde ich es schöner, return zu benutzen anstatt Variablen zu belegen, so ist auch im Code direkt ersichtlich woher der Wert kommt ($arrCache muss man bei dir erstmal suchen).
          PHP-Code:
          // generated cache file
          <?php return array(...); ?>

          // loadCache method
          <?php
          ...
          $arrCache = include($arrCacheFilePath[0]); 
          ...
          ?>
          Wie gesagt, Kleinigkeiten. Ansonsten erscheint mir das Konzept mit dem Caching auf den ersten Blick recht schlüssig, was mir fehlen würde ist Namespace-Unterstützung oder übersehe ich etwas?
          [IMG]https://g.twimg.com/twitter-bird-16x16.png[/IMG][URL="https://twitter.com/fschmengler"]@fschmengler[/URL] - [IMG]https://i.stack.imgur.com/qh235.png[/IMG][URL="https://stackoverflow.com/users/664108/fschmengler"]@fschmengler[/URL] - [IMG]http://i.imgur.com/ZEqflLv.png[/IMG] [URL="https://github.com/schmengler/"]@schmengler[/URL]
          [URL="http://www.schmengler-se.de/"]PHP Blog[/URL] - [URL="http://www.schmengler-se.de/magento-entwicklung/"]Magento Entwicklung[/URL] - [URL="http://www.css3d.net/"]CSS Ribbon Generator[/URL]

          Kommentar


          • #6
            Ich würde sogar noch weiter gehen. Durch die eine Variable die dort übergeben wird:
            PHP-Code:
                            include ($arrCacheFilePath[0]);

                            
            $arrCache = (array) unserialize($arrCache); 
            gibt es eigentlich keinen Vorteil gegenüber dieser Lösung:
            PHP-Code:
                            $arrCache unserialize(file_get_contents ($arrCacheFilePath[0])); 
            Vorteil: Ein unvollständiges Cachefile schießt mir nicht die Anwendung ab.
            Einen serialisierten String als Variable abzulegen und das zu includen ist irgendwie doppelt gemoppelt.

            Ansonsten stören mich an der Klasse die massiven Filesystemzugriffe. Wieso kann man nicht alles in einem Cachefile ablegen oder die Handvoll Registrierungen einfach als Array zuweisen?
            [COLOR="#F5F5FF"]--[/COLOR]
            [COLOR="Gray"][SIZE="6"][FONT="Georgia"][B]^^ O.O[/B][/FONT] [/SIZE]
            „Emoticons machen einen Beitrag etwas freundlicher. Deine wirken zwar fachlich richtig sein, aber meist ziemlich uninteressant.
            [URL="http://www.php.de/javascript-ajax-und-mehr/107400-draggable-sorttable-setattribute.html#post788799"][B]Wenn man nur Text sieht, haben viele junge Entwickler keine interesse, diese stumpfen Texte zu lesen.“[/B][/URL][/COLOR]
            [COLOR="#F5F5FF"]
            --[/COLOR]

            Kommentar


            • #7
              Hallo Alec32, hallo litter,

              der Autoload-Mechanismus von PHP ist die Idee, Klassen-Namen zu nutzen um die zugehörige Implementierung zu laden. Sofern der Anspruch besteht, den Code einer Anwendung hinsichtlich seiner Nutzung, seiner Bedeutung und seiner Abhängigkeit zu strukturieren, ist man gezwungen, diese Strukturen in den Klassen-Namen abzubilden. Seinen Höhepunkt erreicht das im Autoloading des ZF, in dem die Namespaces in den Klassen abgebildet sind (z.B. Zend_Foo_Bar, das auf Zend/Foo/Bar.php mappt). Damit sind Klassen-Namen nicht nur unaussprechlich, sondern IMHO auch falsch hinsichtlich des OO-Gadankens, die Realität abbilden zu wollen.
              Möchte ich mit Autoloading nun eine Klasse Frontcontroller aus dem Namespace core::frontcontroller laden müsste ich diese entweder Core_Frontcontroller_Frontcontroller nennen oder auf explizite Abhängigkeits-Definition (=require/include/...) ausweichen. Letzteres halte ich bei den aktuellen Mitteln, die mir PHP 5.2.X bietet für die deutlich bessere Variante.

              Sollte sich PHP 5.3.X in vielleicht einem Jahr durchgesetzt haben, so könnte man drüber nachdenken, Autoloading vielleicht doch zu nutzen, denn ein

              PHP-Code:
              use core\frontcontroller\Frontcontroller 
              würde dann den kompletten Namespace und die Klasse selbst beinhalten. Dies lässt sich dann zum jeweils relevanten Datei-Namen der Klassen-Implementierung auflösen und die Klasse einbinden. Dies ist jedoch auch in PHP 5.3.X nicht möglich, wenn ich einfach nur ein

              PHP-Code:
              $fC = new Frontcontroller(); 
              im Code notiere. Davon abgesehen, ist es - hierbei bin ich ein Fan von JAVA und C# - für die bewusste Implementierung ohnehin schlauer, Abhängigkeiten explizit zu definieren. Das macht nicht nur klar, was ich hier nutzen möchte, sondern erleichtert es auch statischen Code-Analyse-Werkzeugen Abhängigkeiten (vielleicht auch zirkulärer Art) zu erkennen und zu bewerten.

              Aus eben den genannten Gründen setzt das APF auf statische Abhängigkeiten und verzichtet auf Autoloading. Sofern du eine vernünftige IDE einsetzt ist das auch weiter kein Problem, da ohnehin alle Klassen für intelli sense indiziert sind und du damit dahingehend keine Nachteile beim Entwickeln hast.

              Meiner Ansicht nach taugt Autoload/SPL Autoload solange nichts, bis nicht eine Integration von Namespaces stattgefunden hat und eine Klasse nicht mehr nur durch ihren Namen sondern vor allem durch ihren Namespace und Namen adressiert werden muss. In PHP 5.3.X ist das Adressieren ja schon möglich aber nicht zwingend notwendig. Nutzt man use, oder explizite Instanziierungen kann Autoloading nützlich sein, rund ist das Feature aber IMHO noch lange nicht.

              Bis dahin bleibe ich ein Fan von expliziten Abhängigkeiten.
              Viele Grüße,
              Dr.E.

              ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
              1. Think about software design [B]before[/B] you start to write code!
              2. Discuss and review it together with [B]experts[/B]!
              3. Choose [B]good[/B] tools (-> [URL="http://adventure-php-framework.org/Seite/088-Why-APF"]Adventure PHP Framework (APF)[/URL][URL="http://adventure-php-framework.org"][/URL])!
              4. Write [I][B]clean and reusable[/B][/I] software only!
              ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

              Kommentar


              • #8
                Zitat von dr.e. Beitrag anzeigen
                Bis dahin bleibe ich ein Fan von expliziten Abhängigkeiten.
                Das heißt du notierst im Code wo du es brauchst z.B.

                PHP-Code:
                include 'FrontController.php'
                Habe ich das richtig verstanden?

                Ich frage deshalb, weil ich grad anfange meine ersten Schritte mit MVC zu machen. Ich habe einen FrontController und lade da momentan durch Adressierung aus der URL meine Models, Subcontroller und Views die ich brauche. Das heist anhand eines in der URL stehenden Parameters. Diesen Parameter oder auch 2, jenachdem, habe ich dann in der Dateibenamung und im Klassennamen stehen. Momentan funktioniert das auch gut, aber wenn ich eben so deine Zeilen lese bekomme ich grad doch ein wenig Zweifel ob das so der richtige Weg ist.
                Aus dem Dynamo Lande kommen wir. Trinken immer reichlich kühles Bier. Und dann sind wir alle voll, die Stimmung ist so toll. Aus dem Dynamo Lande kommen wir.
                [URL]http://www.lit-web.de[/URL]

                Kommentar


                • #9
                  Zitat von fab Beitrag anzeigen
                  Ein paar Kleinigkeiten, die mir aufgefallen sind:

                  1. final function in final class - nicht schlimm aber irgendwie doppelt gemoppelt

                  2. warum der explizite Aufruf von activate()? Ich würde dies im Konstruktor machen, denn du wirst den Autoloader wohl kaum instantiieren wenn du nicht beabsichtigst, ihn zu verwenden.

                  3.
                  PHP-Code:
                          /*
                           * Es wurde kein Cache-Name gewählt
                           */
                          
                  if (empty($strCacheName) === true)
                          {
                              
                  $strCacheName sha1($strCacheName);
                          } 
                  Ergibt so keinen Sinn, ich nehme an, du meinst sha1($strPath)? Außerdem: empty() gibt immer boolean zurück, === true kannst du dir also sparen.

                  4. Allgemein ist die Verwendung von === begrüßenswert aber mit deinem === true in den if-Statements übertreibst du es IMHO. Besonders schön sieht man das hier:
                  PHP-Code:
                  if ((boolean) preg_match('#[^a-zA-Z0-9]#si'$strCacheName) === true
                  preg_match gibt immer entweder 1 oder 0 zurück, was wunderbar ohne weiteres als boolean true oder false interpretiert wird, du castest aber erst noch um unbedingt einen echten boolean zu haben und hängst dann noch ein völlig renundantes === true dran. Selbst in Java wäre das übertrieben

                  5. vielleicht Geschmackssache aber bei solchen Cache-Files finde ich es schöner, return zu benutzen anstatt Variablen zu belegen, so ist auch im Code direkt ersichtlich woher der Wert kommt ($arrCache muss man bei dir erstmal suchen).
                  PHP-Code:
                  // generated cache file
                  <?php return array(...); ?>

                  // loadCache method
                  <?php
                  ...
                  $arrCache = include($arrCacheFilePath[0]); 
                  ...
                  ?>
                  Wie gesagt, Kleinigkeiten. Ansonsten erscheint mir das Konzept mit dem Caching auf den ersten Blick recht schlüssig, was mir fehlen würde ist Namespace-Unterstützung oder übersehe ich etwas?
                  1. Klingt logisch. Habe ich bislang noch nicht drüber nachgedacht gehabt.

                  2. Ich hatte es erst im Konstruktor, habe dann allerdings die activate() eingepflegt weil ich vor dem aktivieren noch ein paar Sachen prüfen wollte (Einstellungen alle gültig etc.). Aber da dies direkt in den jeweiligen Methoden schon gemacht wird wird die activate() wieder in den Konstruktor verfrachtet.

                  3. Stimmt, sollte $strPath sein. Code den man Nachts um 3 produziert sollte man wirklich am nächsten Tag nochmal kontrollieren

                  4. Angewohnheit von mir. Ich prüfe stets mit === um Typenfehler zu vermeiden, bei dem preg_match() sehe ich es aber ein das es Schwachsinn ist.

                  5. Ich war lange am überlegen wie ich verdeutlichen kann woher $arrCache kommt, kam aber bislang nie auf eine Lösung, danke für den Denkanstoß. Wobei ich da das Vorgehen von nikosch eher bevorzuge. Das spart auch nochmal ein paar Bytes (PHP Tag etc.) und bindet mich nicht an eine .php Endung.


                  Ansonsten muss ich sagen das dr.e mich zum nachdenken gebracht hat, besonders der folgende Satz

                  Davon abgesehen, ist es - hierbei bin ich ein Fan von JAVA und C# - für die bewusste Implementierung ohnehin schlauer, Abhängigkeiten explizit zu definieren. Das macht nicht nur klar, was ich hier nutzen möchte, sondern erleichtert es auch statischen Code-Analyse-Werkzeugen Abhängigkeiten (vielleicht auch zirkulärer Art) zu erkennen und zu bewerten.
                  Mal schauen was sich aus dieser Diskussion noch so wird.

                  Kommentar


                  • #10
                    @litter:

                    Habe ich das richtig verstanden?
                    Korrekt.

                    Ich frage deshalb, weil ich grad anfange meine ersten Schritte mit MVC zu machen. Ich habe einen FrontController und lade da momentan durch Adressierung aus der URL meine Models, Subcontroller und Views die ich brauche.
                    Das ist prinzipiell eine valide Vorgehensweise. MVC wird oft zusammen mit dem Frontcontroller-Pattern implementiert, da gewisse Probleme nicht direkt mit MVC zu tun haben, jedoch auch generisch abgebildet werden sollten. Implementierst du ein hierarchisches MVC-Modell sind wieder andere Mechanismen notwendig. Was oft missinterpretiert wird ist, dass der Frontcontroller (mehr oder weniger) zu MVC gehört. Um das bei deiner Implementierung aber genauer beurteilen zu können, müsste ich mir den Code mal ansehen. "Subcontroller" klingt mir aber nach einem hierarchischen Modell bzw. einer Vermischung von MVC und Frontcontroller, was nicht in jedem Fall korrekt ist. MVC ist nur dann korrekt interpretiert, wenn du zwischen Front-Controller-Command bzw. -Action unterscheidest. Die Front-Controller-Action kannst du dann als Router oder Input-Filter nutzten der den MVC-Controller ausführt. Der Frontcontroller - das hatte ich in einer Diskussion neulich schon mal angesprochen - darf nichts von MVC selbst wissen, sonst ist er nicht generisch einsetztbar.

                    Aus den genannten Gründen trennt das APF beispielsweise zwischen Front-Controller, der das gleichnamige Pattern generisch implementiert und einem Page-Controller, der sich um das (H)MVC kümmert. So kannst du den Front-Controller in vielen Applikationen ohne Software-Änderung einsetzen. Gleiches gilt für den Page-Controller, der noch dazu den Vorteil bietet, HMVC zu ermöglichen. Damit bist du noch ein Stück weiter unabhängig in deinem URL-Layout (siehe unten).

                    Das heist anhand eines in der URL stehenden Parameters. Diesen Parameter oder auch 2, jenachdem, habe ich dann in der Dateibenamung und im Klassennamen stehen. Momentan funktioniert das auch gut, aber wenn ich eben so deine Zeilen lese bekomme ich grad doch ein wenig Zweifel ob das so der richtige Weg ist.
                    Ich würde die URL nie 1:1 auf Klassen abbilden. Einige Implementierungen von MVC handhaben das so, dass ein /index eine IndexAction aufruft oder ein /foo/bar die Methode FooAction::bar(). Das ist in meinen Augen aber ein Fehler, denn du machst dein URL-Layout abhängig von deiner technischen Umsetzung. Möchtest du die URL nun aus SEO- oder aus Konsistenz-Gründen anpassen, ändern oder redesignen, dann hast änderst du zig Stellen im Code. Das muss meiner Ansicht nach transparent gehalten werden.

                    Aus diesem Grund besitzt das APF beispielsweise Input- und Output-Filter, die das URL-Layout von einer externen Repräsentation in eine interne übersetzten können. So ist es ohne eine Zeile Software-Änderung möglich von einem auf das andere Layout zu switchen.

                    Darf ich fragen, wie du dir MVC gerade zu gemüte führst? Nutzt du ein Framework oder eine eigene Implementierung?
                    Viele Grüße,
                    Dr.E.

                    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                    1. Think about software design [B]before[/B] you start to write code!
                    2. Discuss and review it together with [B]experts[/B]!
                    3. Choose [B]good[/B] tools (-> [URL="http://adventure-php-framework.org/Seite/088-Why-APF"]Adventure PHP Framework (APF)[/URL][URL="http://adventure-php-framework.org"][/URL])!
                    4. Write [I][B]clean and reusable[/B][/I] software only!
                    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

                    Kommentar


                    • #11
                      Anhand meines Praktikums eine eher eigene Implementierung. Meine Chefin hat sich viel Mühe gegeben mir da was beizubiegen und das versuche ich nun umzusetzen. Wenn es soweit ist dann poste ich dir bzw. hier im Forum auf alle Fälle mal den Code. Momentan ist nur ein Beispiel anhand eines simplen Gästebuches, halt zur Übung um überhaupt erst mal ein Gefühl zu bekommen.

                      Momentan habe ich das so, ich habe einen frontController der so mit meinem MVC nichts weiter eigentlich zu tun hat. Über meine URL (hast du ja gesagt ist nicht so gut) lade ich zum Beispiel anhand eines Modul (?modul=) ein Model, View, Controller für die Darstellung des Index. Wenn ich nun z.B. einen Link klicke um zum Eintragsformular zu gelangen für einen neuen Eintrag lade ich anhand des action (?modul=gb&action=newEntry) meine Klassen NewEntryDatabaseModel, NewEntryController, NewEntryView. So war mein Grundgedanke dafür. Das heißt mein FrontController weiß von meiner MVC Implementierung nichts sondern lädt Klassen bzw. MVC Komponenten anhand der URL Adressierung. Daher denke ich bin ich schon ein wenig flexibel.

                      Was mich interessieren würde wie man, wenn man über URL Adressierung seine Klassen lädt das so übersetzen kann das es nun allgemein flexibel einsetzen kann. Denn soweit wie ich das gelernt oder besser gesagt verstanden habe sind Models, Controllers und Views ja doch immer Anwendungsspeziel. Ode rliege ich da falsch?

                      Gruß Litter
                      Aus dem Dynamo Lande kommen wir. Trinken immer reichlich kühles Bier. Und dann sind wir alle voll, die Stimmung ist so toll. Aus dem Dynamo Lande kommen wir.
                      [URL]http://www.lit-web.de[/URL]

                      Kommentar


                      • #12
                        Hallo litter,

                        Denn soweit wie ich das gelernt oder besser gesagt verstanden habe sind Models, Controllers und Views ja doch immer Anwendungsspeziel. Ode rliege ich da falsch?
                        MVC-Elemente sind Anwendungs-spezifisch - korrekt. Deshalb sollte man versuchen, die Problem-Domäne zu abstrahieren. Einmal hast du das mit dem Front-Controller ja schon getan, andererseits sollte (auch aus meiner Erfahrung bestätigt) MVC an sich abstrahiert werden, denn in dieserm Bereich gibt es auch immer wieder gleichartige Aufgaben und Verhaltensweisen über Anwendungen hinweg. Ein Punkt ist das Thema Routing/URL-Mapping in einem statischen MVC-Modell so wie du es beschreibst. Das lässt sich recht einfach in eine eigene Action packen, die für jede Anwendung wieder eingesetzt werden kann - durch Konfiguration "personalisiert". Beim APF übernimmt diesen Job der Page-Controller, der sich um das Gerüst der Seite, dessen Views und Controller kümmert.

                        Treibst du das weiter, schickt es sich dafür eine Komponente einzusetzen, die sowohl das Management von MVC- oder gleich HMVC - übernimmt als sich auch in ein Konstrukt einpasst, das hinsichtlich der URL-Abstraktion unterstützt. Gerade das URL-Mapping bzw. -Layout ist ein Thema, was meiner Ansicht nach durch viele MVC-Umsetzungen (1:1-Mapping auf Controller) sehr strapaziert wird. Hier fordere ich eine Abstraktion über Input- und Output-Filter. Somit ist es nicht notwendig, einen Controller in der URL zu definieren, sondern dieser kann ganz einfach durch das Gesamtkonstrukt implizit oder durch die codierte URL mehr oder weniger explizit definiert werden. Damit schränkst du dich auch nicht in der Länge der URL ein, wenn du in einer komplexen Applikation mehrere Controller brauchst oder must Krücken wie View-Helper zu Hilfe nehmen, die nichts weiter tun als die Wiederverwendbarkeit kaputt zu machen. Such mal im Software-Design-Forum nach Beiträgen zum Thema URL-Layout, wir haben das Thema schon sehr ausführlich diskutiert.

                        Ein konkretes Beispiel für ein Mapping kommt wieder auf den Anwendungsfall an, kann aber grundsätzlich sehr einfach sein, denn das APF basiert beispielsweise auf dem Paradigma, dass nur die effektiv notwendigen Parameter in der URL enthalten sein müssen. Es ist nicht notwendig, alle Controller/Views in der URL zu codieren, die in einem HMVC-Baum notwendig sind. Nehmen wir an, du hast eine Seite mit einem Header, einem Menü und einem Content-Bereich und auch das Haupt-Template (in vielen MVC-Implementierungen auch "Layout" genannt). Das erfordert nach MVC 4 Views und Controller - vielleicht 1-2 Models. Musst du das in der URL abbilden, braucht es 4 Parameter, zur Ansteuerung der Impressum-Seite ist effektiv aber nur 1 Parameter notwendig. Genau diesen solltest du auch in der URL haben und das ist auch kein Problem, da die 3 anderen entweder durch die Struktur des Baumes oder der expliziten Auszeichnung in der URL definiert sind. Hierbei muss jedoch nicht der Controller in der URL definiert sein, sondern Parameter, die auf die Steuerung des Baumes Einfluss haben (z.B. Seite 2 anzeigen, ...).

                        Wenn dich das Konzept näher interessiert - es bietet meiner Meinung nach wirklich die größte Flexibilität -, können wir uns gerne in einem anderen Thread drüber unterhalten. Ich würde den Thread hier ungern hijacken.
                        Viele Grüße,
                        Dr.E.

                        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                        1. Think about software design [B]before[/B] you start to write code!
                        2. Discuss and review it together with [B]experts[/B]!
                        3. Choose [B]good[/B] tools (-> [URL="http://adventure-php-framework.org/Seite/088-Why-APF"]Adventure PHP Framework (APF)[/URL][URL="http://adventure-php-framework.org"][/URL])!
                        4. Write [I][B]clean and reusable[/B][/I] software only!
                        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

                        Kommentar

                        Lädt...
                        X