PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : PHP: Funktion einer Funktion übergeben - mit Klasse


Kinman
2011-11-18, 15:05:25
Hallo,
ich habe ein kleine Problem mit PHP. Bevor ich jedoch lange herumexperimentiere, frage ich einfach mal nach ob es überhaupt möglich ist: Man kann in PHP ja Funktionen einer Variabel zuweisen. Somit kann man Funktionen anderen Funktionen übergeben. Ich habe jetzt zwei Klassen, eine "Main"-Klasse mit der gesamten Funktionalität und eine Klasse meiner Template-Engine.
Für eine Plugin-Funktion ist es jetzt nötig, dass ich in der Main-Klasse ein Template einlese. Allerdings habe ich die Template-Klasse nicht in der Main-Klasse instanziiert (will ich auch nicht), benötige aber in der Main-Klasse eine Funktion der Template-Klasse zum Einlesen des Templates. Diese würde ich gern der Funktion übergeben.

Pseudo-Code meiner Klassen und dem Hauptprogramm, was mir vorschwebt:


class Template
{
[..]

function readTemplate($templateFile)
{
[..]

return $templateContents;
}
}

class Main
{
[..]

function loadExtension($type, $readTemplateWrapper)
{
[..]

return $readTemplateWrapper($someTemplateFile);
}
}


//Hauptprogramm

$main = new Main();
$template = new Template();

[..]

$main->loadExtension(gallery, '$template->readTemplate');


Tja und wie auch immer ich es momentan gedreht und gewendet habe, kam ich zu keinem Erfolg. Darum wollte ich mal wissen, ob das, was ich vorhabe, überhaupt möglich ist.

Danke,
mfg Kinman

BadCop
2011-11-18, 22:02:33
was du vorhast geht nur mit statischen funktionen aus andren klassen heraus, ohne instanz kommst du sonst nicht an die funktion ran. das was du ansprichst ist in php unter 'variable variables' (http://www.php.net/manual/en/language.variables.variable.php) nachlesbar und lässt sich theoretisch endlos stacken, wird dir aber in deinem fall glaub nichts bringen.

Kinman
2011-11-18, 23:10:59
Hmm.. als statische Funktion wäre es leider nicht möglich. Sieht wohl aus, dass ich hier auf den Holzweg bin und etwas Unmögliches will. Naja, dann muss ich mir einen anderen, hoffentlich auch eleganten, Weg suchen, mein Problem zu lösen.

Danke dir,
mfg Kinman

Gast
2011-11-18, 23:30:28
class Template
{
function readTemplate($templateFile)
{
return $templateContents;
}
}

class Main
{
function loadExtension($type, $readTemplateWrapper)
{
return call_user_func($readTemplateWrapper, $someTemplateFile);
}
}


//Hauptprogramm

$main = new Main();
$template = new Template();

$main->loadExtension(gallery, array($template, 'readTemplate'));


Noch Fragen?

Gast
2011-11-19, 00:27:27
Und ab PHP 5.3 geht's dann genau so, wie von dir gedacht:

class Template
{
function readTemplate($templateFile)
{
return $templateContents;
}
}

class Main
{
function loadExtension($type, $readTemplateWrapper)
{
return $readTemplateWrapper($someTemplateFile);
}
}


//Hauptprogramm

$main = new Main();

$main->loadExtension
(gallery
,function($templateFile)
{ $template = new Template(); $template -> readTemplate($templateFile); }
);


Lesen: Callback Type (http://de.php.net/manual/en/language.pseudo-types.php#language.types.callback), Anonymous Functions (http://de.php.net/manual/en/functions.anonymous.php)

BadCop
2011-11-19, 00:55:07
cuf/cufa sollte man möglichst vermeiden, gibt da immer risiken bzgl injection und performance ist auch nicht so gut, je nach php version ist anon funcs ne alternative, aber glaub da fehltn return :)

der lesbarkeit wegen lieber so:

//Hauptprogramm

$main = new Main();
$func = function($templateFile)
{
$template = new Template();
return $template->readTemplate($templateFile);
};

$content = $main->loadExtension(gallery, $func);

Gast
2011-11-19, 01:29:43
Guter Stil ist was anderes, das stimmt. Deshalb würde mich auch interessieren, weshalb er nicht direkt mit einer Instanz der Templateklasse (oder einem Wrapper davon) arbeiten möchte.

Wie z.B. so (ohne Templateklasse, da nicht geändert):
class Main
{
function loadExtension($type, $readTemplateWrapper)
{
return $readTemplateWrapper -> readTemplate($someTemplateFile);
}
}


//Hauptprogramm

$main = new Main();
$template = new Template();

$main->loadExtension(gallery, $template);

Danke für die Korrektur mit dem Return ;)

