Blog zu meinem PHP Framework

Notizen zu meinem PHP Framework die Anwendungen in PHP betreffend [PHP]

Enctype application/x-www-form-urlencoded und Prozentkodierung

$q = http_build_query( array(
    'foo[a]'  => 123,
    'foo[b]'  => 'bar',
    'name' => 'boo',
    'amt'  => '€ 2.59'
) );

$res = array();
parse_str ( $q, &$res );

echo $q, print_r($res,1);

foo%5Ba%5D=123&foo%5Bb%5D=bar&name=boo&amt=%E2%82%AC+2.59
Array
(
    [foo] => Array
        (
            [a] => 123
            [b] => bar
        )

    [name] => boo
    [amt] => € 2.59
)

Mein Framework als MVC

Die Programmstruktur meines Framework besitzt sämtlichen Merkmale die einen MVC charakterisiert.

Modell

Bei jedem Request wird eine Instanz derjenigen Klasse erzeugt die per Konfiguration/Routingtable an den URL gebunden ist. Diese Instanz implementiert das Modell und besitzt Methoden zur Datenbeschaffung und Methoden die das View erzeugen und dazu bspw. ein Template rendern..

View

Je nach Request, Klasse und Konfiguration wird ein jedes View mit einem bestimmten Content-Type erstellt und ausgeliefert. In der Regel lautet der Content-Type: text/html.

Controller

In meinem FW Ist der Kontroller eine Methode der Instanz derjenigen Klasse welche per´statische Route an den URL gebunden ist.

MVC by PHP + MySQL

In einem anderen Forum: Hat sich doch mal einer darüber mockiert, daß Perl gar kein richtiges OOP kann sondern daß da nur Referenzen mit dem Namen einer Klasse gesegnet werden. Was er nicht sagt! Aber gucken wir mal was PHP da macht:

public PDOStatement::fetchObject ([ string $class_name = "stdClass" [, array $ctor_args ]] ) : mixed

Ach!

# Und so geht das dann:
class main{
    public $FILEDIR = "d:/home/files";
    function selfdump(){
        print_r($this);
    }
}
require "factory/_dbh.php";
$m = new main();
$pdo = _dbh( $m, array('myweb') );
$sth = $pdo->prepare("SELECT * FROM forum WHERE mesgid=39");
$sth->execute();
$r = $sth->fetchObject('main'); # Gebe den Namen einer Klasse mit
$r->selfdump();

WOW: Die Daten können Methoden aufrufen! Na dann auf zum MVC by PHP+MySQL. Immerhin wird über den PDO::STH der Konstruktor der angegebenen Klasse gerufen die auch als Code vorliegen muss. Da werden auch sämtliche Eigenschaften zugewiesen.

Template Engineering

Wenn es für eine Antwortseite erforderlich ist, ermöglicht das Framework den Austausch des kompletten BODY-Templates. Darüber hinaus ermöglicht die eingesetzte Templating-Engine die Anwendung einfacher Kontollstrukturen innerhalb eines Templates, so können einzelne Abschnitte eines Templates ein- oder ausgeblendet werden, je nachdem was das MVC-Datenmodell für die Sicht auf die Response (Antwortseite) vorsieht.

Codeverteilung im Wandel der Zeit

Codeverteilung

Das Bild zeigt die Entwicklung der Codeverteilung für mein Framework. In den Versionen 1 und 2 meines FW wurde bei jedem Request sämtlicher Code kompiliert, auch Code für Anwendungen, die nicht requested wurden. Gerouted wurde jedoch auch bereits in den ersten Versionen statisch anhand der Klassenbindung.

Erst die Version 3 brachte infolge konsequenter Anwendung der Vererbung hinsichtlich der Codeverteilung den entscheidenden Durchbruch. Was sich natürlich auch bestens auf die Performance auswirkt. Kompliliert wird nur noch der Code welcher zum Ausführen der requesteten Anwendung erforderlich ist.

Infolge weiterer Teilung des Codes und Auslagerung dessen in eine Factory konnte die Effizienz weiter gesteigert werden. So ist die Aufteilung von Code in Methoden der Factory die konsequente Fortsetzung der Organisation von Code in Klassen.

Ein typisches Beispiel für eine Methode der Factory ist eine Funktion zur Herstellung einer Sitzung mit MySQL. Charakteristisch deswegen weil eine MySQL Verbindung in nur wenigen Anwendungen gebraucht wird.

