2009-07-29 6 views
27

Hier ist, was ich tun möchte:Dynamisch generieren Klassen zur Laufzeit in PHP?

$clsName = substr(md5(rand()),0,10); //generate a random name 
$cls = new $clsName(); //create a new instance 

function __autoload($class_name) 
{ 
    //define that instance dynamically 
} 

Offensichtlich ist dies nicht das, was ich gerade tue, aber im Grunde habe ich unbekannte Namen für eine Klasse und basiert auf dem Namen, möchte ich mit der Klasse generieren bestimmte Eigenschaften usw.

ich habe versucht, mit eval(), aber es gibt mir über Privat passt und $ this-> Referenzen ...

// bearbeiten

Ok, natürlich meine kurze und süß "hier ist, was ich tun will" verursacht massive Streit und Bestürzung unter denen, die Antworten geben können. In der Hoffnung auf eine tatsächliche Antwort werde ich detaillierter sein.

Ich habe ein Validierungsframework mit Codehinweisen auf der Site, die ich pflege. Jede Funktion hat zwei Definitionen

function DoSomething($param, $param2){ 
    //code 
} 
function DoSomething_Validate(vInteger $param, vFloat $param2){ 
    //return what to do if validation fails 
} 

Ich suche einen Validator für Primärschlüssel in der Datenbank hinzuzufügen. Ich möchte keine separate Klasse für jede Tabelle erstellen (203). So war mein Plan, etwas zu tun wie

function DoSomething_Validate(vPrimaryKey_Products $id){ } 

Wo die __autoload eine Unterklasse von vPrimaryKey erzeugen würde und die Tabellenparameter auf Produkte gesetzt.

Glücklich jetzt?

+1

Ich schlage vor, Sie sagen uns, was genau Sie versuchen, und fragen Sie uns, wie es besser geht. Was Sie versuchen, ist nicht der richtige Ansatz. – hobodave

+2

Ich habe diesen neu gewählt, also hatte ich keine negative Stimme. Dies ist eine gültige Frage, auch wenn es eine schlechte Idee ist. – MitMaro

+0

Ich habe die Frage aktualisiert. –

Antwort

4

Dies ist fast sicher eine schlechte Idee.

Ich denke, Ihre Zeit wäre besser zum Erstellen eines Skripts, die Ihre Klassendefinitionen für Sie erstellen würde, und nicht versuchen, es zur Laufzeit zu erstellen.

Etwas mit einer Kommandozeilen-Signatur wie:

./generate_classes_from_db <host> <database> [tables] [output dir] 
+9

Sie sollten zumindest einen Grund dafür angeben. –

+14

Wenn du nicht wüsstest, was der Tod war, dann ja, es sollte erklärt werden. Das OP kann die Sicherheitsprobleme damit nicht verstehen. – MitMaro

+1

Gültiger Punkt hobodave. – MitMaro

2

Mit eval() ist wirklich eine schlechte Idee. Es öffnet sich ein großes Sicherheitsloch. Benutz es einfach nicht!

+1

+1 für die Angabe, warum dies eine schlechte Idee ist. – MitMaro

+13

Ich kann diese Ironie nicht lesen, aber als ernsthafte Antwort - 'eval()' ist per Definition nicht unsicher, wenn es so wäre, gäbe es keine solche Funktion. Es ist sein Input, der die Sicherheitslücken öffnet, wenn er mit Benutzereingaben kombiniert wird. Wenn Sie zum Beispiel ein 'eval ('2 + 2')' oder 'eval ('function() {return 42;}') machen, gibt es kein sicherheitsbezogenes Problem, selbst wenn eine solche Designentscheidung fraglich ist. –

2

Bitte lesen Sie alle anderen Antworten darauf, wie das wirklich eine sehr sehr schlechte Idee ist.

Sobald Sie das verstehen, hier ist eine kleine Demo, wie Sie dies tun könnten, aber nicht tun sollten.


<?php 
$clname = "TestClass"; 

eval("class $clname{}; \$cls = new $clname();"); 

var_dump($cls); 
+2

Ja, aber wenn Sie eval (...) ausführen, schlägt das fehl: eval ("class $ clsname {öffentliche Funktion DoSomething() {$ this-> bob = 4;}}"); weil Sie nicht "this" in der Mitte einer Nicht-Klasse-Funktion verwenden können. Oder wenn ich in einer Klassenfunktion wäre, wäre es der falsche "dieser" Zeiger ... –

+3

Sie haben ein Fluchtproblem, aber ich weigere mich, weiter zu helfen, denn das ist so, als hätten alle eine schlechte Idee. – MitMaro

+1

MitMaro ... wow, ich muss gestern wirklich nicht da gewesen sein, um nicht zu bemerken, dass ich meinem $ entkommen muss. Vielen Dank. –

13

seine lustig, ist eigentlich diese eine der wenigen Dinge, wo eval tut so eine schlechte Idee zu sein scheinen.

solange Sie sicherstellen können, dass keine Benutzereingaben jemals in das Eval eingegeben werden.

Sie haben immer noch Nachteile wie wenn Sie einen Bytecode-Cache verwenden, der Code wird nicht im Cache usw. gespeichert, aber die Sicherheitsprobleme von eval sind ziemlich ähnlich zu Benutzer iny in der Eval, oder in den falschen Bereich zu landen.

Wenn Sie wissen, was Sie tun, wird eval Ihnen dabei helfen.

das gesagt ist, meiner Meinung nach Sie sind viel besser aus, wenn Sie nicht auf Ihren Prüfungstyp-Hinting verlassen, aber Sie haben eine Funktion

