Je voudrais comparer les constructeurs PHP et Java.
parent :: __ construct ()
pour appeler "constructeur de superclasse"
--Si le constructeur n'est ** pas défini dans la sous-classe **Pour ceux de Java, je vois un article qui explique:
Lors de la définition d'un constructeur, Java le définit comme une méthode portant le même nom que le nom de la classe. Par contre, en PHP, il est défini par
__construct ()
. C'est ça.
class Sample
{
public Sample() {
System.out.println("Constructor of Sample Class");
}
}
class Sample
{
public function __construct() {
echo "Constructor of Sample Class\n");
}
}
Mais est-ce vraiment la seule différence entre PHP et Java? [^ 1]
[^ 1]: Lorsque PHP 4 a introduit pour la première fois l'orientation objet, même en PHP, le constructeur était une méthode portant le même nom que le nom de la classe. Après cela, j'ai commencé à écrire __construct ()
en PHP 5, mais même si je l'ai écrit en PHP 4, il a été reconnu comme constructeur. Cependant, PHP 7 imprime maintenant une erreur "E_DEPRECATED" lorsqu'il est écrit au format PHP 4. Et à partir de la prochaine version de PHP 8, il ne sera plus reconnu comme constructeur. Voir RFC pour plus d'informations.
La différence entre PHP et Java réside dans l'utilisation de ** l'héritage **.
Java En Java, le "constructeur de superclasse" peut être appelé implicitement. [^ 2]
[^ 2]: Je pense que c'est la même chose non seulement en Java mais aussi en C ++.
public class SuperClass {
public SuperClass() {
System.out.println("Constructor of Super Class");
}
}
public class SubClass extends SuperClass {
public SubClass() {
System.out.println("Constructor of Sub Class");
}
}
public class Main {
public static void main(String[] args) {
new SubClass();
}
}
Lorsque j'exécute le code ci-dessus, j'obtiens ce qui suit:
Constructor of Super Class
Constructor of Sub Class
Le processus d'appel explicite du "constructeur de super classe" (super ()
) n'est pas écrit dans le "constructeur de sous-classe".
Cependant, dans de tels cas, Java appelle «** no argument ** superclass constructor» ** implicitement ** Language Specification. Il s'agit de public / standards / tr_javalang2 / classes.doc.html # 78435). [^ 3] Il est important de dire ** sans argument ** ici.
[^ 3]: La spécification de langue citée est une deuxième édition légèrement plus ancienne, mais la dernière [Spécification de langue](https://docs.oracle.com/javase/specs/jls/se12/html/jls-8. html # jls-8.8.7) a presque la même description.
Si le corps du constructeur n'est pas démarré par un appel de constructeur explicite et que le constructeur déclaré ne fait pas partie de la classe de classe sous-jacente Object, le corps du constructeur appelle implicitement le constructeur de classe supérieure "super (" ); "est supposé démarrer. Autrement dit, il s'agit d'un appel de constructeur qui ne prend pas un argument réel qui existe dans la classe supérieure directe.
Dans le cas du code précédent, le processus d'appel explicite du "constructeur de superclasse" n'était pas écrit dans le "constructeur de sous-classe", donc ** implicitement ** "** aucun argument ** de la superclasse" Le constructeur a été appelé.
D'un autre côté, si seulement "** constructeur avec ** arguments" est défini dans "constructeur de super classe", "** constructeur sans arguments" ne peut pas être appelé, ce qui entraîne une erreur lors de la compilation. Je vais.
public class SuperClass {
//Seuls les constructeurs avec des arguments sont définis
public SuperClass(String name) {
System.out.println("Constructor of Super Class");
}
}
public class SubClass extends SuperClass {
public SubClass() {
System.out.println("Constructor of Sub Class");
}
}
public class Main {
public static void main(String[] args) {
new SubClass();
}
}
Error:(4, 23) java:Classe com.example.Le constructeur SuperClass SuperClass ne peut pas être appliqué au type spécifié.
Valeur attendue: java.lang.String
Valeur détectée:Aucun argument
Raison:Les longueurs de la liste d'arguments réelle et de la liste d'arguments formels sont différentes.
Dans ce cas, vous devez ** explicitement ** appeler le "constructeur de superclasse" dans le "constructeur de sous-classe".
public class SuperClass {
//Seuls les constructeurs avec des arguments sont définis
public SuperClass(String name) {
System.out.println("Constructor of Super Class");
}
}
public class SubClass extends SuperClass {
public SubClass() {
//Appelez explicitement le constructeur de la superclasse
super("hoge");
System.out.println("Constructor of Sub Class");
}
}
public class Main {
public static void main(String[] args) {
new SubClass();
}
}
De plus, même si aucun constructeur n'est défini dans la sous-classe, "** constructeur de superclasse sans arguments **" peut être appelé implicitement.
public class SuperClass {
public SuperClass() {
System.out.println("Constructor of Super Class");
}
}
public class SubClass extends SuperClass {
//Constructeur de sous-classe non défini
}
public class Main {
public static void main(String[] args) {
new SubClass();
}
}
Lorsque j'exécute le code ci-dessus, j'obtiens ce qui suit:
Constructor of Super Class
Si aucun constructeur n'est défini dans la sous-classe, Java créera automatiquement un ** constructeur par défaut . Et le constructeur par défaut appelle " no argument ** super class constructor" [Spécifications du langage](http://www.y-adagio.com/public/standards/tr_javalang2/classes.doc.html# C'est 16823).
Si la classe ne contient pas de déclaration de constructeur, un constructeur par défaut qui ne prend aucun argument réel est automatiquement fourni.
--Si la classe déclarante est la classe racine Object, le constructeur par défaut a un corps vide.
- Sinon, le constructeur par défaut ne prend aucun argument réel et appelle simplement le constructeur de la classe supérieure qui n'a pas d'argument réel.
Si le compilateur fournit un constructeur par défaut, mais que l'ancêtre n'a pas de constructeur sans arguments réels, une erreur de compilation se produira.
De plus, il est appelé dans l'ordre depuis le constructeur avec la hiérarchie d'héritage la plus profonde.
public class AncestorClass {
public AncestorClass() {
System.out.println("Constructor of Ancestor Class");
}
}
public class SuperClass extends AncestorClass {
public SuperClass() {
System.out.println("Constructor of Super Class");
}
}
public class SubClass extends SuperClass {
public SubClass() {
System.out.println("Constructor of Sub Class");
}
}
public class Main {
public static void main(String[] args) {
new SubClass();
}
}
Lorsque le code ci-dessus est exécuté, il sera exécuté dans l'ordre de la hiérarchie d'héritage la plus profonde, comme indiqué ci-dessous.
SuperClass
SubClass
Constructor of Ancestor Class
Constructor of Super Class
Constructor of Sub Class
PHP D'un autre côté, PHP n'appelle pas implicitement le "constructeur de superclasse". Ce qui suit est une citation du Manuel officiel.
Remarque: Si la classe enfant a un constructeur, le constructeur de la classe parent ne sera pas appelé implicitement. Pour exécuter le constructeur de la classe parent, vous devez appeler `parent :: __ construct () ʻ dans le constructeur de la classe enfant. Si la classe enfant ne définit pas de constructeur, elle hérite du constructeur de la classe parent (sauf si elle est déclarée privée). Ceci est similaire à une méthode de classe régulière.
En PHP, l'héritage du constructeur peut être considéré comme un remplacement de méthode normal. En d'autres termes, si vous définissez un constructeur dans une sous-classe, vous remplacez le constructeur dans la superclasse.
Par conséquent, en PHP, vous pouvez créer une règle simple comme celle-ci:
règle
--Si le constructeur est ** défini dans la sous-classe **
parent :: __ construct ()
pour appeler "constructeur de superclasse"
--Si le constructeur n'est ** pas défini dans la sous-classe **Si un constructeur est ** défini dans une sous-classe, ** seul le "constructeur de sous-classe" ** sera appelé. ** Le "constructeur de superclasse" n'est jamais appelé implicitement. ** **
class SuperClass {
public function __construct() {
echo "Constructor of Super Class\n";
}
}
class SubClass extends SuperClass {
public function __construct() {
echo "Constructor of Sub Class\n";
}
}
new SubClass();
Constructor of Sub Class
De plus, contrairement aux remplacements de méthode normaux, les constructeurs sont exceptionnellement considérés comme des remplacements même s'ils ont des signatures différentes (Manuel officiel. oop5.basic.php)).
Lors du remplacement d'une méthode, les signatures de paramètres doivent être identiques. Sinon, PHP donnera une erreur de niveau E_STRICT. L'exception est le constructeur, qui peut être remplacé par différents paramètres.
En bref, ** lorsqu'un constructeur est défini dans une sous-classe, seul le "constructeur de sous-classe" est appelé **.
class SuperClass {
public function __construct() {
echo "Constructor of Super Class\n";
}
}
class SubClass2 extends SuperClass {
//Certains arguments ne sont pas dans le constructeur de la superclasse
public function __construct(String $name) {
echo "Constructor of Sub Class\n";
}
}
new SubClass2('hoge');
Constructor of Sub Class
Si la sous-classe ** n'a pas de constructeur défini **, alors ** "Super Class Constructor" ** est appelé.
class SuperClass {
public function __construct() {
echo "Constructor of Super Class\n";
}
}
class SubClass3 extends SuperClass {}
new SubClass3();
Constructor of Super Class
Pour appeler le "constructeur de superclasse" depuis le "constructeur de sous-classe", appelez parent :: __ construct ()
.
parent :: __ construct ()
est l'équivalent Java de super ()
, mais beaucoup plus libre que le super ()
contraint de diverses manières.
class SuperClass {
public function __construct() {
echo "Constructor of Super Class\n";
}
}
class SubClass4 extends SuperClass {
public function __construct() {
//Il n'est pas nécessaire que ce soit la première ligne
echo "Constructor of Sub Class Called\n";
//Vous pouvez appeler autant de fois que vous le souhaitez
parent::__construct();
parent::__construct();
}
}
new SubClass4();
Notez que nous avons appelé parent :: __ construct ()
deux fois, donc nous voyons deux lignes de " Constructor of Super Class "
.
Constructor of Sub Class Called
Constructor of Super Class
Constructor of Super Class
Notez que PHP n'appelle pas ** implicitement ** le "constructeur de superclasse", donc ** automatiquement ** n'appelle pas dans l'ordre depuis le constructeur avec la hiérarchie d'héritage la plus profonde.
Si vous voulez faire cela, vous devez appeler explicitement parent :: construct ()
dans chaque classe.
J'ai été surpris d'entendre que "l'orientation objet de PHP n'est-elle pas mauvaise?", Alors je l'ai essayé avec Ruby, qui est un langage naturel orienté objet.
Je n'entrerai pas dans les détails, mais vous pouvez voir qu'il se comporte comme PHP.
#Super classe
class SuperClass
def initialize
puts 'initialize of Super Class'
end
end
#Sous-classe
#Seuls les constructeurs de sous-classes sont appelés
class SubClass < SuperClass
def initialize
puts 'initialize of Sub Class'
end
end
#Sous-classe 2
#Seuls les constructeurs de sous-classes sont appelés
class SubClass2 < SuperClass
#Certains arguments ne sont pas dans le constructeur de la superclasse
def initialize name
puts 'initialize of Sub Class'
end
end
#Sous-classe 3
#Si vous n'avez pas défini de constructeur
#Le constructeur de superclasse est appelé
class SubClass3 < SuperClass
end
#Sous-classe 4
#Lors de l'appel de la super méthode
#La méthode de la superclasse du même nom (initialize) est appelée
class SubClass4 < SuperClass
def initialize
super
end
end
puts 'SubClass'
SubClass.new
puts 'SubClass2'
SubClass2.new('name')
puts 'SubClass3'
SubClass3.new
puts 'SubClass4'
SubClass4.new
SubClass
initialize of Sub Class
SubClass2
initialize of Sub Class
SubClass3
initialize of Super Class
SubClass4
initialize of Super Class
Java
PHP
Ruby
Dans mon goût personnel, je préfère PHP et Ruby car je n'aime pas pouvoir bouger derrière. [^ 5]
Cependant, considérant que ** l'héritage ** devrait être est-une relation, PHP qui ne fait pas "d'appels de constructeur implicites" En Ruby, je pense aussi que les sous-classes peuvent hériter de superclasses qui n'ont rien à voir avec elles.
De ce point de vue, il est naturel que les «appels de constructeur implicites» le soient, et je pense que les programmes qui causent des problèmes de cette manière ne sont pas orientés objet en premier lieu.
[^ 5]: C'est peut-être parce que PHP a été le premier langage orienté objet (?) Que j'ai mentionné. Ou est-ce tout à propos de ça?
Recommended Posts