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";
?>