Din punctul de vedere al programatorului script-urilor PHP, schimbarea care cel mai probabil va afecta codul-sursă vechi este modul în care sunt manipulate referințele în toate versiunile PHP ce au urmat după PHP 4.4.0.
Până la, și inclusiv în PHP 4.3 era posibil de a transmite, atribui sau întoarce variabile prin referință, care ar fi trebuit în mod real să fie întoarse prin valoare, cum ar fi o constantă, o valoare temporară (de ex. rezultatul unei expresii) sau rezultatul unei funcții care însăși a fost întoarsă prin valoare, ca în acest exemplu:
<?php
$foo = "123";
function return_value() {
global $foo;
return $foo;
}
$bar = &return_value();
?>
Cu toate că acest cod-sursă de obicei lucrează conform așteptărilor în PHP 4.3, în caz general rezultatul este nedefinit. Motorul Zend nu poate funcționa corect cu aceste valori în calitate de referințe. Această eroare putea, și într-adevăr a dus la diverse probleme de alterare a conținutului memoriei dificile de reprodus, în special acolo unde baza de cod-sursă era foarte mare.
În PHP 4.4.0, PHP 5.0.4 și toate versiunile ulterioare ale PHP Motorul a
fost corectat pentru a 'ști' când operația de referință este utilizată
asupra unei valori care nu ar trebui să fie referită. Acum în aceste cazuri
este utilizată valoarea propriu-zisă și este emisă o preîntâmpinare.
Preîntâmpinarea ia forma unui E_NOTICE
în PHP 4.4.0 și
ulterior, și E_STRICT
în PHP 5.0.4 și ulterior.
Codul-sursă care potețial putea să producă alterarea memoriei acum nu mai poate face aceasta. Însă unele coduri-sursă vechi pot ca rezultat să funcționeze în mod diferit.
<?php
function func(&$arraykey) {
return $arraykey; // funcția întoarce rezultatul prin valoare!
}
$array = array('a', 'b', 'c');
foreach (array_keys($array) as $key) {
$y = &func($array[$key]);
$z[] =& $y;
}
var_dump($z);
?>
<
Lansând în execuție script-ul de mai sus în orice versiune a PHP mai înainte de corectarea referințelor va produce următoarea ieșire:
array(3) { [0]=> &string(1) "a" [1]=> &string(1) "b" [2]=> &string(1) "c" }
După corectarea referințelor același cod-sursă va produce următoarele:
array(3) { [0]=> &string(1) "c" [1]=> &string(1) "c" [2]=> &string(1) "c" }
Aceasta se întâmplă din cauza că, după corectare, func()
atribuie prin valoare. Valoarea variabilei $y este
re-atribuită și legătura prin referință este păstrată prin
$z. Înainte de corectare valoarea era atribuită prin
referință, ce ducea la faptul că $y era realipit la
fiecare atribuire. Încercarea de a alipi ceva prin referință la o valoare
temporară cauza alterarea memoriei.
Un astfel de cod-sursă poate fi făcut să funcționeze identic în ambele
versiuni PHP: înainte de corectare și după. Semnătura
func()
poate fi alterată ca să întoarcă valoarea prin
referință, sau atribuirea prin referință poate fi eliminată din rezultatul
func()
.
<?php
function func() {
return 'function return';
}
$x = 'original value';
$y =& $x;
$y = &func();
echo $x;
?>
În PHP 4.3 $x ar fi fost 'valoarea originară', în timp
ce după corectări aceasta va fi 'ceea ce întoarce funcția' - amintiți-vă că
atunci când funcția nu întoarce valoarea prin referință, atribuirea prin
referință este convertită într-o atribuire obișnuită. Iarăși, aceasta
poate fi adus la un numitor comun prin forțarea func()
să întoarcă valoarea prin referință, sau prin eliminarea atribuirii prin
referință.
<?php
class Foo {
function getThis() {
return $this;
}
function destroyThis() {
$baz =& $this->getThis();
}
}
$bar = new Foo();
$bar->destroyThis();
var_dump($bar);
?>
În PHP 5.0.3, $bar evalua în NULL
în loc să întoarcă un obiect. Aceasta s-a întâmplat din cauza că
getThis()
întoarce prin valoare, dar aici valoarea e
atribuită prin referință. Cu toate că acum script-ul funcționează conform
așteptărilor, acesta este de fapt un cod invalid, care va arunca un
E_NOTICE
sub PHP 4.4, sau un
E_STRICT
sub PHP 5.0.4 și ulterior.
<?php
function &f() {
$x = "foo";
var_dump($x);
print "$x\n";
return($a);
}
for ($i = 0; $i < 3; $i++) {
$h = &f();
}
?>
În PHP 4.3 al treilea apel la var_dump() produce
NULL
, din cauza alterării memoriei cauzate de
întoarcerea unei valori neinițializate prin referință. Acest cod-sursă
este valid în PHP 5.0.4 și ulterior, dar aruncă erori în versiunile
anterioare ale PHP.
<?php
$arr = array('a1' => array('alfa' => 'ok'));
$arr =& $arr['a1'];
echo '-'.$arr['alfa']."-\n";
?>
Până la PHP 5.0.5, nu era posibil de a atribui valoarea unui element al tabloului prin referință, în acest mod. Acum este posibil.
ar fi trebuit să lucreze
în PHP
5.0.x
Există vre-o două erori raportate în PHP 5.0 înainte de corectarea
referințelor, care acum 'lucrează'. Însă în ambele cazuri erorile sunt
aruncate de PHP 5.1.x, deoarece în primul rând codul-sursă era invalid.
Întoarcerea valorilor prin referință utilizând self::
acum lucrează la general, dar aruncă o preîntâmpinare
E_STRICT
, și cu toate că rezultatele variază de la caz
la caz la atribuirea prin referință la un obiect supraîncărcat, oricum veți
vedea un E_ERROR
atunci când încercați aceasta, chiar
și acolo unde însăși atribuirea pare să funcționeze.
Apeluri incluse unul în altul către funcții care întorc valoarea prin
referință sunt exemple de cod-sursă valid în ambele PHP 4.3.x și PHP 5.1.x,
dar aruncau erori nejustificate E_NOTICE
sau
E_STRICT
în versiunile intermediare ale PHP.
<?php
function & foo() {
$var = 'ok';
return $var;
}
function & bar() {
return foo();
}
$a =& bar();
echo "$a\n";
?>