Files
doc-fr/language/oop5/decon.xml
2022-04-10 00:59:42 +01:00

388 lines
14 KiB
XML

<?xml version="1.0" encoding="utf-8"?>
<!-- EN-Revision: 18b39f03ef77080a349f6cd2d82112dd43f904c2 Maintainer: yannick Status: ready -->
<!-- Reviewed: no -->
<sect1 xml:id="language.oop5.decon" xmlns="http://docbook.org/ns/docbook">
<title>Constructeurs et destructeurs</title>
<sect2 xml:id="language.oop5.decon.constructor">
<title>Constructeur</title>
<methodsynopsis xml:id="object.construct">
<type>void</type><methodname>__construct</methodname>
<methodparam rep="repeat"><type>mixed</type><parameter>values</parameter><initializer>""</initializer></methodparam>
</methodsynopsis>
<para>
PHP permet aux développeurs de déclarer des constructeurs pour
les classes. Les classes qui possèdent une méthode constructeur
appellent cette méthode à chaque création d'une nouvelle instance
de l'objet, ce qui est intéressant pour toutes les initialisations
dont l'objet a besoin avant d'être utilisé.
</para>
<note>
<simpara>
Les constructeurs parents ne sont pas appelés implicitement
si la classe enfant définit un constructeur. Si vous
voulez utiliser un constructeur parent, il sera nécessaire de faire
appel à <literal>parent::__construct()</literal> depuis le constructeur enfant.
Si l'enfant ne définit pas un constructeur alors il peut être hérité
de la classe parent, exactement de la même façon qu'une méthode le serait
(si elle n'a pas été déclarée comme privée).
</simpara>
</note>
<example>
<title>Constructeur lors de l'héritage</title>
<programlisting role="php">
<![CDATA[
<?php
class BaseClass {
function __construct() {
print "Dans le constructeur de BaseClass\n";
}
}
class SubClass extends BaseClass {
function __construct() {
parent::__construct();
print "Dans le constructeur de SubClass\n";
}
}
class OtherSubClass extends BaseClass {
// Constructeur hérité de BaseClass
}
// Dans le constructeur de BaseClass
$obj = new BaseClass();
// Dans le constructeur de BaseClass
// Dans le constructeur de SubClass
$obj = new SubClass();
// Dans le constructeur de BaseClass
$obj = new OtherSubClass();
?>
]]>
</programlisting>
</example>
<para>
À la différence des autres méthodes, <link linkend="object.construct">__construct()</link>
est exclus des <link linkend="language.oop.lsp">règles de compatibilités des signatures</link>
usuel quand elle est étendue.
</para>
<para>
Les constructeurs sont des méthodes ordinaires qui sont appelées lors de
l'instanciation de leur objet correspondant. Par conséquent, ils peuvent
définir un nombre arbitraire d'arguments, qui peuvent être requis, avoir un type,
et peuvent avoir une valeur par défaut. Les arguments d'un constructeur sont appelés
en plaçant les arguments dans des parenthèses après le nom de la classe.
</para>
<example>
<title>Utiliser les arguments d'un constructeur</title>
<programlisting role="php">
<![CDATA[
<?php
class Point {
protected int $x;
protected int $y;
public function __construct(int $x, int $y = 0) {
$this->x = $x;
$this->y = $y;
}
}
// Pass both parameters.
$p1 = new Point(4, 5);
// Pass only the required parameter. $y will take its default value of 0.
$p2 = new Point(4);
// With named parameters (as of PHP 8.0):
$p3 = new Point(y: 5, x: 4);
?>
]]>
</programlisting>
</example>
<para>
Si une classe n'a pas de constructeur, ou que le constructeur n'a pas d'arguments requis,
les parenthèses peuvent être omises.
</para>
<sect3>
<title>Style ancien des constructeurs</title>
<para>
Antérieur à PHP 8.0.0, les classes dans le nom d'espace global interpréteront une
méthode qui à la même nom que la classe comme un constructeur de style ancien.
Cette syntaxe est obsolète, et résultera en une erreur <constant>E_DEPRECATED</constant>
mais appellera quand même cette fonction comme un constructeur.
Si <link linkend="object.construct">__construct()</link> et une méthode du même nom
sont définie, <link linkend="object.construct">__construct()</link> sera appelé.
</para>
<para>
Les classes dans les espaces de nom, ou toute classe à partir de PHP 8.0.0,
une méthode du même nom que la classe n'a jamais de signification particulière.
</para>
<para>
Toujours utiliser <link linkend="object.construct">__construct()</link> dans du nouveau code.
</para>
</sect3>
<sect3 xml:id="language.oop5.decon.constructor.promotion">
<title>Promotion du Constructeur</title>
<para>
À partir de PHP 8.0.0, les paramètres du constructeur peuvent être promus pour
correspondre à une propriété de l'objet. Il est très commun pour les paramètres
d'un constructeur d'être assigné à une propriété sans effectuer d'opérations dessus.
La promotion du constructeur fournie un raccourci pour ce cas d'utilisation.
L'exemple ci-dessus peut être réécrit de la façon suivante.
</para>
<example>
<title>Utilisant la promotion de propriété de constructeur</title>
<programlisting role="php">
<![CDATA[
<?php
class Point {
public function __construct(protected int $x, protected int $y = 0) {
}
}
]]>
</programlisting>
</example>
<para>
Quand un argument de constructeur inclus un modificateur de visibilité, PHP l'interprétera
comme une propriété d'objet et un argument du constructeur, et assigne la valeur de l'argument
à la propriété. Le corps du constructeur peut être alors vide ou peut contenir d'autres
déclarations. Toutes déclarations additionnelles seront exécutées après que la valeur de
l'argument a été assignée à sa propriété correspondante.
</para>
<para>
Tous les arguments ne doivent pas être promus. Il est possible de mélanger et assortir les
arguments promus et non-promus, dans n'importe quel ordre. Les arguments promus n'ont aucun impact
sur du code appellant le constructeur.
</para>
<note>
<para>
Les propriétés d'objet ne peuvent être typés <type>callable</type> à cause des ambiguïtés du moteur
que ceci introduirait. Ainsi, les arguments promus, ne peuvent pas non plus être typés
<type>callable</type>. Cependant, toute autre
<link linkend="language.types.declarations">déclaration de type</link> est permise.
</para>
</note>
<note>
<para>
Les <link linkend="language.attributes">attributs</link> placés sur un
argument de constructeur promu seront reproduits à la fois sur la
propriété et sur l'argument.
</para>
</note>
</sect3>
<sect3 xml:id="language.oop5.decon.constructor.new">
<title>New in initializers</title>
<para>
À partir de PHP 8.1.0, les objets peuvent être utilisé comme valeur par défaut pour les paramètres,
variables statiques, constantes globales et les arguments d'attributs.
Les objets peuvent être désormais passé à <function>define</function>.
</para>
<note>
<para>
L'utilisation d'un nom de classe dynamique ou non-string ou une class anonyme n'est pas permit.
L'utilisation de déballage d'argument n'est pas permit.
L'utilisation d'expressions pas supportées en tant qu'argument n'est pas permit.
</para>
</note>
<example>
<title>Utilisation de new dans des initialiseurs</title>
<programlisting role="php">
<![CDATA[
<?php
// All allowed:
static $x = new Foo;
const C = new Foo;
function test($param = new Foo) {}
#[AnAttribute(new Foo)]
class Test {
public function __construct(
public $prop = new Foo,
) {}
}
// All not allowed (compile-time error):
function test(
$a = new (CLASS_NAME_CONSTANT)(), // dynamic class name
$b = new class {}, // anonymous class
$c = new A(...[]), // argument unpacking
$d = new B($abc), // unsupported constant expression
) {}
?>
]]>
</programlisting>
</example>
</sect3>
<sect3 xml:id="language.oop5.decon.constructor.static">
<title>Méthode de création statique</title>
<para>
PHP supporte uniquement un constructeur unique par classe. Cependant, dans
certains cas il peut être désirable de permettre à un objet d'être construit
de manière différente avec des entrées différentes.
La façon recommandée de faire ceci est en utilisant des méthodes statiques
comme une enveloppe du constructeur.
</para>
<example>
<title>Utilisant la création via une méthode statique</title>
<programlisting role="php">
<![CDATA[
<?php
class Product {
private ?int $id;
private ?string $name;
private function __construct(?int $id = null, ?string $name = null) {
$this->id = $id;
$this->name = $name;
}
public static function fromBasicData(int $id, string $name): static {
$new = new static($id, $name);
return $new;
}
public static function fromJson(string $json): static {
$data = json_decode($json);
return new static($data['id'], $data['name']);
}
public static function fromXml(string $xml): static {
// Logique personnalisé.
$data = convert_xml_to_array($xml);
$new = new static();
$new->id = $data['id'];
$new->name = $data['name'];
return $new;
}
}
$p1 = Product::fromBasicData(5, 'Widget');
$p2 = Product::fromJson($some_json_string);
$p3 = Product::fromXml($some_xml_string);
]]>
</programlisting>
</example>
<para>
Le constructeur peut être rendu privé ou protégé pour empêcher son appel
depuis l'extérieur. Dans ce cas, seul une méthode statique sera capable
d'instancier la classe. Car elles sont dans la même définition de classe
elles ont accès aux méthodes privées, même dans une instance différente de
l'objet. Un constructeur privé est optionnel et peut ou pas faire de sens
en fonction du cas d'utilisation.
</para>
<para>
Les trois méthodes statiques publiques démontrent alors des manières différentes
d'instancier l'objet.
</para>
<simplelist>
<member><code>fromBasicData()</code> prend les paramètres exacts qui sont nécessaires,
puis créé l'objet en appellant le constructeur puis retournant le résultat.</member>
<member><code>fromJson()</code> accepte une chaîne de caractère JSON et fait
du pré-traitement sur lui même pour ce convertir dans le format désiré par
le constructeur. Elle retourne alors le nouvel objet.</member>
<member>
<code>fromXml()</code> accepte une chaîne de caractère XML, fait du pré-traitement,
puis créé un objet brut. Le constructeur est appelé, mais comme tout les
paramètres sont optionnels la méthode les ignore. Elle assigne alors les
valeurs aux propriétés de l'objet directement avant de retourner le résultat.
</member>
</simplelist>
<para>
Dans les trois cas, le mot clé <code>static</code> est traduit en le nom de
la classe dont le code y est. Dans ce cas, <code>Product</code>.
</para>
</sect3>
</sect2>
<sect2 xml:id="language.oop5.decon.destructor">
<title>Destructeur</title>
<methodsynopsis xml:id="object.destruct">
<type>void</type><methodname>__destruct</methodname>
<void />
</methodsynopsis>
<para>
PHP possède un concept de destructeur similaire à celui d'autres langages
orientés objet, comme le <literal>C++</literal>. La méthode destructeur est appelée
dès qu'il n'y a plus de référence sur un objet donné, ou dans n'importe quel
ordre pendant la séquence d'arrêt.
</para>
<example>
<title>Exemple avec un Destructeur</title>
<programlisting role="php">
<![CDATA[
<?php
class MyDestructableClass
{
function __construct() {
print "In constructor\n";
}
function __destruct() {
print "Destroying " . __CLASS__ . "\n";
}
}
$obj = new MyDestructableClass();
]]>
</programlisting>
</example>
<para>
Tout comme le constructeur, le destructeur parent ne sera pas appelé
implicitement par le moteur. Pour exécuter le destructeur parent, vous
devez appeler explicitement la fonction
<literal>parent::__destruct</literal> dans le corps du destructeur.
Tout comme les constructeurs, une classe enfant peut hériter du
destructeur du parent s'il n'en implémente pas un lui même.
</para>
<para>
Le destructeur sera appelé même si l'exécution du script est stoppée
en utilisant la fonction <function>exit</function>.
Appeler la fonction <function>exit</function>
dans un destructeur empêchera l'exécution des routines d'arrêt restantes.
</para>
<note>
<para>
Les destructeurs appelés durant l'arrêt du script sont dans une situation
où les en-têtes HTTP ont déjà été envoyés.
Le dossier de travail dans la phase d'arrêt du script
peut être différent avec certaines APIs (e.g. Apache).
</para>
</note>
<note>
<para>
Tenter de lancer une exception depuis un destructeur (appelé à la fin du script)
entraine une erreur fatale.
</para>
</note>
</sect2>
</sect1>
<!-- Keep this comment at the end of the file
Local variables:
mode: sgml
sgml-omittag:t
sgml-shorttag:t
sgml-minimize-attributes:nil
sgml-always-quote-attributes:t
sgml-indent-step:1
sgml-indent-data:t
indent-tabs-mode:nil
sgml-parent-document:nil
sgml-default-dtd-file:"~/.phpdoc/manual.ced"
sgml-exposed-tags:nil
sgml-local-catalogs:nil
sgml-local-ecat-files:nil
End:
vim600: syn=xml fen fdm=syntax fdl=2 si
vim: et tw=78 syn=sgml
vi: ts=1 sw=1
-->