2010-03-31 7 views
15

Est-il possible de créer une instance d'une classe php sans appeler son constructeur?En PHP, est-il possible de créer une instance d'une classe sans appeler le constructeur de la classe?

Je possède la classe A et, en en créant une instance, je passe le fichier et dans le constructeur de la classe A j'ouvre le fichier.

Maintenant dans la classe A, il y a une fonction que j'ai besoin d'appeler mais je n'ai pas besoin de passer le fichier et donc il n'est pas nécessaire d'utiliser la fonction constructeur du fichier d'ouverture. Donc, ma question est, Est-il possible par n'importe quel moyen de créer une instance d'une classe PHP sans appeler son constructeur?

note Je ne peux pas rendre la fonction statique en utilisant certaines des propriétés de classe dans la fonction.

Répondre

12

Un constructeur de classe sera toujours appelée. Cependant, il existe plusieurs façons de contourner ce problème. La première consiste à fournir des valeurs par défaut pour vos paramètres dans le constructeur, et d'effectuer uniquement certaines actions sur ces paramètres s'ils sont définis. Par exemple:

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 
    } 
} 

Une autre option est d'étendre votre classe telle que le constructeur de la classe de l'enfant ne remet pas le constructeur de la classe parente.

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

Ou, comme d'autres l'ont souligné, une méthode statique peut mieux répondre à vos besoins selon ce que vous essayez de faire. –

+1

+1 pour étendre la classe. Peut-être que c'est une classe d'une bibliothèque tierce qui ne devrait pas être changée ... –

+0

+1 pour les bonnes solutions alternatives. – Yacoby

2

Ne serait-il préférable de faire de la fonction, vous devez static - modifier la classe A de sorte qu'il a un autre constructeur qui ne prend pas aruguments


Si une classe a une fonction qui doesn N'accède à aucune des propriétés ou fonctions non statiques d'une classe, il peut être rendu statique.

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

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

Il peut alors être appelé sans avoir à construire la classe

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

La différence entre une statique et une aucune fonction statique est que la fonction statique ne peut pas accéder aux propriétés de la classe de fonctions qui sont également statiques . Donc, si dans foo() vous avez un code qui utilise $this-> vous ne pouvez pas le rendre statique.

+0

apprécierions vraiment si vous pouvez vous parler plus en détail ceci comme je ne suis pas clair avec lui. – Rachel

+0

Maintenant, quelle est la différence en appelant 'A-> foo() vs A :: foo()' – Rachel

+1

@Rachel: Vous appelez '$ a-> foo()' comme méthode d'une instance et 'A :: foo() 'en tant que méthode de classe statique.Ce dernier ne fonctionne pas ** sur les instances de la classe 'A' et vous n'avez donc pas besoin d'appeler' new A() 'pour en créer un. Pour avoir une meilleure idée, vous pouvez lire cet article: http://en.wikipedia.org/wiki/Static_methods et le document PHP: http://www.php.net/manual/fr/language.oop5.static .php –

-1

Vous pouvez rendre la méthode statique et l'appeler du contexte de classe et non du contexte d'objet.

dans le code, il ressemblerait à ceci:

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

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

Hmm, comment ça peut être fait, je ne suis vraiment pas sûr. J'apprécierais si vous pouvez donner plus d'explications à ce sujet. – Rachel

13

Note: La solution est ci-dessous pour PHP 5.3 et ci-dessous. Depuis PHP 5.4, vous pouvez aussi do it via Reflection as shown elsewhere on this page.

Ceci est en effet possible.

de Modified PHPUnit_Framework_MockObject_Generator

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

S'il vous plaît garder à l'esprit, ce code comme cela est bon et justifié dans un cadre comme PHPUnit. Mais si vous avez un code comme celui-ci dans votre code de production, vous risquez de faire quelque chose de très étrange.


Puisque vous demande une explication:

Lorsque vous serialize an Object vous obtenez une représentation de chaîne de l'objet. Par exemple

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

L'objet O signifie. 8 est la longueur de la chaîne du nom de la classe. "stdClass" est évidemment le nom de la classe. L'objet sérialisé a 0 propriétés définies (plus à cela plus tard), indiqué par les accolades vides. Les : ne sont que des délimiteurs.

Chaque chaîne sérialisée peut être recréée dans sa valeur d'origine "en direct" avec la fonction unserialize. Ce faisant, contournera le constructeur. Comme Charles a correctement souligné le magic method __wakeup() sera appelé s'il est défini (tout comme __sleep() sera appelé lors de la sérialisation).

Dans la ligne 3, vous voyez une chaîne préparée pour être utilisée avec sprintf (ligne 2). Comme vous pouvez le voir la longueur de chaîne du nom de classe est donnée comme %d et le nom de classe est donné comme %s. C'est dire à sprintf qu'il doit utiliser le premier argument passé à la ligne 4 comme un chiffre et le second comme une chaîne. Par conséquent, le résultat de l'appel sprintf est

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

vous devez remplacer les deux occurences de « MyClass » dans la ligne 4 avec votre nom de classe désirée pour créer une chaîne sérialisée de la classe que vous voulez instancier sans invoquer le contrôleur.

Cette chaîne est ensuite désérialisée dans une instance MyClass de la ligne 1, en contournant le constructeur. L'instance non sérialisée aura toutes les méthodes de sa classe et aussi toutes les propriétés. S'il existe des propriétés dans MyClass, celles-ci auront leurs valeurs par défaut, à moins que vous n'ayez ajouté des valeurs différentes à la chaîne factice sérialisée.

Et c'est déjà ça. Rien de trop magique à ce sujet.

+0

C'est très difficile à comprendre. Pouvez-vous ajouter quelques explications à cela. – Rachel

+1

Ce code crée manuellement une représentation sérialisée de la classe, puis la désérialise. Cela crée une nouvelle copie de l'objet sans appeler le constructeur. Cependant, il essayera d'appeler la méthode __wakeup(). – Charles

+0

@Rachel @Charles a fait du bon boulot en le résumant déjà, mais voyez aussi mon explication détaillée. – Gordon

17

Dans votre cas, je recommanderais de penser à la refonte de votre code afin que vous n'ayez pas besoin de faire une telle chose, mais pour répondre à votre question: oui, il est possible.

Vous pouvez utiliser ReflectionClass et sa méthode newInstanceWithoutConstructor introduit dans PHP 5.4 Ensuite, il est très facile de créer une instance d'une classe sans appeler son constructeur:

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

Cela vaut la peine que 'newInstanceWithoutConstructor()' soit disponible avec PHP 5.4.0. Il n'est disponible dans aucune version de PHP 5.3 ou ci-dessous. – salathe

+0

Merci pour l'info. La documentation PHP m'a trompé ... –

Questions connexes