DoSomething_Validate($id) 
{ 
    // get_class($id) and other validation foo here 
} 
3
function __autoload($class) { 
    $code = "class $class {` 
     public function run() { 
      echo '$class<br>'; 
     } 
     ".' 
     public function __call($name,$args) { 
      $args=implode(",",$args); 
      echo "$name ($args)<br>"; 
     } 
    }'; 

    eval($code); 
} 

$app=new Klasse(); 
$app->run(); 
$app->HelloWorld(); 

Dies könnte eine Klasse zu erstellen, hilft bei Laufzeit. Es erstellt auch einen Methor-Lauf und eine Catchall-Methode für unbekannte Methoden Aber besser Objekte zur Laufzeit, nicht Klassen erstellen.

10

Ich weiß, das ist eine alte Frage und es gibt Antworten, die funktionieren, aber ich wollte ein paar Schnipsel anbieten, die die ursprüngliche Frage beantworten würden und ich denke, bieten eine erweiterte Lösung sollte jemand hier enden wie ich wann getan Suche nach einer Antwort auf dieses Problem.

Erstellen von Einzel Dynamische Klasse

<?php 
// Without properties 
$myclassname = "anewclassname"; 
eval("class {$myclassname} { }"; 
// With a property 
$myclassname = "anewclassname"; 
$myproperty = "newproperty"; 
eval("class {$myclassname} { protected \${$myproperty}; }"; 
?> 

Solange Sie Ihren Text richtig entkommen, können Sie auch eine Funktion dort hinzuzufügen.

Aber was ist, wenn Sie dynamisch Klassen basierend auf etwas erstellen möchten, das selbst dynamisch sein könnte, wie das Erstellen einer Klasse für jede Tabelle in Ihrer Datenbank als die ursprüngliche Frage erwähnt?

Erstellen mehrerer Dynamische Klassen

<?php 

// Assumes $dbh is a pdo connection handle to your MySQL database 
$stmt=$dbh->prepare("show tables"); 
$stmt->execute(); 
$result = $stmt->fetchAll(PDO::FETCH_ASSOC); 
$handle = null; 
$classcode = ''; 
foreach ($result as $key => $value) { 
    foreach ($value as $key => $value) { 
     $classcode = "class {$value} { "; 
     $stmt2=$dbh->prepare("DESC $value"); 
     $stmt2->execute(); 
     $result2 = $stmt2->fetchAll(PDO::FETCH_ASSOC); 
     foreach ($result2 as $key => $value) { 
      $classcode .= "public \${$value['Field']}; "; 
     } 
     $classcode .= "}"; 
     eval($classcode); 
    } 
} 

?> 

Dies wird dynamisch eine Klasse für jede Tabelle in einer Datenbank generieren. Für jede Klasse wird auch eine Eigenschaft erstellt, die nach jeder Spalte benannt ist.

Jetzt wurde darauf hingewiesen, dass Sie dies nicht tun sollten. Solange Sie kontrollieren, was im Eval passiert, ist das Sicherheitsrisiko kein Problem. ABER - es gibt höchstwahrscheinlich eine Lösung, die mehr Sinn macht, wenn Sie gründlich genug darüber nachdenken. Ich dachte, ich hätte den perfekten Anwendungsfall, um dynamisch neue Klassen zu erstellen. Sorgfältige Untersuchung des Problems erwies sich als anders.

Eine mögliche Lösung - Verwenden Sie die stdClass zum Erstellen von Objekten, die nur Datencontainer sind und keine Methoden benötigen.

Auch - wie bereits erwähnt, könnten Sie ein Skript verwenden, um viele Klassen manuell zu generieren. Im Fall von Klassen, die Ihre Datenbanktabellen spiegeln, können Sie die gleiche Logik verwenden, die ich oben verwendet habe, und anstatt diese Informationen auszuwerten, schreiben Sie diese Informationen in eine Datei.

+0

Letzter Absatz von Ihnen Antwort ist ziemlich gut - Code ist das gleiche für Eval wie für die Klasse in der Datei, also schreiben Sie diese Klassen in Datei und ** haben sie in VCS-Repository ** – PeterM

4

Ich denke, mit eval() ist es keine zuverlässige Lösung, vor allem, wenn Ihr Skript oder Ihre Software an verschiedene Clients verteilt wird. Shared Hosting-Anbieter deaktivieren immer eval() Funktion.

Ich bin wie diese von einem besseren aproach denken:

<?php 

function __autoload($class) { 
     require 'classes/'.$class.'.php'; 

} 

$class = 'App'; 
$code = "<?php class $class { 
    public function run() { 
     echo '$class<br>'; 
    } 
    ".' 
    public function __call($name,$args) { 
     $args=implode(",",$args); 
     echo "$name ($args)<br>"; 
    } 
}'; 

file_put_contents('classes/App.php' ,$code); 

$a = new $class(); 
$a->run(); 

Nach Beendigung der Ausführung des Codes, können Sie die Datei löschen, wenn Sie möchten, testete ich es und es funktioniert perfekt.

+0

+1 für die clevere Antwort aber. . . Die Sicherheitsrisiken von eval sind jetzt größer, da Sie das Dateisystem nun für den Angriff verfügbar gemacht haben. Aber wie oben erwähnt, wird das Risiko minimiert, wenn Eingaben bereinigt werden. Übrigens, ich liebe es, Dinge wie diese mit '$ code =" "' Zu testen – eggmatters