2010-03-31 2 views
15

Ist es möglich, eine Instanz einer PHP-Klasse zu erstellen, ohne ihren Konstruktor aufzurufen?In PHP ist es möglich, eine Instanz einer Klasse zu erstellen, ohne den Konstruktor der Klasse aufzurufen?

Ich habe Klasse A und beim Erstellen einer Instanz davon übergeben Sie Datei und im Konstruktor der Klasse A am Öffnen der Datei.

Jetzt in Klasse A, gibt es eine Funktion, die ich aufrufen muss, aber bin nicht erforderlich, Datei zu übergeben, und so muss nicht Konstruktor-Funktionalität der Eröffnungsdatei als nicht übergeben Datei verwendet werden.

Also meine Frage ist, ist es möglich, auf irgendeine Weise eine Instanz einer PHP-Klasse zu erstellen, ohne seinen Konstruktor aufzurufen?

Hinweis Ich kann Funktion nicht statisch machen, da einige der Klasseneigenschaften in Funktion sind.

Antwort

12

Ein Klasse-Konstruktor wird immer aufgerufen werden. Es gibt jedoch einige Möglichkeiten, wie Sie das umgehen könnten.

Die erste Möglichkeit besteht darin, Standardwerte für Ihre Parameter im Konstruktor anzugeben und nur bestimmte Aktionen für diese Parameter auszuführen, wenn diese festgelegt sind. Zum Beispiel:

class MyClass { 
    public __construct($file = null) { 
     if ($file) { 
      // perform whatever actions need to be done when $file IS set 
     } else { 
      // perform whatever actions need to be done when $file IS NOT set 
     } 
     // perform whatever actions need to be done regardless of $file being set 
    } 
} 

Eine weitere Option ist die Klasse, so dass der Konstruktor der Kind Klasse erweitern nicht den Konstruktor der übergeordneten Klasse nicht nennen.

class MyParentClass { 
    public __construct($file) { 
     // perform whatever actions need to be done regardless of $file being set 
    } 
} 

class MyChildClass extends MyParentClass { 
    public __construct() { 
     // perform whatever actions need to be done when $file IS NOT set 
    } 
} 
+1

Oder, wie andere gezeigt haben, kann eine statische Methode Ihren Anforderungen am besten entsprechen, je nachdem, was Sie versuchen zu tun. –

+1

+1 für die Erweiterung der Klasse. Vielleicht ist es eine Klasse von einer Drittanbieter-Bibliothek, die nicht geändert werden sollte ... –

+0

+1 für die guten alternativen Lösungen. – Yacoby

2

Wäre es nicht besser, die Funktion zu machen, die Sie benötigen static - Klasse A verändern, so dass es einen anderen Konstruktor hat, der keine aruguments


nimmt Wenn eine Klasse eine Funktion besitzt, doesn Wenn Sie auf eine der nicht statischen Eigenschaften oder Funktionen in einer Klasse zugreifen, kann sie statisch gemacht werden.

class A{ 
    public function __construct($arg1){ 
    } 

    public static function foo(){ 
     //do something that doesn't involve the class properties 
    } 
} 

Sie kann dann ohne die Klasse

//the constructor will not be called as we haven't created an instance of A 
A::foo(); 

Der Unterschied zwischen einem statischen und einem keine statische Funktion zu konstruieren, die aufgerufen werden, dass die statische Funktion nicht Klasseneigenschaften der Funktionen, die auch statisch sind zugreifen . Wenn Sie also in foo() Code haben, der $this-> verwendet, können Sie es nicht statisch machen.

+0

Wäre wirklich zu schätzen, wenn man Sie mehr über erarbeiten können Das ist mir nicht klar. – Rachel

+0

Nun, was ist der Unterschied durch den Aufruf von 'A-> foo() vs A :: foo()' – Rachel

+1

@Rachel: Sie würden '$ a-> foo()' als eine Methode einer Instanz und 'A :: foo() 'als statische Klassenmethode.Letzteres funktioniert ** nicht ** auf Instanzen der Klasse "A" und Sie müssen daher nicht 'new A()' aufrufen, um eins zu erstellen. Um eine bessere Idee zu bekommen, sollten Sie diesen Artikel lesen: http://en.wikipedia.org/wiki/Static_methods und die PHP-Dokumentation: http://www.php.net/manual/en/language.oop5.static .php –

-1

Sie könnten die Methode statisch machen und sie aus dem Klassenkontext und nicht aus dem Objektkontext aufrufen.

in Code würde es so aussehen:

class A { 
    public static function func($txt) { 
    print($txt); 
    } 
} 

A::func('test'); 
+0

