Also, ich bin gerade dabei ein größeres Projekt in PHP neu umzusetzen.
Dabei würde es sich anbieten, mit Plugins zu arbeiten.
Leider konnte mir Google nicht mit irgendwelchen Design Pattern, o.ä. dienen, daher die Frage hier:
Wie setze ich das am besten um?
Dabei gehts eigentlich nicht um den codespezifischen Teil.
Daher poste ich auch ins Profi-Forum: require, call_user_func und die ganzen Späße kenne ich. Geht ruhig davon aus, dass ich alle relevanten (auch php spezifischen) Kniffe kenne.
Bei mir haperts nur an einer Idee zur Architektur.
Prinzipiell muss ich ja in der Lage sein, jede Funktion durch nahezu beliebigen Code zu erweitern.
Welche Ansätze gibt es da?
Zum Beispiel:
- "Require" ich einfach alle passende Plugins am Ende jeder Methode?
- Wie "registriere" ich Plugins am sinnigsten - sprich: Wie teilt mir das Plugin mit, mit welchen Funktionen es gerne arbeiten will.
- Oder arbeite ich lieber mit Overloading von Klassen?
Fragen über Fragen...
Wie gesagt: Ich suche Designpatterns, Flussdiagramme, Ideen und Konzepte zur Realisierung von Plugins. Die eigentliche technische Umsetzung ist kein Problem.
Vielen Dank schonmal für Eure Bemühungen.
Ankündigung
Einklappen
Keine Ankündigung bisher.
Umsetzung eines Pluginsystems
Einklappen
Neue Werbung 2019
Einklappen
X
-
Umsetzung eines Pluginsystems
Stichworte: -
-
Ein Gast antworteteIch versuche derzeit etwas ähnliches auf die Beine zu stellen. Zu Hilfe nehme ich die __autoload()-Funktion von PHP5. Somit kann ich benötigte Klassen dynamisch nachladen lassen. Vorraussetzung ist hier natürlich, dass jedes Modul als Klasse dargestellt wird.
Zur Organisation der Klassen verwende ich den Unterstrich. Jeder Unterstrich wird bei der Suche nach einer Klasse in ein DIRECTORY_SEPARATOR umgewandelt (grobe Beschreibung). Somit kann man die einzelnen Klassen in Ordnern strukturieren.
Vorteil:
Die Plugins müssen nicht direkt wissen, was für Abhängigkeiten sie benötigen. Fehlt eine Klasse (Äbhängigkeit von einer anderen Klasse) wird sie automatisch nachgeladen.
Derzeit spiele ich noch mit zusätzlichen Optionen/Funktionen die der Modulmanager enthalten kann, weshalb Teile unkommentiert sind o.ä., einen Einblick sollte das aber verschaffen können:
http://beta.webmasterpro.de:60080/sv...dules/molp.php
Zur Verwirklichung von Filtern würde ich versuchen ein ähnliches Konzept wie Java zu benutzen, bin mir aber unsicher, ob das in PHP klappt.
Würde grob heißen:
* Man schreibt ein Interface über dessen Methoden ein Ausgabemodul die Daten bekommt
* Von dieser Klasse leitet man eine Klasse ab, die die Daten direkt aus der Datenbank liest
* Nun leitet man weitere Klassen ab, die im Konstruktur eine Klasse vom Typ des Interfaces bekommen und die Daten dieser Klasse in den eigenen Rückgabefunftionen verändern
Beispiel:
PHP-Code:<?php
// Deklaration
interface datasource {
function getData();
}
class datasource_database {
private $data;
function __construct($id) {
/*
Daten lesen und nach $data schreiben
(Ich nehme $data ab hier als einfachen String an)
*/
}
function getData() {
return $data;
}
}
class datasource_filter1 {
private $source;
function __construct(datasource $source)
{
$this->source = $source;
}
function getData()
{
return $source->getData() . '...1';
}
}
class datasource_filter2 {
private $source;
function __construct(datasource $source)
{
$this->source = $source;
}
function getData()
{
return $source->getData() . '...2';
}
}
// Aufruf
$datasource = new datasource_database(1);
if (/* Bedingung 1 */)
$datasource = new datasource_filter1($datasource);
if (/* Bedingung 2 */)
$datasource = new datasource_filter2($datasource);
// Anmerkung: Wegen dem Interface ist $datasource in jedem Fall 'instanceof datasource'
echo $datasource->getData();
?>
-
Das is doch mal ein Ansatz.
Fürs erste sollte das genügen, denke ich.
Ich teste das Ganze mal an und sollte was Produktives dabei herauskommen, poste ich es.
Danke!
Einen Kommentar schreiben:
-
Ein Gast antwortetehi,
na gut letzter versuch (:
um dynamisch zu includen (lazy loading genannt) brauchst du 2 sachen.
1. module müssen wissen was sie alles brauchen und es selber includen
2. module sollten in einer festen verzeichniss struktur abgelegt sein um sie
einfach über namen zu includen.
beispiel:
PHP-Code:<?
function require_filter($name)
{
$className = 'Filter'.$name;
if (!class_exists($className))
{
include_once(FILTER_PATH.'/'.$className.'.filter.php');
}
}
?>
<?
require_filter('FormatNumber');
require_filter('FormatCurrency');
class FormatWhatever
{
function execute(&$datasource)
{
....
}
}
?>
<?
require_filter('FormatWhatever');
require_filter('FormatBBCode');
class FormatFoo
{
function execute(&$datasource)
{
....
}
}
Einen Kommentar schreiben:
-
Ein Gast antwortete*hmm*Es geht nur um die prinzipielle Möglichkeit beliebigen Code an bestimmten Stellen einzufügen. Wann welche Code zu benutzen ist, ist kein Problem.
Ich weis nicht ob wir uns da doch zumindest grob an Regeln halten sollten
sonst gibt es ja keine Bedingungen selbst für Dynamischen aufruf, oder ?!
Ich meine das letzte ECHO muss doch wissen wann es gemeint sein muss
das sagst Du hast Du schon ... wie bist Du da vorgegangen ?
Ich mache das meist anhand von zahlen.
*maleinerauchengeh*
*und dann Thread noch mal durchles*
Einen Kommentar schreiben:
-
Ich glaube ihr versteift euch zu sehr auf diese Regeln.dann solltest du erstmal rausfinden nach welchen regeln die daten gefiltert werden. es hört sich so an als wäre das ganze recht kompliziert wann welcher filter rann darf. es wird also nicht einfach werden da regeln aufzustellen. daher würde ich damit anfangen die regeln hardcoded zu hinterlegen. mit einfachen if / else konstrukten. wenn du dann merkst das du das vereinfachen kannst : tu es (:.
Es geht nur um die prinzipielle Möglichkeit beliebigen Code an bestimmten Stellen einzufügen. Wann welche Code zu benutzen ist, ist kein Problem.
In der Datenbank ist hinterlegt, welches Frontend welches Plugin nutzen will. Die Sortierung ist also nicht der Haken.
Im Prinzip bin ich ja schon an dem Punkt.as ganze nennt sich refactoring und basiert auf der idee ein problem einfachstmöglich zu lösen. sobald mann dann an den punkt kommt "erm.... wieso so kompliziert?" sollte mann keine scheu haben den code zu ändern (egal was da für ein rattenschwanz dranhängt). das führt meistens zu problem orientiertem, schlanken code.
Die grobe Struktur der Klassen und des Codes ist fertig. Jetzt bin ich an dem Punkt, wo ich mich frage, wie ich am sinnvollsten auslager.
Ich halte mich nicht bei jedem Kleinscheiss an Patterns - klar!ach nochwas zu design patterns : ich würde mich nicht zu sehr drauf versteifen einen pattern zu deinem problem zu suchen. imho führt das meistens zu überkomplizierten konstrukten (:
Nur wäre es halt sinnvoll, bei einem Problem, wo ich mir nicht ganz sicher bin, einfach mal zu schauen, was sich andere schlaue(re) Leute dazu schon gedacht haben.
Grundsätzlich habe ich damit auch kein Problem.vor allem solltest du keine angst vor änderungen haben (siehe oben)
Nur wirds eben schwierig wenn mehrere Leute an einem Projekt arbeiten.
Da braucht man erstmal eine grobe Struktur, wie was gemacht werden muss, damits nachher nicht im Chaos endet.
Daher versuche ich momentan erstmal auf abstrakter Ebene zu arbeiten (richtig: ich habe keine konkreten Anforderungen), ums dann nachher in der Praxis einfacher zu haben.
Die Leute rennen mir die Tür ein, wenn ich mitten im Projekt das Ganze nochmal umschmeisse
Vielen Dank an dieser Stelle schonmal für die ausführlichen Kommentare und Eure Mühe!
Einen Kommentar schreiben:
-
Ein Gast antworteteok,Zitat von /tmpDie Aktion ist eben nicht immer die selbe.
Um obriges Beispiel mal aufzugreifen...ganz plump müsste das Plugin System wie folgt aussehen:
Dieses Beispiel ist nur eins von vielen möglichen.Code:// Suche nach allen Plugins, die im aktuellen Frontend benutzt werden sollen // Suche unter diesen Plugins nach allen, die in genau dieser Funktion // eingesetzt werden sollen foreach (...) { // Füge die gefundenen Plugins ein ..... //Eigentliche Aktion, die diese Funktion ausführt }
Zum Beispiel könnte ich - wie gesagt - mit Overloads arbeiten.
Ich könnte auch mit call_user_func(); einfach Funktionen aufrufen, die in den Plugins definiert werden müssten.
Alles tolle Ideen - aber alle haben irgendeinen Haken
Problem ist: Es hängt von verschiedenen Faktoren ab, wann welches Plugin geladen werden soll.
Sowohl für den Umfang des Programms, als auch für Effizienz und Übersichtlichkeit macht es sinn, die Codezeilen, die nicht immer benutzt werden, auszulagern und nur bei Bedarf einzufügen - Plugins eben.
Ich brauche nur eine effiziente Methode wie ich das am besten realisiere.
Daher möchte ich wissen, ob es da ganz abstrakte Ansätze gibt - Design Patterns zum Beispiel.
Vorteilhaft wäre es nämlich auf bewährte Ideen zurückzugreifen.
Problem verstanden?
Ich bin kein gelernter Informatiker. Mit der herrschenden Lehre usw. kenne ich mich einfach nicht aus. Ich arbeite sonst lediglich auf Grundlage der natürlichen Logik und meines beschränkten Verstandes.
Nur sind an dieses Projekt ne Menge Anforderungen gestellt, sodass ich mich nicht nur auf mich alleine verlassen will/kann.
dann solltest du erstmal rausfinden nach welchen regeln die daten gefiltert werden. es hört sich so an als wäre das ganze recht kompliziert wann welcher filter rann darf. es wird also nicht einfach werden da regeln aufzustellen. daher würde ich damit anfangen die regeln hardcoded zu hinterlegen. mit einfachen if / else konstrukten. wenn du dann merkst das du das vereinfachen kannst : tu es (:.
das ganze nennt sich refactoring und basiert auf der idee ein problem einfachstmöglich zu lösen. sobald mann dann an den punkt kommt "erm.... wieso so kompliziert?" sollte mann keine scheu haben den code zu ändern (egal was da für ein rattenschwanz dranhängt). das führt meistens zu problem orientiertem, schlanken code.
ach nochwas zu design patterns : ich würde mich nicht zu sehr drauf versteifen einen pattern zu deinem problem zu suchen. imho führt das
meistens zu überkomplizierten konstrukten (: löse lieber dein spezielles problem so einfach wie möglich und achte auf gute dokumentation. vor allem solltest du keine angst vor änderungen haben (siehe oben). wenn du einen schritt weiter gehen willst solltest du dir mal was über test
driven design anlesen (suche mal nach simpletest, eine sehr gute php implementation).
gruss
Sike
ps. ich weiss das ist alles nicht sehr konkret, aber du hast imho auch noch keine konkreten anforderungen.
Einen Kommentar schreiben:
-
Die Aktion ist eben nicht immer die selbe.
Um obriges Beispiel mal aufzugreifen...ganz plump müsste das Plugin System wie folgt aussehen:
Dieses Beispiel ist nur eins von vielen möglichen.Code:// Suche nach allen Plugins, die im aktuellen Frontend benutzt werden sollen // Suche unter diesen Plugins nach allen, die in genau dieser Funktion // eingesetzt werden sollen foreach (...) { // Füge die gefundenen Plugins ein ..... //Eigentliche Aktion, die diese Funktion ausführt }
Zum Beispiel könnte ich - wie gesagt - mit Overloads arbeiten.
Ich könnte auch mit call_user_func(); einfach Funktionen aufrufen, die in den Plugins definiert werden müssten.
Alles tolle Ideen - aber alle haben irgendeinen Haken
Problem ist: Es hängt von verschiedenen Faktoren ab, wann welches Plugin geladen werden soll.
Sowohl für den Umfang des Programms, als auch für Effizienz und Übersichtlichkeit macht es sinn, die Codezeilen, die nicht immer benutzt werden, auszulagern und nur bei Bedarf einzufügen - Plugins eben.
Ich brauche nur eine effiziente Methode wie ich das am besten realisiere.
Daher möchte ich wissen, ob es da ganz abstrakte Ansätze gibt - Design Patterns zum Beispiel.
Vorteilhaft wäre es nämlich auf bewährte Ideen zurückzugreifen.
Problem verstanden?
Ich bin kein gelernter Informatiker. Mit der herrschenden Lehre usw. kenne ich mich einfach nicht aus. Ich arbeite sonst lediglich auf Grundlage der natürlichen Logik und meines beschränkten Verstandes.
Nur sind an dieses Projekt ne Menge Anforderungen gestellt, sodass ich mich nicht nur auf mich alleine verlassen will/kann.
Einen Kommentar schreiben:
-
Ein Gast antwortetehmmm nur mal so
... wie du es sagst legst Du die Filter doch auch fest an !?
... wenn du die zu filternden zeichen hinterlegst ... und wenn er das eine nicht findet legst dus an und machst
dann die prozedur ? Des Filtern...
... dadurch lernt das system ja direkt -> es braucht eigentlich nur
zu wissen welche Zeichen nicht !?
Fragt sich ist die aktion immer die selbe ?
Einen Kommentar schreiben:
-
Ein Gast antwortetehi,Zitat von /tmpDas sieht schon gut aus, allerdings müssen eben diese Filter dynamisch als Plugins genutzt werden können.
Denn je nach Frontend muss ich andere Filter anwenden.
Bei Bedarf muss ich auch Filter dynamisch nachdefinieren können und das schreit förmlich nach Plugins.
Ausserdem sind die Filter ja nur ein Aspekt der Plugins (wenn auch zugegebenermaßen der wichtigste).
das da oben war nur ein beispiel um die grundlegenden mechanismen zu zeigen (: wenn du also wie oben gesagt keine problem mit der technischen umsetzung hast solltest du daraus ja eine system mit lazy loading basteln können.
als denkanstoss:
PHP-Code:function &addFilter($name)
{
$className = 'Filter'.$name;
if (!class_exists($className))
{
include_once(PLUGIN_PATH.'/'.$className.'.class.php');
}
$filter = new $className();
$this->filter[] = &$filter;
return $filter;
}
also irgendwie musst da ja definieren welche filter für welche frontendsZitat von /tmpDenn je nach Frontend muss ich andere Filter anwenden.
Und es macht keinen Sinn das hart einzucoden.
anwendbar sind. eventuell sogar mit regeln wann sie angewendet werden dürfen. das _musst_ du imho hardcoden oder du arbeitest mit config files (mag ich persönlich nicht ganz so gerne).
gruss
Sike
Einen Kommentar schreiben:
-
Das sieht schon gut aus, allerdings müssen eben diese Filter dynamisch als Plugins genutzt werden können.
Denn je nach Frontend muss ich andere Filter anwenden.
Und es macht keinen Sinn das hart einzucoden.
Bei Bedarf muss ich auch Filter dynamisch nachdefinieren können und das schreit förmlich nach Plugins.
Ausserdem sind die Filter ja nur ein Aspekt der Plugins (wenn auch zugegebenermaßen der wichtigste).
Einen Kommentar schreiben:
-
Ein Gast antwortetehi,
so wie ich dich verstehe redest du eher von filtern als von plugins.
ich würde das ganze objekt orientiert aufbauen als einen einfachen
filter chain. die idee dahinter ist eigentlich recht simpel : es gibt einen
filter manager über den du filter registrierst. der manager bekommt dann
die ausgangsdatenquelle zugewiesen und arbeitet seine filter der reihe nach
ab und gibt am ende die modifizierten werte zurück. wie mann das im
detail aufbaut hängt (wie immer) sehr stark von deiner restlichen architektur ab.
hier mal ein kleines beispiel :
grussPHP-Code:<?
class Datasource
{
var $data = false;
function Datasource()
{
}
function import(&$data)
{
$this->data = &$data;
}
function importDatasource(&$datasource)
{
$this->data = $datasource->data;
}
function get($name)
{
return (isset($this->data[$name])) ? $this->data[$name] : null;
}
function set($name, $value)
{
$this->data[$name] = $value;
}
}
class Filter
{
function Filter()
{
}
function execute(&$datasource)
{
}
}
class FilterFormatNumber
{
var $decimals = 2;
function execute(&$datasource)
{
if ($datasource->get('number1') !== null)
{
$datasource->set('number1', number_format($datasource->get('number1'), $this->decimals, ',', ' '));
}
}
}
class FilterWordWrap
{
var $maxWidth = 20;
function execute(&$datasource)
{
if ($datasource->get('text1') !== null)
{
$datasource->set('text1', wordwrap($datasource->get('text1'), $this->maxWidth));
}
}
}
class FilterManager
{
var $input = false;
var $output = false;
var $filter = array();
function FilterManager(&$datasource)
{
$this->input = &$datasource;
$this->output = new Datasource();
$this->output->importDatasource(&$this->input);
}
function addFilter(&$filter)
{
$this->filter[] = &$filter;
}
function execute()
{
$filters = count($this->filter);
for($filter=0; $filter<$filters; $filter++)
{
$this->filter[$filter]->execute(&$this->output);
}
}
function &getOutput()
{
return $this->output;
}
}
//
// Beispiel
//
$input = new Datasource();
$input->set('number1', 123.5678);
$input->set('text1', 'Zur Ast Satin Blei ums fals Helene Dem, auf ob Baal Irrenhaus brandet Flug Farm, wog Geologen ums, merkt Brutto gekürzter Knies et Gashahn killt Schopfes zur Dottern zerrten Allmacht neigt. Leere Trios, ans Geo zus Atü webt halb Tabake so No. Eher Dufy Belebung bestreit, Brei im Filz hohlen Gelände fache. Bonn zudeckendes Pius vager Big Faltern geb Abart. Alp As Task erregten erb wird als Bhaltis.');
$manager = new FilterManager(&$input);
$filter1 = new FilterFormatNumber();
$manager->addFilter(&$filter1);
$filter2 = new FilterWordWrap();
$manager->addFilter(&$filter2);
$manager->execute();
$output = &$manager->getOutput();
print_r($output);
?>
Sike
Einen Kommentar schreiben:
-
Das mit den Firmeninterna war auch nicht ganz ernst gemeint.
Problem ist, dass es ein sehr umfangreiches Projekt wird und ich noch keine genaue Anforderungsanalyse aufm Tisch habe.
Grundsätzlich wirds ne Art internes Forum (nicht ganz, aber vergleichbar) auf SOAP Basis.
Im Prinzip als Supportplattform auf Intranet Basis mit verschiedenen Frontends. Also Abteilung Buchhaltung hat ein eigenes, autonomes Frontend, Abteilung Support hat eins, Abteilung EDV ebenfalls...
Für jede Abteilung können einzelne User (Mitarbeiter) registriert werden, die entsprechend mit den Beiträgen verknüpft werden.
Frontend <---> SOAP <-> Applikation <-> Datenbank
Ein User schreibt also einen Beitrag. Dieser wird per SOAP an die Applikation geschickt und die packt es in die Datenbank.
Umgekehrt natürlich wenn gelesen wird:Code:Beitrag ---> Frontend ---> SOAP -> Applikation -> (Plugins) -> Datenbank
Und natürlich der ganze kleine Schnickschnack.Code:Datenbankbeitrag -> Applikation -> (Plugins) -> SOAP ---> Frontend
Und eben diese Kleinigkeiten sollen als Plugin realisiert werden.
Beispiel 1:
Kunde XY holt sich einen Text - sagen wir eine Kalkulation - aus der Datenbank.
Das ist die normale SOAP Anfrage. Ein Plugin könnte dann so aussehen, dass der Text nochmal mit ner RegEx bearbeitet (Platzhalter ersetzen zum Beispiel) oder um Informationen ergänzt wird. Zum Beispiel ne Copyright Zeile.
Beispiel 2:
Ein Kunde XY speichert einen Text - sagen wir eine Notiz.
Ein Plugin könnte sein, dass der Text vorher auf Rechtschreibung überprüft wird und nur dann gespeichert werden darf, wenn alles "clean" ist.
Beispiel 3:
User A wird registriert, also mit ein paar erforderlichen Daten in die Datenbank gepackt. Ein Plugin könnte definieren, welche Daten Pflicht sind und welche nicht.
Soweit ausreichend zum Verständnis?
Einen Kommentar schreiben:
-
Ein Gast antwortetealso entweder du oder ich hat gerade nen knoten im kopp - und ich glaube das is meine wenigkeit .... ich mach mich ma ins bettsche und werd drüber nachgrübeln
trotzdem hast du mir nich verraten, was die plugins machen sollen - die firmeninternas sind mir ziemlich egal - ich weiß nichma für welche firma du arbeitest - und auch wenn hab ich genug eigenen kram... *g*
so ganz sind wir noch nich auf einem nenner, wie gesagt - soll das plugin nen string generieren ??? - meine vorstellungskraft ist begrenzt - gerade zu dieser zeit, also geb uns doch noch ein bissel mehr info als die foreach-schleife...
greetz
andy
ps: bisher sehe ich nämlich noch garkein problem *doof kuck*
Einen Kommentar schreiben:
-
lol...diese Foren sind einfach ungeeignet, wenn man direkt ohne Delay kommunizieren will - mit Edit Funktion erst recht
Das Beispiel von oben sollte eigentlich erstmal reichen zur Veranschaulichung (viel kann ich zum dem Projekt an sich nicht sagen, ohne wirklich lange ausschweifen zu müssen und firmeninterna auszuplaudern
)
Nehmen wir an, ich will in der foreach Schleife ne Schnittstelle zu nem Plugin geben:
Der Plugincode könnte dann wie folgt aussehen:Code:foreach ($this->cArray as $aElement) { // <--- Insert Plugin here $string .= $aElement.$seperator; }
Dann müsste ich zunächst herausbekommen, welche Plugins an dieser Stelle überhaupt arbeiten wollen und diese dann includen.Code://Aus einem Array von 0, 1, 2, 3 // soll 0te, 1te, 2te, 3te... werden. if($aElement == 1) $aElement = "1ste"; else $aElement .= "te";
Hätte den Vorteil, dass ich wenig Overhead habe (siehe unten), aber den Nachteil, dass ich erstmal Plugins suchen müsste und mir ein System überlegen müsste, wie mir die Plugins mitteilen, an welcher Stelle sie benutzt werden wollen.
Ausserdem wäre die Sache eher unflexibel, weil die Plugins nur an vordefinierten Stellen arbeiten könnten.
Soweit Idee eins.
Zweite Idee wäre, die ganze Methode zu overloaden.
Was dann natürlich ne Menge Overhead geben würde, weil ja die foreach Schleife nochmal ausgeführt werden müsste, um auf einzelne Elemente des Arrays zuzugreifen - und zwar bei jedem Plugin neu!
Problem verstanden?
Wir haben also zur Auswahl: Unflexibilität & Aufwand vs. Overhead & Rechenleistung.
Meine Lieblingslösung wäre Flexibilität & wenig Overhead
[EDIT]
Ich muss erstmal ins Bett, schaue morgen wieder rein.
Danke schonmal!!
[/EDIT]
Einen Kommentar schreiben:

Einen Kommentar schreiben: