Changement dans la gestion des références
Présentation
Du point de vue du programmeur, le changement qui aura le plus d'impact sur le code déjà écrit est la manière avec laquelle les références sont gérées dans les versions PHP 4.4.0 et plus récentes.
Jusqu'à la version PHP 4.3 incluse, il était possible d'envoyer, assigner ou retourner des variables par références, alors qu'elles auraient dues être retournées par valeur, comme des constantes, des valeurs temporaires (comme le résultat d'une expression), ou le résultat d'une fonction qui elle-même, retourne une valeur.
<?php
$foo = "123";
function return_value() {
global $foo;
return $foo;
}
$bar = &return_value();
?>
Même si ce code fonctionne tel qu'attendu en PHP 4.3, en général il conduit à une situation indéfinie. Le moteur Zend ne peut pas fonctionner correctement avec des valeurs passées par références. Ce bogue peut et a conduit à des corruptions de mémoire difficiles à reproduire, notamment lorsque le code de l'application est compliqué.
En PHP 4.4.0, PHP 5.0.4 et toutes les versions plus récentes, le moteur
Zend a été modifié pour reconnaître les cas où une valeur ne doit pas
être utilisée par référence. La valeur réelle est maintenant utilisée
dans ces cas, et une alerte est émise. Cette alerte prend la forme d'un
message E_NOTICE
en PHP 4.4.0 et plus récent, et
E_STRICT
en PHP 5.0.4 et plus récent.
Du code qui pouvait produire des corruptions de mémoire ne peut plus le faire. Cependant, certains codes anciens peuvent fonctionner de manière différente.
Code qui fonctionnait en 4.3.x, mais qui échoue maintenant
<?php
function func(&$arraykey) {
return $arraykey; // la fonction retourne par valeur!
}
$array = array('a', 'b', 'c');
foreach (array_keys($array) as $key) {
$y = &func($array[$key]);
$z[] =& $y;
}
var_dump($z);
?>
<
L'exécution du script ci-dessus dans une version de PHP antérieure à la correction du bogue produit ce résultat :
array(3) { [0]=> &string(1) "a" [1]=> &string(1) "b" [2]=> &string(1) "c" }
Après la correction du bogue, cela donne :
array(3) { [0]=> &string(1) "c" [1]=> &string(1) "c" [2]=> &string(1) "c" }
Ceci est dû au fait que func() effectue une assignation par valeur. La valeur de $y est réassignée, et que la liaison par référence avec $z est préservée. Avant la correction du bogue, la valeur était assignée par référence, faisant que la variable $y était réassignée à chaque assignement. La tentative de liaison avec une valeur temporaire est la cause de la corruption de la mémoire.
Ce code peut être réparé pour fonctionner à l'identique avec des versions pré et post-correction. La signature de func() peut être modifiée pour retourner les valeurs par référence, ou bien l'affectation par référence peut être supprimée du résultat de func().
<?php
function func() {
return 'function return';
}
$x = 'original value';
$y =& $x;
$y = &func();
echo $x;
?>
En PHP 4.3, $x vaudrait 'original value', alors qu'après le changement, il vaudrait 'function return' : n'oubliez pas que la fonction ne retourne plus par référence, et que la référence est convertie en affectation par valeur. Encore une fois, cela peut être corrigé en forçant func() à retourner par référence, ou bien en éliminant l'affectation par référence.
Code qui fonctionnait en PHP 4.3.x, mais qui émet maintenant une erreur
<?php
class Foo {
function getThis() {
return $this;
}
function destroyThis() {
$baz =& $this->getThis();
}
}
$bar = new Foo();
$bar->destroyThis();
var_dump($bar);
?>
En PHP 5.0.3, $bar vaut NULL
au
lieu de l'objet attendu. Cela arrive car getThis()
retourne une valeur, mais que la valeur est assignée par référence.
Même si cela fonctionne désormais comme attendu, ce code est en
fait invalide, et émettra une alerte E_NOTICE
sous
PHP 4.4 ou E_STRICT
en PHP 5.0.4 et plus récent.
Code qui échouaient en PHP 4.3.x, mais qui fonctionne maintenant
<?php
function &f() {
$x = "foo";
var_dump($x);
print "$x\n";
return($a);
}
for ($i = 0; $i < 3; $i++) {
$h = &f();
}
?>
En PHP 4.3, le troisième appel à var_dump() produit
NULL
, à cause d'une correction de la mémoire, causée
par le retour d'une valeur non initialisée par référence. C'est du code
valide en PHP 5.0.4 et plus récent, mais il produit une erreur dans les
versions plus anciennes.
<?php
$arr = array('a1' => array('alfa' => 'ok'));
$arr =& $arr['a1'];
echo '-'.$arr['alfa']."-\n";
?>
Jusqu'en PHP 5.0.5, il n'était pas possible d'assigner un élément de tableau par référence de cette manière. C'est corrigé maintenant.
Code qui aurait du fonctionner en PHP 5.0.x
Il y a quelques cas de bogues rapportés en PHP PHP 5.0 avant la correction
de ce bogue qui 'refonctionnent'. Cependant, dans tous les cas, des erreurs
sont émises en PHP 5.1.x, car le code est invalide. Retourner des références
avec self:: fonctionne maintenant, mais émet une alerte
E_STRICT
, et même si votre expérience est différente
lors de l'assignation d'un objet par référence, vous verrez toujours une
erreur E_ERROR
lorsque vous tentez cela même si
l'assignation semble fonctionner.
Alertes qui vont et viennent
Des appels imbriqués à des fonctions retournant des valeurs par référence
sont valides en PHP 4.3.x et PHP 5.1.x, mais ils émettent des erreurs
E_NOTICE
et E_STRICT
dans les
nouvelles versions de PHP.
<?php
function & foo() {
$var = 'ok';
return $var;
}
function & bar() {
return foo();
}
$a =& bar();
echo "$a\n";
?>
Version en cache
24/11/2024 18:10:48 Cette version de la page est en cache (à la date du 24/11/2024 18:10:48) afin d'accélérer le traitement. Vous pouvez activer le mode utilisateur dans le menu en haut pour afficher la dernère version de la page.Document créé le 30/01/2003, dernière modification le 26/10/2018
Source du document imprimé : https://www.gaudry.be/php-rf-migration51.references.html
L'infobrol est un site personnel dont le contenu n'engage que moi. Le texte est mis à disposition sous licence CreativeCommons(BY-NC-SA). Plus d'info sur les conditions d'utilisation et sur l'auteur.
Références
Ces références et liens indiquent des documents consultés lors de la rédaction de cette page, ou qui peuvent apporter un complément d'information, mais les auteurs de ces sources ne peuvent être tenus responsables du contenu de cette page.
L'auteur de ce site est seul responsable de la manière dont sont présentés ici les différents concepts, et des libertés qui sont prises avec les ouvrages de référence. N'oubliez pas que vous devez croiser les informations de sources multiples afin de diminuer les risques d'erreurs.