Hmm, wie das Kann gemacht werden, bin mir wirklich nicht sicher. Würde mich freuen, wenn Sie darüber mehr erklären können. – Rachel

13

Hinweis: Die Lösung unten ist für PHP 5.3 und unten. Ab PHP 5.4 können Sie auch do it via Reflection as shown elsewhere on this page.

Dies ist in der Tat möglich.

Geändert von PHPUnit_Framework_MockObject_Generator

1 $myClass = unserialize(
2  sprintf(
3   'O:%d:"%s":0:{}', 
4   strlen('MyClass'), 'MyClass' 
5  ) 
6 ); 

Bitte denken Sie daran, dass Code wie das alles gut und gerechtfertigt in einem Rahmen wie PHPUnit. Aber wenn Sie Code wie diesen in Ihrem Produktionscode haben müssen, tun Sie wahrscheinlich etwas sehr merkwürdiges.


Da Sie nach einer Erklärung gefragt:

Wenn Sie Sie eine String-Darstellung des Objekts erhalten serialize an Object. Zum Beispiel

echo serialize(new StdClass) // gives O:8:"stdClass":0:{} 

Die O bedeutet Objekt. 8 ist die Zeichenfolgenlänge des Klassennamens. "stdClass" ist offensichtlich der Klassenname. Das serialisierte Objekt hat die Eigenschaften 0 (mehr dazu später), angezeigt durch die leeren geschweiften Klammern. Die : sind nur Trennzeichen.

Jede serialisierte Zeichenfolge kann mit der Funktion unserialize in ihrem ursprünglichen "Live" -Wert wiederhergestellt werden. Dadurch wird der Konstruktor umgangen. Wie Charles richtig darauf hingewiesen hat, wird die magic method __wakeup() aufgerufen, wenn sie definiert ist (genau wie __sleep() wird bei der Serialisierung aufgerufen werden).

In Zeile 3 sehen Sie eine Zeichenfolge, die für die Verwendung mit sprintf (Zeile 2) vorbereitet wurde. Wie Sie sehen können, ist die String-Länge des Klassennamens %d und der Klassenname ist %s. Dies dient dazu, sprintf mitzuteilen, dass es das erste Argument in Zeile 4 als Ziffer und das zweite Argument als Zeichenfolge verwenden soll. Daher ist das Ergebnis der sprintf Anruf

'O:7:"MyClass":0:{}' 

Sie würden beide Vorkommen von „MyClass“ in Zeile 4 mit der gewünschten Klassennamen ersetzen, um eine serialisierte Zeichenfolge der Klasse, die Sie ohne Berufung auf den Controller instanziiert erstellen möchten.

Diese Zeichenfolge wird dann in Zeile 1 in eine MyClass-Instanz unserialisiert, wobei der Konstruktor umgangen wird. Die unserialisierte Instanz wird alle Methoden ihrer Klasse und auch alle Eigenschaften haben. Wenn in MyClass Eigenschaften vorhanden sind, haben diese ihre Standardwerte, es sei denn, Sie fügen der serialisierten Dummy-Zeichenfolge andere Werte hinzu.

Und das ist es schon. Nichts Magisches daran.

+0

Das ist sehr schwer zu verstehen. Kannst du ihm eine Erklärung hinzufügen? – Rachel

+1

Dieser Code erstellt manuell eine serialisierte Darstellung der Klasse und deserialisiert sie dann. Dies erstellt eine neue Kopie des Objekts, ohne den Konstruktor aufzurufen. Es wird jedoch versuchen, die __wakeup() -Methode aufzurufen. – Charles

+0

@Rachel @Charles hat einen guten Job gemacht, es bereits zu summieren, aber siehe auch meine detaillierte Erklärung. – Gordon

17

In Ihrem Fall würde ich empfehlen, darüber nachzudenken, Ihren Code neu zu entwerfen, so dass Sie solche Dinge nicht tun müssen, aber Sie zu beantworten Frage: ja, es ist möglich.

können Sie ReflectionClass verwenden und es ist Methode newInstanceWithoutConstructor in eingeführt PHP 5.4 Dann ist es sehr einfach, eine Instanz einer Klasse zu erstellen, ohne den Konstruktor aufrufen:

$reflection = new ReflectionClass("ClassName"); 
$instance = $reflection->newInstanceWithoutConstructor(); //That's it! 
+3

Es ist nichts wert, dass 'newInstanceWithoutConstructor()' mit PHP 5.4.0 verfügbar sein wird. Es ist in keiner Version von PHP 5.3 oder niedriger verfügbar. – salathe

+0

Danke für die Info. Die PHP-Dokumentation hat mich ausgetrickst ... –

Verwandte Themen