Files
doc-fr/language/types/string.xml
2022-05-27 17:46:58 -04:00

1444 lines
43 KiB
XML

<?xml version="1.0" encoding="utf-8"?>
<!-- EN-Revision: 59244d9ae93cc5059a07c7eadf36b02a1704512c Maintainer: yannick Status: ready -->
<!-- Reviewed: no Maintainer: girgias -->
<sect1 xml:id="language.types.string">
<title>Les chaînes de caractères</title>
<para>
Une &string; est une série de caractères, où un caractère est
la même chose qu'un octet. De ce fait, PHP ne supporte que les jeux de
caractères comportant 256 caractères différents, et, donc,
n'a pas de support natif pour l'Unicode.
Reportez-vous aux
<link linkend="language.types.string.details">détails sur le type
chaîne de caractères
</link>
pour plus d'informations.
</para>
<note>
<simpara>
Sur les systèmes 32-bit une &string; peut être d'une taille allant
jusqu'au plus 2Go (2147483647 octets maximum).
</simpara>
</note>
<sect2 xml:id="language.types.string.syntax">
<title>Syntaxe</title>
<para>
Une &string; littérale peut être spécifiée de 4 façons différentes :
</para>
<itemizedlist>
<listitem>
<simpara>
<link linkend="language.types.string.syntax.single">Guillemets simples</link>
</simpara>
</listitem>
<listitem>
<simpara>
<link linkend="language.types.string.syntax.double">Guillemets doubles</link>
</simpara>
</listitem>
<listitem>
<simpara>
<link linkend="language.types.string.syntax.heredoc">Syntaxe Heredoc</link>
</simpara>
</listitem>
<listitem>
<simpara>
<link linkend="language.types.string.syntax.nowdoc">Syntaxe Nowdoc</link>
</simpara>
</listitem>
</itemizedlist>
<sect3 xml:id="language.types.string.syntax.single">
<title>Guillemets simples</title>
<para>
La façon la plus simple de spécifier une &string; est de l'entourer de guillemets
simples (le caractère <literal>'</literal>).
</para>
<para>
Pour spécifier un guillemet simple littéral, il doit être échappé à l'aide
d'un antislash (<literal>\</literal>). Pour spécifier un antislash littéral,
doublez-le (<literal>\\</literal>).
Toute les autres instances d'antislash seront traitées comme un antislash
littéral : ce qui signifie que les autres séquences auquelles vous
êtes éventuellement habitués (comme <literal>\r</literal> ou <literal>\n</literal>)
s'afficheront telles quelles, sans avoir une quelconque signification particulière.
</para>
<note>
<simpara>
Contrairement aux syntaxes avec
<link linkend="language.types.string.syntax.double">double guillemets</link>
et <link linkend="language.types.string.syntax.heredoc">heredoc</link>, les
<link linkend="language.variables">variables</link>
et les séquences d'échappement
pour les caractères spéciaux ne seront <emphasis>pas</emphasis> interprétées lorsqu'elles
figurent dans une &string; entourée de guillemets simples.
</simpara>
</note>
<informalexample>
<programlisting role="php">
<![CDATA[
<?php
echo 'ceci est une chaîne simple';
echo 'Vous pouvez également ajouter des nouvelles lignes
dans vos chaînes
de cette façon';
// Affiche : Arnold a dit : "I'll be back"
echo 'Arnold a dit : "I\'ll be back"';
// Affiche : Voulez-vous supprimer C:\*.*?
echo 'Voulez-vous supprimer C:\\*.*?';
// Affiche : Voulez-vous supprimer C:\*.*?
echo 'Voulez-vous supprimer C:\*.*?';
// Affiche : Ceci n'affichera pas \n de nouvelle ligne
echo 'Ceci n\'affichera pas \n de nouvelle ligne';
// Affiche : Les variables ne seront pas $traitees $ici
echo 'Les variables ne seront pas $traitees $ici';
?>
]]>
</programlisting>
</informalexample>
</sect3>
<sect3 xml:id="language.types.string.syntax.double">
<title>Guillemets doubles</title>
<para>
Si la &string; est entourée de guillemets doubles ("), PHP interprétera
les séquences d'échappement suivantes pour les caractères spéciaux :
</para>
<table>
<title>Caractères échappés</title>
<tgroup cols="2">
<thead>
<row>
<entry>Séquence</entry>
<entry>Signification</entry>
</row>
</thead>
<tbody>
<row>
<entry>
<literal>\n</literal>
</entry>
<entry>Fin de ligne (LF ou 0x0A (10) en ASCII)</entry>
</row>
<row>
<entry>
<literal>\r</literal>
</entry>
<entry>Retour à la ligne (CR ou 0x0D (13) en ASCII)</entry>
</row>
<row>
<entry>
<literal>\t</literal>
</entry>
<entry>Tabulation horizontale (HT or 0x09 (9) en ASCII)</entry>
</row>
<row>
<entry>
<literal>\v</literal>
</entry>
<entry>Tabulation verticale (VT ou 0x0B (11) en ASCII)</entry>
</row>
<row>
<entry>
<literal>\e</literal>
</entry>
<entry>échappement (ESC or 0x1B (27) en ASCII)</entry>
</row>
<row>
<entry>
<literal>\f</literal>
</entry>
<entry>Saut de page (FF ou 0x0C (12) en ASCII)</entry>
</row>
<row>
<entry>
<literal>\\</literal>
</entry>
<entry>Antislash</entry>
</row>
<row>
<entry>
<literal>\$</literal>
</entry>
<entry>Signe dollar</entry>
</row>
<row>
<entry>
<literal>\"</literal>
</entry>
<entry>Guillemet double</entry>
</row>
<row>
<entry>
<literal>\[0-7]{1,3}</literal>
</entry>
<entry>
La séquence de caractères correspondant à cette expression rationnelle
est un caractère, en notation octale, qui débordera
silencieusement pour s'adapter à un octet
(e.g. "\400" === "\000")
</entry>
</row>
<row>
<entry>
<literal>\x[0-9A-Fa-f]{1,2}</literal>
</entry>
<entry>
La séquence de caractères correspondant à cette expression rationnelle
est un caractère, en notation hexadécimale
</entry>
</row>
<row>
<entry>
<literal>\u{[0-9A-Fa-f]+}</literal>
</entry>
<entry>
La séquence de caractères correspondant à
l'expression régulière est un point de code Unicode, qui
sera la sortie de la chaîne de caractères
représentant le codepoint UTF-8
</entry>
</row>
</tbody>
</tgroup>
</table>
<para>
De la même façon que pour les &string; entourées de guillemets simples,
l'échappement de tout autre caractère affichera l'antislash.
</para>
<para>
La fonctionnalité la plus intéressante des &string; guillemets doubles
est que les noms de variables seront interprétés. Voir la documentation sur
<link linkend="language.types.string.parsing">l'analyse des chaînes de caractères</link>
pour plus de détails.
</para>
</sect3>
<sect3 xml:id="language.types.string.syntax.heredoc">
<title>Syntaxe Heredoc</title>
<simpara>
Une troisième façon de délimiter une &string; est la syntaxe Heredoc :
<literal>&lt;&lt;&lt;</literal>. Après cet opérateur, un identifiant
est fourni, suivi d'une nouvelle ligne. La &string; en elle-même vient ensuite,
suivie du même identifiant pour fermer la notation.
</simpara>
<simpara>
L'identifiant de fin peut être indenté par des espaces ou tabulations,
au quel cas l'indentation sera retirée de toutes les lignes dans la
chaîne de caractères doc.
Antérieur à PHP 7.3.0, l'identifiant de fin
<emphasis>doit</emphasis>
commencer à la première colonne de la ligne.
</simpara>
<simpara>
De plus, l'identifiant doit suivre les mêmes règles que n'importe quel
autre libellé PHP : il ne doit contenir que des caractères alphanumériques
et des soulignés, et doit commencer par un caractère non numérique ou un
souligné (<literal>"underscore"</literal>).
</simpara>
<example>
<title>Example Heredoc basique à partir de PHP 7.3.0</title>
<programlisting role="php">
<![CDATA[
<?php
// no indentation
echo <<<END
a
b
c
\n
END;
// 4 spaces of indentation
echo <<<END
a
b
c
END;
]]>
</programlisting>
&example.outputs.73;
<screen>
<![CDATA[
a
b
c
a
b
c
]]>
</screen>
</example>
<simpara>
Si l'identifiant de fin est indenté plus que n'importe quelle ligne du texte,
alors une <classname>ParseError</classname> sera lancée :
</simpara>
<example>
<title>Closing identifier must not be indented further than any lines of the body</title>
<programlisting role="php">
<![CDATA[
<?php
echo <<<END
a
b
c
END;
]]>
</programlisting>
&example.outputs.73;
<screen>
<![CDATA[
PHP Parse error: Invalid body indentation level (expecting an indentation level of at least 3) in example.php on line 4
]]>
</screen>
</example>
<simpara>
Si l'identifiant de fin est indenté, alors les tabulations peuvent aussi
être utilisé, néanmoins, les tabulations et les espaces <emphasis>ne
doivent pas
</emphasis> être mélangé en ce qui concerne l'indentation de
l'identifiant et l'indentation du texte (jusqu'à l'identifiant de fin).
Dans quelconque de ces cas, une <classname>ParseError</classname> sera lancée.
Ces contraintes sur les caractères d'espacement blanc ont été incluse car
le mélange de tabulations et d'espaces pour l'indentation est nuisible à
la lisibilité.
</simpara>
<example>
<title>Indentation différente pour le texte (espace) et identifiant de fin</title>
<programlisting role="php">
<![CDATA[
<?php
// All the following code do not work.
// different indentation for body (spaces) ending marker (tabs)
{
echo <<<END
a
END;
}
// mixing spaces and tabs in body
{
echo <<<END
a
END;
}
// mixing spaces and tabs in ending marker
{
echo <<<END
a
END;
}
]]>
</programlisting>
&example.outputs.73;
<screen>
<![CDATA[
PHP Parse error: Invalid indentation - tabs and spaces cannot be mixed in example.php line 8
]]>
</screen>
</example>
<simpara>
L'identifiant de fin du corps du texte n'est pas requis d'être suivi
d'une point virgule ou une nouvelle ligne. Par example, le code suivant
est autorisé à partir de PHP 7.3.0:
</simpara>
<example>
<title>Continuer une expression après un identifiant de fin</title>
<programlisting role="php">
<![CDATA[
<?php
$values = [<<<END
a
b
c
END, 'd e f'];
var_dump($values);
]]>
</programlisting>
&example.outputs.73;
<screen>
<![CDATA[
array(2) {
[0] =>
string(11) "a
b
c"
[1] =>
string(5) "d e f"
}
]]>
</screen>
</example>
<warning>
<simpara>
Si l'identifiant de fin a été trouvé au début d'une ligne, alors peut
importe s'il fait partie d'un autre mot, il peut être considéré comme
l'identifiant de fin et causer une <classname>ParseError</classname>.
</simpara>
<example>
<title>Identifiant de fin dans le corps de la chaîne de caractères tend à causer une ParseError</title>
<programlisting role="php">
<![CDATA[
<?php
$values = [<<<END
a
b
END ING
END, 'd e f'];
]]>
</programlisting>
&example.outputs.73;
<screen>
<![CDATA[
PHP Parse error: syntax error, unexpected identifier "ING", expecting "]" in example.php on line 6
]]>
</screen>
</example>
<simpara>
Pour éviter ce problème, il suffit de suivre cette règle simple :
<emphasis>ne pas choisir l'identifiant de fin qui apparait dans le
corps du texte</emphasis>.
</simpara>
</warning>
<warning>
<simpara>
Antérieur à PHP 7.3.0, il est très important de noter que la ligne
contenant l'identifiant de fin ne doit contenir aucun autre caractère,
mis à part un point-virgule (<literal>;</literal>).
Cela signifie en particulier que l'identifiant
<emphasis>ne doit pas être indenté</emphasis>, et qu'il ne doit y avoir aucun
espace ou tabulation avant ou après le point-virgule. Il est également important
de garder à l'esprit que le premier caractère avant l'identifiant de fermeture
doit être une nouvelle ligne telle que définie par le système d'exploitation ; sur les
systèmes Unix, incluant macOS, il s'agit du caractère <literal>\n</literal>.
Le délimiteur de fermeture doit aussi être suivi d'une nouvelle ligne.
</simpara>
<simpara>
Si cette règle n'est pas respectée et que l'identifiant de fermeture
n'est pas "propre", il ne sera pas considéré comme identifiant de fermeture,
et PHP continuera à en chercher un. Si un identifiant de fermeture "propre"
n'est pas trouvé avant la fin du fichier courant, une erreur d'analyse
sera émise à la dernière ligne.
</simpara>
<example>
<title>Exemple invalide, antérieur à PHP 7.3.0</title>
<programlisting role="php">
<!-- Ceci est un exemple INVALIDE -->
<![CDATA[
<?php
class foo {
public $bar = <<<EOT
bar
EOT;
}
// L'identifiant ne doit pas être indenté
?>
]]>
</programlisting>
</example>
<example>
<title>Exemple valide, même antérieur à PHP 7.3.0</title>
<programlisting role="php">
<!-- Ceci est un exemple VALIDE -->
<![CDATA[
<?php
class foo {
public $bar = <<<EOT
bar
EOT;
}
?>
]]>
</programlisting>
</example>
<para>
Heredoc contenant des variables ne peuvent être utilisé pour initialiser
les propriétés d'une classe.
</para>
</warning>
<para>
Heredoc se comporte exactement comme une &string; guillemets doubles,
sans les guillemets doubles. Cela signifie que les guillemets dans une
syntaxe Heredoc n'ont pas besoin d'être échappés, mais que les codes d'échappement
listés plus haut peuvent toujours être utilisés. Les variables seront interprétées,
mais les mêmes précautions doivent être prises lorsque des variables complexes
sont exprimées dans une Heredoc comme avec &string;.
</para>
<example>
<title>Exemple de chaînes Heredoc</title>
<programlisting role="php">
<![CDATA[
<?php
$str = <<<EOD
Exemple de chaîne
sur plusieurs lignes
en utilisant la syntaxe Heredoc.
EOD;
/* Exemple plus complexe, avec des variables. */
class foo
{
var $foo;
var $bar;
function __construct()
{
$this->foo = 'Foo';
$this->bar = array('Bar1', 'Bar2', 'Bar3');
}
}
$foo = new foo();
$name = 'MyName';
echo <<<EOT
Mon nom est "$name". J'affiche quelques $foo->foo.
Maintenant, j'affiche quelques {$foo->bar[1]}.
Et ceci devrait afficher un 'A' majuscule : \x41
EOT;
?>
]]>
</programlisting>
&example.outputs;
<screen>
<![CDATA[
Mon nom est "MyName". J'affiche quelques Foo.
Maintenant, j'affiche quelques Bar2.
Et ceci devrait afficher un 'A' majuscule : A
]]>
</screen>
</example>
<para>
Il est aussi possible d'utiliser la syntaxe Heredoc
pour passer des données en paramètre à une fonction :
</para>
<example>
<title>Exemple d'utilisation de Heredoc pour passer des arguments</title>
<programlisting role="php">
<![CDATA[
<?php
var_dump(array(<<<EOD
foobar!
EOD
));
]]>
</programlisting>
</example>
<para>
Il est possible d'initialiser les variables statiques et les propriétés
ou constantes de classes avec la syntaxe Heredoc :
</para>
<example>
<title>Utilisation de Heredoc pour initialiser des valeurs statiques</title>
<programlisting role="php">
<![CDATA[
<?php
// Variables statiques
function foo()
{
static $bar = <<<LABEL
Nothing in here...
LABEL;
}
// Constantes et propriétés de classe
class foo
{
const BAR = <<<FOOBAR
Constant example
FOOBAR;
public $baz = <<<FOOBAR
Property example
FOOBAR;
}
?>
]]>
</programlisting>
</example>
<para>
L'identifiant ouvrant Heredoc peut éventuellement
être écrit entre guillemets doubles :
</para>
<example>
<title>Utilisation des guillemets doubles avec Heredoc</title>
<programlisting role="php">
<![CDATA[
<?php
echo <<<"FOOBAR"
Hello World!
FOOBAR;
?>
]]>
</programlisting>
</example>
</sect3>
<sect3 xml:id="language.types.string.syntax.nowdoc">
<title>Nowdoc</title>
<para>
Nowdoc est aux chaînes guillemets simples ce qu'Heredoc est aux chaînes
guillemets doubles. Un Nowdoc est spécifié de manière similaire à un Heredoc,
mais <emphasis>aucune analyse n'est effectuée</emphasis> à l'intérieur d'une
Nowdoc. Cette syntaxe est idéale pour embarquer du code PHP ou d'autres
larges blocs de texte, sans avoir besoin d'échapper quoi que ce soit.
Elle partage quelques fonctionnalités avec la syntaxe SGML
<literal>&lt;![CDATA[ ]]&gt;</literal>, en ce qu'elle déclare un bloc
de texte qui ne doit pas être analysé.
</para>
<para>
Nowdoc est identifié avec la même séquence
<literal>&lt;&lt;&lt;</literal>
utilisée par Heredoc, mais l'identifiant qui suit est entouré de guillemets
simples, comme <literal>&lt;&lt;&lt;'EOT'</literal>. Toutes les règles concernant
les identifiants Heredoc s'appliquent également aux identifiants Nowdoc,
et, tout particulièrement, celles concernant la forme de l'identifiant de fin.
</para>
<example>
<title>Exemple de chaîne Nowdoc</title>
<programlisting role="php">
<![CDATA[
<?php
echo <<<'EOD'
Exemple de chaîne sur plusieurs lignes en utilisant la syntaxe Nowdoc.
Les barre oblique inversée sont toujours traité de façon littérale,
par exemple \\ and \'.
EOD;
]]>
</programlisting>
&example.outputs;
<screen>
<![CDATA[
Exemple de chaîne sur plusieurs lignes en utilisant la syntaxe Nowdoc.
Les barre oblique inversée sont toujours traité de façon littérale,
par exemple \\ and \'.
]]>
</screen>
</example>
<example>
<title>Exemple de chaîne Nowdoc avec des variables</title>
<programlisting role="php">
<![CDATA[
<?php
class foo
{
public $foo;
public $bar;
function __construct()
{
$this->foo = 'Foo';
$this->bar = array('Bar1', 'Bar2', 'Bar3');
}
}
$foo = new foo();
$name = 'MyName';
echo <<<'EOT'
Mom nom est "$name". J'affiche quelques $foo->foo.
Maintenant, j'affiche quelques {$foo->bar[1]}.
Ceci ne devrait pas afficher un 'A' : \x41
EOT;
?>
]]>
</programlisting>
&example.outputs;
<screen>
<![CDATA[
Mom nom est "$name". J'affiche quelques $foo->foo.
Maintenant, j'affiche quelques {$foo->bar[1]}.
Ceci ne devrait pas afficher un 'A' : \x41]]>
</screen>
</example>
<example>
<title>Exemple avec des données statiques</title>
<programlisting role="php">
<![CDATA[
<?php
class foo {
public $bar = <<<'EOT'
bar
EOT;
}
?>
]]>
</programlisting>
</example>
</sect3>
<sect3 xml:id="language.types.string.parsing">
<title>Analyse des variables</title>
<simpara>
Lorsqu'une &string; est spécifiée entre guillemets doubles ou en Heredoc,
les <link linkend="language.variables">variables</link> qu'elle contient sont interprétées.
</simpara>
<simpara>
Il existe 2 types de syntaxes : une
<link linkend="language.types.string.parsing.simple">simple</link>
et une
<link linkend="language.types.string.parsing.complex">complexe</link>.
La syntaxe simple est la plus commune et la plus pratique. Elle fournit
une façon d'embarquer une variable, une valeur de &array;, ou une
propriété d'&object; dans une &string; avec un minimum d'effort.
</simpara>
<simpara>
La syntaxe complexe se reconnaît à l'utilisation d'accolades autour de
l'expression.
</simpara>
<sect4 xml:id="language.types.string.parsing.simple">
<title>Syntaxe simple</title>
<simpara>
Si un signe dollar (<literal>$</literal>) est rencontré, l'analyseur prendra
autant de caractères que possible pour former un nom de variable valide.
Entourer le nom de la variable avec des accolades, pour spécifier
explicitement la fin de celui-ci.
</simpara>
<informalexample>
<programlisting role="php">
<![CDATA[
<?php
$juice = "pomme";
echo "Il a bu du jus de $juice.".PHP_EOL;
// Invalide. "s" est un caractère valide dans un nom de variable, mais la variable est $juice.
echo "Il a bu du jus constitué de $juices.";
// Valide. Il est explicitement spécifié la fin du nom de la variable en l'encadrant par des accolades
echo "Il a bu du jus constitué de ${juice}s.";
?>
]]>
</programlisting>
&example.outputs;
<screen>
<![CDATA[
Il a bu du jus de pomme.
Il a bu du jus constitué de .
Il a bu du jus constitué de pommes.
]]>
</screen>
</informalexample>
<simpara>
De la même façon, un index d'un &array; ou une propriété d'un &object;
peut être analysé. Avec les indices de tableaux, le crochet fermant
(<literal>]</literal>) marque la fin de l'index. Les mêmes règles sont
appliquées aux propriétés d'objets que pour les simples variables.
</simpara>
<example>
<title>Exemple de la syntaxe simple</title>
<programlisting role="php">
<![CDATA[
<?php
$juices = array("pomme", "poire", "koolaid1" => "raisin");
echo "Il a bu du jus de $juices[0].".PHP_EOL;
echo "Il a bu du jus de $juices[1].".PHP_EOL;
echo "Il a bu du jus de $juices[koolaid1].".PHP_EOL;
class people {
public $john = "John Smith";
public $jane = "Jane Smith";
public $robert = "Robert Paulsen";
public $smith = "Smith";
}
$people = new people();
echo "$people->john a bu du jus de $juices[0].".PHP_EOL;
echo "$people->john a dit bonjour à $people->jane.".PHP_EOL;
echo "$people->john's wife greeted $people->robert.".PHP_EOL;
echo "$people->robert a dit bonjour aux $people->smiths."; // Ne fonctionne pas
?>
]]>
</programlisting>
&example.outputs;
<screen>
<![CDATA[
Il a bu du jus de pomme.
Il a bu du jus de poire.
Il a bu du jus de raisin.
John Smith a bu du jus de pomme.
John Smith a dit bonjour à Jane Smith.
John Smith's wife greeted Robert Paulsen.
Robert Paulsen a dit bonjour aux .
]]>
</screen>
</example>
<simpara>
À partir de PHP 7.1.0 les indices numériques
<emphasis>négatifs</emphasis>
sont aussi supportés.
</simpara>
<example>
<title>Indices numériques négatifs</title>
<programlisting role="php">
<![CDATA[
<?php
$string = 'string';
echo "Le personnage à l'index -2 est $string[-2].", PHP_EOL;
$string[-3] = 'o';
echo "Change le caractère à l'index -3 par o donne $string.", PHP_EOL;
?>
]]>
</programlisting>
&example.outputs;
<screen>
<![CDATA[
Le personnage à l'index -2 est n.
Change le caractère à l'index -3 par o donne strong.
]]>
</screen>
</example>
<simpara>
Pour tout ce qui est plus complexe, vous devriez utiliser la
syntaxe complexe.
</simpara>
</sect4>
<sect4 xml:id="language.types.string.parsing.complex">
<title>Syntaxe complexe</title>
<simpara>
Cette syntaxe est appelée complexe, non pas parce qu'elle est complexe,
mais parce qu'elle permet l'utilisation d'expressions complexes.
</simpara>
<simpara>
Toute variable scalaire, élément de tableau ou attribut d'objet représentable
en tant que &string; peut être utilisé avec cette syntaxe.
L'expression est écrite de la même façon qu'elle apparaitrait à l'extérieur
de la &string; et est entouré des caractères
<literal>{</literal>
et <literal>}</literal>. Sachant que <literal>{</literal> ne peut pas être
échappé, cette syntaxe ne sera reconnue que lorsque le
<literal>$</literal>
suit immédiatement <literal>{</literal>. Utiliser
<literal>{\$</literal>
pour afficher littéralement <literal>{$</literal>.
Voici quelques exemples pour éclaircir ceci :
</simpara>
<informalexample>
<programlisting role="php">
<![CDATA[
<?php
// Montre toutes les erreurs
error_reporting(E_ALL);
$great = 'fantastic';
// Ne fonctionne pas, affiche : This is { fantastic}
echo "This is { $great}";
// Fonctionne, affiche : This is fantastic
echo "This is {$great}";
// Fonctionne
echo "This square is {$square->width}00 centimeters broad.";
// Fonctionne, les clés entourées de guillemets simples ne fonctionnent qu'avec la syntaxe à accolades
echo "This works: {$arr['key']}";
// Fonctionne
echo "This works: {$arr[4][3]}";
// Ceci est faux pour la même raison pour laquelle $foo[bar] est faux à l'extérieur d'une chaîne.
// En d'autres termes, ceci fonctionnera, mais uniquement parce que PHP cherchera d'abord
// une constante nommée foo ; une erreur de niveau E_NOTICE (constante indéfinie) sera émise.
echo "This is wrong: {$arr[foo][3]}";
// Fonctionne. Lors de l'utilisation de tableaux multidimensionnels, utilisez toujours
// les accolades autour du tableau lorsqu'il se trouve dans la chaîne
echo "This works: {$arr['foo'][3]}";
// Fonctionne.
echo "This works: " . $arr['foo'][3];
echo "This works too: {$obj->values[3]->name}";
echo "This is the value of the var named $name: {${$name}}";
echo "This is the value of the var named by the return value of getName(): {${getName()}}";
echo "This is the value of the var named by the return value of \$object->getName(): {${$object->getName()}}";
// Ne fonctionne pas, affiche : This is the return value of getName(): {getName()}
echo "This is the return value of getName(): {getName()}";
// Ne fonctionne pas, affiche : C:\folder\{fantastic}.txt
echo "C:\folder\{$great}.txt"
// fonctionne, affiche : C:\folder\fantastic.txt
echo "C:\\folder\\{$great}.txt"
?>
]]>
</programlisting>
</informalexample>
<para>
Il est également possible d'accéder aux propriétés de classes en utilisant
des variables contenues dans des chaînes, en utilisant cette syntaxe.
</para>
<informalexample>
<programlisting role="php">
<![CDATA[
<?php
class foo {
var $bar = 'I am bar.';
}
$foo = new foo();
$bar = 'bar';
$baz = array('foo', 'bar', 'baz', 'quux');
echo "{$foo->$bar}\n";
echo "{$foo->{$baz[1]}}\n";
?>
]]>
</programlisting>
&example.outputs;
<screen>
<![CDATA[
I am bar.
I am bar.
]]>
</screen>
</informalexample>
<note>
<para>
Les valeurs accédé via les fonctions, méthodes, variables statiques de classes,
ainsi que les constantes de classes à l'intérieur de
<literal>{$}</literal>
sont interprétée
comme le nom d'une variable dans le contexte où la chaîne est définie.
L'utilisation de simples accolades (<literal>{}</literal>) ne fonctionnera
pas pour accéder à la valeur retournée par des fonctions, méthodes, ou
les valeurs de constantes et de variables statiques de classes.
</para>
</note>
<informalexample>
<programlisting role="php">
<![CDATA[
<?php
// Affichage de toutes les erreurs.
error_reporting(E_ALL);
class beers {
const softdrink = 'rootbeer';
public static $ale = 'ipa';
}
$rootbeer = 'A & W';
$ipa = 'Alexander Keith\'s';
// Ceci fonctionne ; Affiche : I'd like an A & W
echo "I'd like an {${beers::softdrink}}\n";
// Ceci fonctionne également ; Affiche : I'd like an Alexander Keith's
echo "I'd like an {${beers::$ale}}\n";
?>
]]>
</programlisting>
</informalexample>
</sect4>
</sect3>
<sect3 xml:id="language.types.string.substr">
<title>Accès et modification d'une chaîne, par caractère</title>
<para>
On peut accéder à, et modifier un, caractère d'une &string; en spécifiant
sa position (à partir de 0) après la &string; en utilisant les crochets de
&array;, tel que <varname>$str[42]</varname>.
Il convient dans ce cas de voir une &string; comme un &array; de caractères.
Les fonctions <function>substr</function> et
<function>substr_replace</function>
peuvent être utilisées lorsque vous voulez extraire ou remplacer plus d'un caractère.
</para>
<note>
<simpara>
À partir de PHP 7.1.0, les positions négatives dans les chaînes de
caractères sont aussi supportées. Cela spécifie la position en partant
de la fin de la chaîne de caractères.
Auparavant, les index négatif émettait <constant>E_NOTICE</constant> pour
la lecture (donnant une chaîne vide) et <constant>E_WARNING</constant> pour
l'écriture (laissant la chaîne inchangée).
</simpara>
</note>
<note>
<simpara>
Antérieur à PHP 8.0.0, les <type>string</type>s pouvait aussi être accédé
en utilisant les accolades, comme ceci <varname>$str{42}</varname>.
La syntaxe avec les accolades a été rendu obsolète en PHP 7.4.0 et n'est
plus supportée à partir de PHP 8.0.0.
</simpara>
</note>
<warning>
<simpara>
Écrire à une position hors de l'intervalle existant fait que la chaîne est
complétée par des espaces jusqu'à cette position.
Les positions sont toujours converties en valeur entière.
Les types de positions invalides émettent une <constant>E_WARNING</constant>.
Seul le premier caractère d'une chaîne assignée est utilisé.
À partir de PHP 7.1.0, assigner une chaîne vide lève une erreur fatale.
Auparavant, cela affectait un octet NULL.
</simpara>
</warning>
<warning>
<simpara>
En interne, les chaînes PHP sont des tableaux d'octets. Ainsi, l'accès ou la
modification d'une chaîne en utilisant les crochets d'un tableau n'est pas
multioctets, et ne doit être utilisé qu'avec les chaînes dont l'encodage
est sur un seul octet, comme ISO-8859-1.
</simpara>
</warning>
<note>
<simpara>
À partir de PHP 7.1.0, appliquer un index vide sur une chaîne vide lève
une erreur fatale.
Auparavant, la chaîne était silencieusement convertie en un tableau.
</simpara>
</note>
<example>
<title>Quelques exemples de chaînes</title>
<programlisting role="php">
<![CDATA[
<?php
// Récupération du premier caractère d'une chaîne
$str = 'This is a test.';
$first = $str[0];
// Récupération du troisième caractère d'une chaîne
$third = $str[2];
// Récupération du dernier caractère d'une chaîne
$str = 'This is still a test.';
$last = $str[strlen($str)-1];
// Modification du dernier caractère d'une chaîne
$str = 'Look at the sea';
$str[strlen($str)-1] = 'e';
?>
]]>
</programlisting>
</example>
<para>
Les positions d'une chaîne doivent être un entier,
ou des chaînes pouvant être converties en entier, sinon, une alerte
sera émise.
</para>
<example>
<title>Exemple de Positions de Chaîne Invalide</title>
<programlisting role="php">
<![CDATA[
<?php
$str = 'abc';
var_dump($str['1']);
var_dump(isset($str['1']));
var_dump($str['1.0']);
var_dump(isset($str['1.0']));
var_dump($str['x']);
var_dump(isset($str['x']));
var_dump($str['1x']);
var_dump(isset($str['1x']));
?>
]]>
</programlisting>
&example.outputs;
<screen>
<![CDATA[
string(1) "b"
bool(true)
Warning: Illegal string offset '1.0' in /tmp/t.php on line 7
string(1) "b"
bool(false)
Warning: Illegal string offset 'x' in /tmp/t.php on line 9
string(1) "a"
bool(false)
string(1) "b"
bool(false)
]]>
</screen>
</example>
<note>
<para>
Accéder à des variables d'autres types (pas des tableaux
ni des objets implémentant les interfaces appropriées) en utilisant
<literal>[]</literal>
ou <literal>{}</literal> retournera
silencieusement &null;.
</para>
</note>
<note>
<para>
Les caractères dans une chaîne de caractères littérales peuvent être
accédé en utilisant la syntaxe
<literal>[]</literal>
ou <literal>{}</literal>.
</para>
</note>
<note>
<para>
Accéder aux caractères dans une chaîne de caractères littérales en
utilisant la syntaxe <literal>{}</literal> a été rendu obsolète en PHP 7.4.
Ceci a été supprimée en PHP 8.0.
</para>
</note>
</sect3>
</sect2><!-- end syntax -->
<sect2 xml:id="language.types.string.useful-funcs">
<title>Fonctions et opérateurs utiles</title>
<para>
Les &string; peuvent être concaténées en utilisant l'opérateur '.' (point).
Il est à noter que l'opérateur '+' (addition) ne fonctionnera
<emphasis>pas</emphasis>. Voir
<link linkend="language.operators.string">opérateurs de chaînes</link>
pour plus d'informations.
</para>
<para>
Il existe de nombreuses fonctions utiles pour la manipulation de &string;.
</para>
<simpara>
Voir la section sur les <link linkend="ref.strings">fonctions de chaînes de
caractères
</link> pour des fonctions génériques, et à la section sur les
<link linkend="ref.pcre">expressions rationnelles compatibles Perl</link>
pour des fonctionnalités de recherches et remplacements avancés.
</simpara>
<simpara>
Il existe également des <link linkend="ref.url">fonctions pour les URL</link>,
et des fonctions pour chiffrer/déchiffrer des chaînes de caractères
(<link linkend="ref.sodium">Sodium</link> et
<link linkend="ref.hash">Hash</link>).
</simpara>
<simpara>
Finalement, voir aussi les <link linkend="ref.ctype">fonctions "type de
caractères"</link>.
</simpara>
</sect2>
<sect2 xml:id="language.types.string.casting">
<title>Conversion en &string;</title>
<para>
Une valeur peut être convertie en une &string; en utilisant le mot-clé
<literal>(string)</literal>
ou la fonction <function>strval</function>.
La conversion en &string; est automatiquement effectuée dans le contexte
d'une expression où une &string; est nécessaire. Ceci survient notamment
lors de l'utilisation des fonctions <function>echo</function> ou
<function>print</function>, ou lorsqu'une variable est comparée à une &string;.
Les sections sur les <link linkend="language.types">types</link> et sur le
<link linkend="language.types.type-juggling">transtypage</link>
expliquent
ce qui suit de manière plus détaillée. Voir aussi la fonction
<function>settype</function>.
</para>
<para>
Une valeur &boolean; &true; est convertie en la &string;
<literal>"1"</literal>. Une valeur &boolean; &false; est convertie en
<literal>""</literal>
(une chaîne vide). Ceci permet les conversions vers
et depuis les valeurs &boolean; et &string;.
</para>
<para>
Un &integer; ou un &float; est converti en une &string; représentant
le nombre de façon textuelle (y compris l'exposant pour les &float;).
Les nombres à virgule flottante peuvent être convertis en utilisant
la notation exponentielle (<literal>4.1E+6</literal>).
</para>
<note>
<para>
À partir de PHP 8.0.0, le point décimal est toujours
<literal>.</literal>. Antérieur à PHP 8.0.0, le point décimal est défini
dans la locale du script (catégorie LC_NUMERIC).
Voir la fonction <function>setlocale</function>.
</para>
</note>
<para>
Les &array; sont toujours convertis en la &string;
<literal>"Array"</literal>
; à cause de cela,
<function>echo</function>
et
<function>print</function>
ne peuvent pas afficher par eux-même le contenu d'un &array;.
Pour afficher un seul élément, il faut utiliser une syntaxe tel que
<literal>echo $arr['foo']</literal>. Voir ci-dessous pour des astuces
permettant d'afficher le contenu complet.
</para>
<para>
Pour pouvoir convertir un &object; en &string; la méthode magique
<link linkend="language.oop5.magic">__toString</link>
doit être utilisée.
</para>
<para>
Les &resource;s sont toujours converties en &string; sous la forme
<literal>"Resource id #1"</literal>, où <literal>1</literal> est l'identifiant
assigné à la &resource; par PHP lors de l'exécution. Alors qu'il ne faut pas se fier
à cette structure, car susceptible d'évoluer, elle sera néanmoins unique pour une
ressource donnée durant toute la durée d'exécution du script courant (ie une
requête web ou un processus CLI). Pour récupérer le type d'une
&resource;, utilisez la fonction <function>get_resource_type</function>.
</para>
<para>
&null; est toujours converti en une chaîne vide.
</para>
<para>
Au vu de tout cela, la conversion d'un &array;, d'un &object;, ou d'une
&resource;, en une &string; ne fournit aucune information utile sur sa
valeur, mis à part son type. Voir les fonctions
<function>print_r</function>
et <function>var_dump</function> pour inspecter
plus efficacement les contenus de ces types.
</para>
<para>
La plupart des valeurs en PHP peuvent également être converties en &string;
afin de les stocker. Cette méthode est appelée "linéarisation", et
est effectuée par <function>serialize</function>.
</para>
</sect2>
<sect2 xml:id="language.types.string.details">
<title>Détails sur le type "chaîne de caractères"</title>
<para>
Le type &string; en PHP est implémenté sous la forme d'un tableau d'octets
accompagné d'un entier indiquant la longueur de la mémoire tampon. Il n'a aucune
information sur la traduction octet/caractère, laissant cette tâche au programmeur.
Il n'y a aucune limitation sur les valeurs pouvant être présentes dans une chaîne ;
en particulier, les octets dont la valeur est <literal>0</literal> (“octets NUL”)
sont autorisés à n'importe quel endroit de la chaîne (cependant, quelques fonctions,
indiquées dans ce manuel comme n'étant pas “sécurisées au niveau binaire”, peuvent
ignorer tous les octets après un octet nul.)
</para>
<para>
La nature même du type "chaîne de caractères" explique
qu'il n'existe pas de type “byte” en PHP - les chaînes de caractères jouent ce rôle.
Les fonctions qui ne retournent pas de données textuelles - par exemple, des données
arbitraires lues depuis un socket réseau - continueront de retourner des chaînes
de caractères.
</para>
<para>
PHP ne dictant aucun encodage spécifique pour les chaînes
de caractères, on pourrait se demander comment les chaînes littérales
sont codés. Par exemple, est-ce que la chaîne
<literal>"á"</literal>
équivaut à la chaîne <literal>"\xE1"</literal> (ISO-8859-1),
<literal>"\xC3\xA1"</literal>
(UTF-8, C form),
<literal>"\x61\xCC\x81"</literal>
(UTF-8, D form) ou à une autre des représentations possibles ?
La réponse est que la chaîne sera encodée suivant l'encodage courant du script.
Aussi, si le script est écrit en ISO-8859-1, alors, la chaîne sera encodée en
ISO-8859-1 ; et ainsi de suite. Toutefois, ceci n'est pas vrai si Zend Multibyte est
activé ; dans ce cas, le script peut être écrit dans n'importe quel encodage (qui sera explicitement
déclaré, ou bien détecté), puis sera converti en un encodage interne, qui sera
utilisé pour les chaînes littérales. Notez qu'il existe des contraintes sur
l'encodage du script (ou sur l'encodage interne, si Zend Multibyte est activé) -
cela signifie quasiment toujours que l'encodage utilisé doit être un sur-ensemble compatible
d'ASCII, comme UTF-8 ou ISO-8859-1. Notez cependant que les encodages dépendant
de l'état, où les mêmes valeurs de l'octet peuvent être utilisées dans des
états de décalage initial et non-initial, peuvent être problématiques.
</para>
<para>
Bien évidemment, pour être utiles, les fonctions qui opèrent sur du texte peuvent devoir
faire des hypothèses sur la façon dont est encodé la chaîne de caractères.
Malheureusement, ces hypothèses ne sont pas les mêmes suivant les fonctions de
PHP :
</para>
<itemizedlist>
<listitem>
<simpara>
Certaines fonctions supposent que la chaîne est encodée en utilisant un (quelconque) encodage
à un seul octet, mais n'ont pas besoin d'interpréter ces octets sous la forme
de caractères. C'est actuellement le cas, par exemple, pour les fonctions
<function>substr</function>, <function>strpos</function>,
<function>strlen</function>
et <function>strcmp</function>.
Une autre façon de voir ces fonctions est qu'elles opèrent sur les mémoires
tampons ; autrement dit, qu'elles fonctionnent avec les octets et leurs positions.
</simpara>
</listitem>
<listitem>
<simpara>
D'autres fonctions reçoivent l'encodage de la chaîne en paramètre, éventuellement en
assumant un encodage par défaut si ce n'est pas le cas. C'est le cas de la fonction
<function>htmlentities</function>
ainsi que de la majorité des fonctions de l'extension
<link linkend="book.mbstring">mbstring</link>.
</simpara>
</listitem>
<listitem>
<simpara>
D'autres utilisent la locale courante (voir <function>setlocale</function>),
mais opèrent octet par octet. C'est le cas de <function>strcasecmp</function>,
<function>strtoupper</function>, et <function>ucfirst</function>.
Cela signifie qu'elles ne peuvent être utilisées qu'avec les encodages sur
un seul octet, et si l'encodage correspond à la locale.
Par exemple, <literal>strtoupper("á")</literal> peut retourner
<literal>"Á"</literal>
si la locale est correctement positionnée et si
<literal>á</literal>
est encodé sur un seul octet. Si la chaîne est encodée
en UTF-8, le résultat correct ne sera pas retourné, et la chaîne résultante pourra
être (ou non) corrompue, suivant la locale courante.
</simpara>
</listitem>
<listitem>
<simpara>
Enfin, elles peuvent juste supposer que la chaîne utilise un encodage
spécifique, généralement UTF-8. C'est le cas de la plupart des fonctions
de l'extension <link linkend="book.intl">intl</link> ainsi que de celles
de l'extension <link linkend="book.pcre">PCRE</link> (dans ce dernier cas,
uniquement lorsque le modificateur <literal>u</literal> est utilisé).
Bien que ce soit en raison de leur buts spécifiques, la fonction
<function>utf8_decode</function>
assume un encodage UTF-8 et la fonction
<function>utf8_encode</function>
pré-suppose un encodage ISO-8859-1.
</simpara>
</listitem>
</itemizedlist>
<para>
Pour conclure, le fait d'écrire un programme correct en utilisant Unicode
dépend de l'utilisation ou non de fonctions qui ne fonctionnent pas en Unicode,
et qui corrompront très certainement les données ; il conviendra donc d'utiliser des fonctions
qui fonctionnent correctement, générallement depuis les extensions
<link linkend="book.intl">intl</link>
et <link linkend="book.mbstring">mbstring</link>.
Cependant, l'utilisation de fonctions qui peuvent gérer des encodages Unicode
n'est que le commencement. Quelques soient les fonctions fournies par le langage,
il est essentiel de connaître les spécifications de l'Unicode. Par exemple, un
programme qui assume qu'il n'y a que des caractères en majuscule et en minuscule
fait une mauvaise hypothèse.
</para>
</sect2>
</sect1><!-- end string -->
<!-- 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
-->