Desde el punto de vista del lector de scripts PHP, el cambio que más impacto tendrá a la hora de mantener el código compatible, es la forma en que se manejan las referencias en las versiones de PHP posteriores a 4.4.0.
Hasta PHP 4.3, incluida ésta, era posible enviar, asignar o devolver variables por referencia que realmente tenían que devolver un valor, como una constante, un valor temporal (p.ej. el resultado de una expresión), o el resultado de una función que ha devuelto sí misma como valor, como aquí:
<?php
$foo = "123";
function return_value() {
global $foo;
return $foo;
}
$bar = &return_value();
?>
Aunque este código normalmente funcionará en PHP 4.3 como cabe esperar, en general el resultado es indefinido. El Zend Engin podría no actuar correctamente con estos valores como referencia. Este error podría llevar a problemas de memorias corruptas difíciles de reproducir, en especial cuando el código base es muy largo.
En PHP 4.4.0, PHP 5.0.4, y posterior, el motor Zend se ha corregido para que
'sepa' cuándo una operación por referencia se usa en un valor que no
debería referenciarse. En estos casos se utiliza el valor real,
y se emite una alerta. Esta alerta es en forma de
E_NOTICE
en PHP 4.4.0 y superior, y de
E_STRICT
en PHP 5.0.4 y superior.
Los códigos que podrían producir corrupciones en memoria ya no podrán hacerlo. Sin embargo, hay códigos fuente que podrían funcionar de forma distinta a la esperada.
<?php
function func(&$arraykey) {
return $arraykey; // ¡la función devuelve un valor!
}
$array = array('a', 'b', 'c');
foreach (array_keys($array) as $key) {
$y = &func($array[$key]);
$z[] =& $y;
}
var_dump($z);
?>
<
Al ejecutar el script superior en alguna versión de PHP anterior a la corrección del error, producirá la siguiente salida:
array(3) { [0]=> &string(1) "a" [1]=> &string(1) "b" [2]=> &string(1) "c" }
Y tras corregir el error de referencias, el mismo código resultará en:
array(3) { [0]=> &string(1) "c" [1]=> &string(1) "c" [2]=> &string(1) "c" }
Esto es porque, de acuerdo a los cambios, la asignación en func() se hace por valor. El valor de $y se reasigna, y se impide enlazar por referencia a $z. Antes de la corrección, se asignaba el valor por referencia, dando lugar a que $y se revinculara en cada asignación. El intento de enlazar a un valor temporal por referencia era la causa de la memoria corrupta.
Dicho código se puede rescribir para funcionar de forma idéntica en ambas versiones. La definición de func() se puede modificar para devolver valores por referencia, o se podría eliminar la asignación por referencia del resultado de func().
<?php
function func() {
return 'devolución de la function';
}
$x = 'valor original';
$y =& $x;
$y = &func();
echo $x;
?>
En PHP 4.3 $x será 'valor original', mientras que tras los cambios será 'devolución de la función' - recuerde que como la función no devuelve el valor por referencia, la asignación por referencia se convierte a una asignación convencional. De nuevo, esto puede se llevar a un comportamiento común, o bien forzando a que func() devuelva el valor por referencia o eliminando la asignación por referencia.
<?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 se evaluaba a NULL
en lugar de devolver un objeto. Esto sucedía porque
getThis() devuelve por valor, pero el valor aquí se
asigna por referencia. A pesar de que funciona de la forma esperada, esto es en realidad
un código inválido que lanzará un E_NOTICE
en PHP 4.4 o un E_STRICT
en PHP 5.0.4 y superior.
<?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 la tercera llamada a var_dump() produce
NULL
, debido a la memoria corrupta provocada tras
devolver por referencia un valor no inicializado. Este código es valido
en PHP 5.0.4 y superior, pero lanza errores en versiones de PHP anteriores.
<?php
$arr = array('a1' => array('alfa' => 'ok'));
$arr =& $arr['a1'];
echo '-'.$arr['alfa']."-\n";
?>
Hasta PHP 5.0.5, no era posible asignar un array por referencia de esta forma. Ahora sí.
Hay un par de de errores en PHP 5.0, anteriores a que se
corrigiera el problema de referencias, que ahora 'funcionan'. Sin embargo, en ambos
casos los errores se emiten en PHP 5.1.x, porque en primer lugar, el código era
inválido. Devolver un valor por referencia usando self:: ahora,
en términos generales, funciona pero emite una alerta E_STRICT
,
y se emitirá un E_ERROR
cuando se asigne por referencia
un objeto sobrecargado, incluso cuando parezca que la asignación ha funcionado.
Las llamadas anidadas a funciones que devuelven por valores por referencia son válidas tanto
en PHP 4.3.x como en PHP 5.1.x, pero emiten
E_NOTICE
o E_STRICT
en las
versiones de PHP intermedias.
<?php
function & foo() {
$var = 'ok';
return $var;
}
function & bar() {
return foo();
}
$a =& bar();
echo "$a\n";
?>