BadCop
2011-11-19, 01:46:33
jo stimmt, das ist alles etwas obskur :)
da wir aber nicht wissen was das alles drumherum noch entsteht, kann man eh nur ein paar hinweise bzw beschreibungen mitgeben.
dynamisches laden ist zwar immer toll flexibel, verliert aber schnell an überschaubarkeit, änderungen sind meist schwer durchführbar und projektneueinsteigern fällt die lesbarkeit des ganzem schnell auf die füsse. zusätzlich wäre mir das ganze zu riskant wegen fehlendem typehinting, man kann da nie abschätzen, was da alles mal schiefgehn kann.

ein weiterer faktor bei solch einer geschichte, die objekte/klassen/funktionen/parameter sollten vordefiniert sein, sodass man wenigstens eine (wenn auch schwache) absicherung hat.

Gast
2011-11-19, 13:49:45
was du vorhast geht nur mit statischen funktionen aus andren klassen heraus, ohne instanz kommst du sonst nicht an die funktion ran. ...

Das ist sehr wohl möglich, da PHPs OOP Modell total kaputt ist.


class Template {

function readTemplate($templateFile) {
return "content: " . $templateFile;
}
}

class Main {

function loadExtension($type, $readTemplateWrapper) {
return $readTemplateWrapper('file.tmpl');
}

}

$main = new Main();
echo $main->loadExtension(null, function($file) {

return Template::readTemplate($file);
});


Lustig wird es aber erst dann, wenn in Template::readTemplate $this benutzt wird. Dann ist $this die Instanz der Main Klasse. Aber wenigstens funktioniert innerhalb von readTemplate nicht der Zugriff auf private Methoden der Main Klasse.

BadCop
2011-11-19, 14:22:44
was du da produzierst ist ein static call und wirft nebenbei noch strict warnings, das fliegt dir in sämtlichen produktiven einsätzen sowas um die ohren :)

Kinman
2011-11-19, 15:58:39
Hallo,
danke nochmals für die zahlreichen Antworten. Werde das heute alles noch probieren und dann auch Feedback geben.

Warum ich das mache:
Der Code sollte möglichst innerhalb meiner eigenen Projekte möglichst kompatibel bleiben, damit ich Updates für alle Projekte machen kann, wenn ich wo etwas verbessere. Darum will ich an diversen Klassen bzw. Routinen nichts ändern (Die eine Klasse in der anderen instanziieren bzw. eine Child-Klasse erstellen und dort instanziieren), da sonst andere Code-Teile ebenfalls geändert werden müssen und wenn ich eine etwas aktualisiere, dann müsste ich immer spezielle Anpassungen machen.

Ob andere dann mit dem Code zurechtkommen ist mir in diesem Fall vollkommen egal, da nur ich an diesem (nicht-kommerziellen) Projekt abeite.

Natürlich werde ich mir auch die Performance diesbezüglich ansehen, aber ich erwarte keinen wirklich großen Impact.

Sicherheitstechnisch mache ich mir in diesem speziellen Fall auch keine Sorgen, da das Projekt rundherum recht gut abgesichert ist (u.a. auch mit Whitelists für Dateien usw.).

mfg Kinman

EDIT:
class Template
{
function readTemplate($templateFile)
{
return $templateContents;
}
}

class Main
{
function loadExtension($type, $readTemplateWrapper)
{
return call_user_func($readTemplateWrapper, $someTemplateFile);
}
}


//Hauptprogramm

$main = new Main();
$template = new Template();

$main->loadExtension(gallery, array($template, 'readTemplate'));


Noch Fragen?

Diese Variante funktioniert perfekt. Änderung in der Performance waren nicht wirklich ersichtlich. Obwohl ich testweise ca. 500 Aufrufe untergebracht habe (im Endstadium werden es unter fünf, voraussichtlich zwei sein) war in der Ausführungsdauer kein Unterschied zu erkennen. Trotzdem werde ich es im Auge behalten, wie es aussieht, wenn mehrere User gleichzeitig darauf zugreifen usw.

Danke nochmals für die super Hilfe!

mfg Kinman

Gast
2011-11-19, 18:39:32
was du da produzierst ist ein static call und wirft nebenbei noch strict warnings, das fliegt dir in sämtlichen produktiven einsätzen sowas um die ohren :)

Ach ehrlich? Was das ist weiss ich selber. Habe ich gesagt, dass ich diesen Mist verwende? Damit wollte ich nur zeigen wie kaputt diese Sprache ist.

BadCop
2011-11-22, 23:56:57
Das hat nix mit kaputt zu tun, das ist ein Relikt von PHP4 Zeiten.