Des Weiteren werden durch die nun auch in PHP angewandte Klassenhierarchie + Factory Coderedundanzen nicht nur weitgehend sondern generell vermieden.

Aktuell werden 376 Seiten einschließlich Anwendungen vom Framework/Version 3 ausgeliefert und die meisten Seiten über eine gemeinsame Klasse (Common-Class). Anwendungen haben entweder eine eigene Klasse oder ein zur Common-Class hinzukonfiguriertes Interface (Trait). Welche Komponenten das sind, verrät ein Blick in den Quelltext einer jeden Seite.

Anwendungen für dieses Framework entwickeln heißt, ein Plugin zu enwickeln was entweder eine dedizierte Klasse sein kann oder ein Trait. So lassen sich Erweiterungen innerhalb extrem kurzen Zeiten entwickeln und in der Regel genügen dazu Grundkenntnisse der jeweiligen Programmiersprache.

Astronomie

Kaum zu glauben, PHP kennt Sonnenauf- und Untergang als Builtinfunktion. Sonnenaufgang: 06:05 Uhr, Sonnenuntergang: 18:55 Uhr, diese Angaben sind für Frankfurt/Main und natürlich aktuell für den heutigen Tag (01.04.2020).

Traits und eine Factory

Wie schon im Perl-Framework, habe ich die Factory für das PHP-Framework in Traits organisiert. So wird der Code für Methoden, die nicht im Namespace der Klasse definiert sind, aus dem Dateisystem nachgeladen und ausgeführt. Um bspw. ein Database-Handle (PDO-Objekt) zu bekommen genügt ein Funktionsaufruf:

$dbh = $this->_dbh($this->base());

Wobei auch hier dafür gesorgt ist, daß die der Methode entsprechende Datei _dbh.php nur einmal eingebunden wird. Der Code wird also gecached und auf diese Art und Weise gibt es auch keine Coderedundanzen. Zentralorgan der Factory ist die Magic Method __call() die auch den Zugriff (Getter und Setter) auf die Eigenschaften der aktuellen URL regelt.

Wie schon in Perl ist nun auch im PHP Framework die Factory das Herzstück, was Instanzen um Code erweitert, der im Moment der Instanzerstellung noch gar nicht feststeht.

Getter und Setter

Für den einfachen Zugriff auf die Konfiguration zu einem URL:

$title = $this->title();
$this->title('Neuer Titel für die Seite');

Der Name einer Eigenschaft wird als Funktion verwendet, welche die Eigenschaft zurückliefert und auch setzen kann.

Ausgabe beliebiger Content-Types

Das Framework ermöglicht die Ausgabe von text/html abweichenden und beliebigen Content-Types wie Grafik, Audio, Video, PDF usw. in einer HTTP Response.

Woher kommt der BODY für eine Antwortseite

Woher der BODY für eine Seite vom Type text/html geladen wird, regelt das Atribut file (Beispiel = phpnotizen.html) in der Konfiguration. Sofern dieses Attrtribut nicht gesetzt ist, liegt der Body bzw. das Template für den Body in der Klassendatei sauber getrennt vom PHP-Bereich. Andere Quellen sind konfigurierbar. In der Regel jedoch ist für den Body ein Template vorgesehen was als Datei im Templateverzeichnis vorliegen muss und damit ist dieses Template auch für die Volltextsuche verfügbar. Das Template in der Klassendatei ist somit die Ausnahme und bspw. sinnvoll für die Klasse NotFound wo sich der Body auf nur wenige Zeilen beschränkt.

HTML::Template

Deprecated Codefragments habe ich bereinigt und auch Einiges verbessert was die Anwendung vereinfacht:

function bodybuild(){
    $tt = new Template5( array(
        'template' => $this->BODY
    ));

    $tt->AddParam($this->STASH);
    $tt->EchoOutput();
}

Entwicklungswerkzeug Dump & Die

Äußerst nützlich beim Entwickeln ist die Möglichkeit, einen Dump der beteffenden Daten im Browser ausgeben zu können. Von daher habe ich diese Möglichkeit, wie schon in meinem Perlframework, auch in der PHP Variante fest eingebaut. Zum Beispiel ist es hiermit möglich einen Dump der für diese Seite zu rendernden Platzhalter im Browser auszugeben. Des Weiteren sind diese Attribute als HTML-Kommentar im Kopfbereich einer jeden Seite eingebaut was eine etwaige Fehlersuche erleichtert.

Erweiterung des Parsers um weitere Enctypes

