2013-06-06 12 views
13

Gibt es eine Möglichkeit in PHP (programmatisch, natürlich) zu sagen, ob eine bestimmte Klasse ist eine interne Klasse (wie DateTime) oder eine Benutzerklasse (class MyClass)?Wie erkennt man, ob eine Klasse eine interne Klasse oder eine Benutzerklasse ist?

Falls Sie sich wundern (und ich bin mir sicher, dass Sie tun), ist dies, weil ReflectionClass::newInstanceWithoutConstructor() eine Ausnahme auslöst, wenn für interne Klassen verwendet, und während ich eine Bibliothek zum Deep-Copy-Objekte schreibe, muss es diese internen überspringen Klassen.

Ja, ich könnte nur die ReflectionException fangen, aber diese Ausnahme wird auch aus anderen Gründen (wie eine nicht vorhandene Klasse) ausgelöst, und wird nicht für alle Systemklassen ausgelöst. also erfüllt es meine Bedürfnisse nicht gerade.

+1

Warum genau möchte man einen Konstruktor überspringen? –

+1

@ Cobra_Fast: Sie würden das nie im alltäglichen Codieren tun wollen. Aber Bibliotheken tun dies, um Objekte zu hydratisieren, die aus einem persistenten Speicher geladen werden, oder in meinem Fall, um ein bereits instantiiertes Objekt tief zu kopieren. – Benjamin

+0

Auch wenn ich es mit externen Daten bevölkern, kann die Ausführung des Konstruktors IMHO nicht falsch sein. Sie können nie wissen, welche Arten von internen Strukturen initialisiert werden müssen. –

Antwort

14

A

$reflection = new ReflectionClass('SomeClass'); 
if($reflection->isUserDefined()) { 
    // 'SomeClass' is not an PHP internal 
} 

Statt einer Zeichenfolge ('SomeClass') Sie können auch: sauberere Lösung als shell_exec mit whould Reflexion zu benutzen, passiere ein Objekt. Für weitere Informationen suchen Reflection und ReflectionClass::isUserDefined() im PHP-Handbuch

+1

Oh, schön! Man könnte 'array_filter' über' get_declared_classes' und eine schöne Liste von benutzerdefinierten Klassen auf diese Weise erhalten. –

+4

Da er bereits eine reflectionClass erstellt hat, ist dies offensichtlich die beste Lösung. – h2ooooooo

+0

Woah, ich habe diese offensichtliche Lösung vermisst. Das ist der eine. Vielen Dank! – Benjamin

3

Interessante Frage, eine Möglichkeit, die ich denken kann durch Überprüfen der Namespace ist, zum Beispiel alle Ihre Klassen unter namespace MyApp definiert werden würde und dann überprüfen:

if(class_exists('\\DateTime')){ 
    continue; 
} 

Art hässlich, ich weiß.

+0

Ich habe darüber nachgedacht, und obwohl es stimmt, dass alle * my * -Klassen Namespaced sind, kann ich nicht garantieren, dass niemand versuchen wird, diesen Code unglücklicherweise für nicht namespaced Klassen zu verwenden. – Benjamin

0

Sie sollten die Klasse das Reflexionsverhalten nachahmen können, durch die Erweiterung die Sie zu kopieren sind versuchen, und das Überschreiben der __construct Funktion:

<?php 
    class MyClass extends ExtendingClass { 
     public function __construct() { 
      /* Override default constructor */ 
     } 
    } 
?> 

, die im Wesentlichen dynamisch gemacht werden könnten eval unter Verwendung:

<?php 
    function newInstanceWithoutConstructor($class) { 
     $className = $class . "Extended" . rand(0, 99999999); 
     while (class_exists($className)) { 
      $className = $class . "Extended" . rand(0, 99999999); 
     } 
     eval("class " . $className . " extends " . $class . " { public function __construct() { } }"); 
     return new $className(); 
    } 
    $newInstance = newInstanceWithoutConstructor("DateTime"); 
?> 

JEDOCH: Die Verwendung von eval kann in diesem Fall nützlich sein, enthüllt aber auch eine ziemlich große Sicherheitslücke, wenn etwas, was Benutzer eingereicht haben, eingereicht werden kann eine Möglichkeit, den Inhalt von $class zu ändern. Wenn Sie diese Einschränkungen und Auswirkungen auf die Sicherheit verstehen, sollten Sie in der Lage sein, dies zu verwenden.

+0

Danke, aber ich will diese interne Klasse um keinen Preis * instantiieren * Ich will nur * es * überspringen, wenn es da ist. – Benjamin

0

Können Sie nicht verwenden get_declared_classes() am Anfang des Skripts, speichern Sie die Daten in einem Array und führen Sie dann eine array_diff() mit den gespeicherten Daten und die Antwort von get_declared_classes() und überprüfen, ob die Klasse, die Sie Überprüfung sind in der Differenz ist mit in_array()?

+1

Haben Sie es getestet? Es enthält bereits *** deklarierte *** Klassen aus allen Skripten. – BlitZ

+3

Ich kann nicht kontrollieren, wann mein Code ausgeführt wird (es ist eine Standalone-Bibliothek), so dass ich zum Zeitpunkt des Aufrufs von 'get_declared_classes()' möglicherweise bereits Benutzerklassen enthält! – Benjamin

0

Diese example druckt alle Klassen mit Ihren Klassen scheint am Ende der Liste zu sein. Vielleicht kann das helfen.

+0

Leider gibt 'get_declared_classes()' auch Benutzerklassen zurück! – Benjamin

+0

Ja, aber sie sind am Ende (= nicht nach ihrem Namen sortiert), also könntest du sie am Ende holen. Entschuldigung, wenn es nicht hilfreich war: | –

0

Was ist mit der Speicherung calling get_declared_classes() Daten vor alle Autoloading/include/require ist gemacht und später Prüfung Klassenname in diesem Speicher?

+0

Gleiche Bemerkung wie für Дамян Станчев: Ich fürchte, ich kann nicht kontrollieren, wann mein Code ausgeführt wird, da es sich um eine eigenständige Bibliothek handelt! – Benjamin

2

Denkanstösse, basierend auf Дамян Станчев Vorschlag:

Sie könnten nur ein PHP-Interpreter über shell_exec() ausführen, die get_declared_classes() heraus spucken wird. Erfassen Sie die Ausgabe von diesem, und Sie sollten eine "saubere" Liste von Systemklassen haben.


Mogria Antwort erweitern, sollte dies ein gut funktionieren (gib mir nicht, obwohl für diese Kredite, wie es Mogria Antwort war, dass es richtig ;-) bekam):

function getUserDefinedClasses() { 
    return array_filter(get_declared_classes(), 
         function ($class) { 
          $reflectionClass = new ReflectionClass($class); 
          return $reflectionClass->isUserDefined(); 
         }); 
} 
+1

Gute Problemumgehung, nur Problem, das ich sehe, ist, dass es sich auf 'shell_exec' verlässt, was einige Systeme möglicherweise verhindern. – Prisoner

+1

Das würde funktionieren. Ein bisschen umständlich, aber, IMHO;) – Benjamin

Verwandte Themen