Der in PHP integrierte Parser liefert Request-Parameter in $_GET, $_POST, $_REQUEST und Uploads in $_FILES. Dafür kennt der Parser die Content-Types application/x-www-form-urlencoded und multipart/form-data die ein Request mit sich bringt sofern ein HTTP-Message-Body anhänglich ist. In Hinblick auf Webservices, REST, SOAP und XMLRPC kann ein Request jedoch auch andere Content-Types mit sich bringen die es zu verabeiten gilt. Eine diesbezügliche Erweiterung ist in meinem Framewok über eine dedizierte Klasse class CGI realisiert. So erfolgt der Zugriff auf Request-Parameter nicht mehr über die o.g. Arrays sondern einheitlich per $this->param('name').

Diese Erweiterung macht den Transportlayer HTTP und Request-Methoden wie GET, POST, PUT usw. vollständig transparent für nachgelagerte Anwendungen, was ja auch in Sinne des Standards CGI/1.1 ist.

Versionsunabhängigkeit

Für mich keine Frage, ein Framework muss von der Version der Programmiersprache in der es entwickelt wurde, unabhängig sein. Mein PHP-Framework jedenfalls läuft unter PHPv5.3 aufwärts. Was bestimmte Erweiterungen bzw. spezielle Anwendungen betrifft, das ist eine ganz andere Frage. Dieser Grundsatz ergibt sich allein schon aus der Idee die eine Templating Engine einschließt welche ein Framework sogar von der Progrmmiersprache unabhängig macht.

Einbau dynamischer Inhalte in jede Web-Einzelseite

File LastModified: 03.02.2020

E ist vollbracht, siehe Dateidatum obenstehend: Wie in Perl, so ermöglicht nun auch die PHP Variante meines Framework den Einbau beliebiger Platzhalter wie z.B. den Platzhalter %filedate% für obenstehende Ausgabe. Zur Realisierung dieses Features betrachten wir zunächst die Konfiguration:

[/phpnotizen.htm]
file = phpnotizen.html
interface = date
parent = /php
class  = Dummy
title  = Blog zu meinem PHP Framework
descr  = Notizen zu meinem PHP Framework die Anwendungen in PHP betreffend
vanguard = 1

Wie die Bezeichnung für die Klasse schon vermuten lässt, ist diese Klasse eine Dummyklasse die nichts weiter zu tun halt, als von der mainClass alle Methoden zu erben. Das Attribut interface = date jedoch sorgt dafür, daß die Methoden des Framework-Interface, die in der mainClass definiert sind, nicht ausgeführt werden. Stattdessen werden Methoden ausgeführt die in der zum Interface gehörigen Datei date.php definiert sind. Diesen Methoden wird die Instanz der zum URL konfigurierten Klasse übergeben, also die Instanz der Klasse Dummy. Diese Instanz referenziert sämtliche zum Request/Responsezyklus gehörigen Daten und so ist es möglich, auch die Platzhalter für diese Seite zum Leben zu erwecken.

Für die Konfiguration statischer Routen (URL - Klassenbindung) ergeben sich damit im Framework sehr vielfältige Möglichkeiten, sowohl zum Einbau dynamischer Inhalte als auch zum Programmieren interaktiver Webanwendungen sowie Webservices wie untenstehendes HTML-Object zeigt:

Das data-Attribut für dieses Objekt referenziert den Parameter jsondate=1 welcher die hier vorliegende Seite damit um einen Webservice erweitert.

Eine Common-Class und hinzukonfigurierte Interfaces

Mit der Erstellung einer Instanz stehen bekanntlich auch die Methoden fest welche diese Instanz ausführen kann. Mein Framework jedoch ermöglicht den Austausch bestimmter Methoden nachdem die Instanz erstellt wurde, ganz einfach durch die Konfiguration. So ist es möglich, eine bestehende Webressource z.B. interaktiv zu machen oder um einen Webservice zu erweitern. Oder anders ausgedrückt: Ein hinzukonfiguriertes Interface ermöglicht einer jeden Seite die Verarbeitung von Benutzereingaben bzw. Parametern.


Datenschutzerklärung: Diese Seite dient rein privaten Zwecken. Auf den für diese Domäne installierten Seiten werden grundsätzlich keine personenbezogenen Daten erhoben. Das Loggen der Zugriffe mit Ihrer Remote Adresse erfolgt beim Provider soweit das technisch erforderlich ist. nmq​rstx-18­@yahoo.de