Reference

Školení, která pořádám

V PHP je možné na jedna data odkazovat více proměnnými, používají se k tomu reference. Osobně reference používám např. tehdy, když chci k datům zanořeným hluboko v poli přistupovat přes jednoduchou proměnnou:

<?php
$column = &$table['columns'][$column_name];
?>

Pak stačí pracovat s proměnnou $column a všechny změny se projeví v původním poli. Pokud tuto proměnnou následně chci použít k jinému účelu (byť třeba ve foreach cyklu), je nutné referenci zrušit, nejsnáze pomocí unset($column).

Reference se dají používat i při předávání parametrů funkcím:

<?php
function reference(&$ar) {
    $ar[0]++;
}
?>

V tom případě se všechny změny v proměnné uvnitř funkce projeví i navenek a jako parametr je nutné předat proměnnou. Za normálních okolností se pracuje s kopií dat a předat lze jakýkoliv výraz. Předávání parametrů referencí se dá využít k jejich jednoduché změně. Podle mě to není úplně čistý způsob – funkce by měla mít jasně definovaný vstup a výstup a jakákoliv modifikace vstupních parametrů musí být přinejmenším důkladně popsána. Předávání parametrů referencí se dá použít pro vracení doplňkových informací – např. funkce fsockopen vrací v případě chyby jednoduše false a chybovou hlášku vrací v parametru předaném referencí.

U velkých dat ale může předávání parametrů referencí znamenat značné zrychlení:

<?php
// pomalé
function setridit($velke_pole) {
    // setřídění
    return $velke_pole;
}

// podstatně rychlejší
function setridit_ref(&$velke_pole) {
    // setřídění
}
?>

Dlužno podotknout, že pokud ke změně parametru uvnitř funkce nedochází, nepřinese předávání referencí žádné zrychlení. PHP totiž data fyzicky kopíruje až když to je potřeba.

V PHP 4 se stejným způsobem pracovalo i s objekty, kdy je vytváření kopií potřeba pouze zřídka. Úskalí, na která při tom můžete narazit, pěkně popisuje autor knihovny JpGraph. V PHP 5 došlo k celkem odvážné zpětně nekompatibilní změně a objekty se v něm předávají referencí.

Ve starších verzích PHP bylo možné předání parametru referencí vynutit až v okamžiku volání funkce. Kvůli možným nežádoucím vedlejším efektům byla tato vlastnost naštěstí odstraněna. Pro staré projekty, které jsou na této vlastnosti závislé, to lze povolit direktivou allow_call_time_pass_reference.

Jakub Vrána, Výuka, 24.8.2005, diskuse: 7 (nové: 0)

Diskuse

ikona dgx:

Pokud bychom měli být zcela přesní, tak se nedá říct, že v PHP5 se objekty předávají referencí, protože reference mají stále svou specifickou funkci, viz http://www.php.net/manual/en/language.oop5.basic.php#AEN5691

<?php
$assigned 
=  $instance;
$reference  =& $instance;

$instance->var = 'assigned will have this value';

$instance = null; // $instance and $reference become null

var_dump($instance);
var_dump($reference);
var_dump($assigned);
?>

dává výsledek

NULL
NULL
object(SimpleClass)#1 (1) {
   ["var"]=>
     string(30) "assigned will have this value"
}

martinpav:

$assigned  =  $instance;
priradi referenciu na objekt do premennej
$reference  =& $instance;
vytvori referenciu na referenciu ???

Akosi nedokazem prist na dovod preco sa autori PHP rozhodli pre taketo chovanie. Pokial by niekto mal priklad rozumneho vyuzitia, rad sa poucim.

johno:

Nie. Rozdiel je v tom, že v PHP5 sa objekty (IMHO úplne logicky) pri priraďovaní nekopírujú (nedochádza k implicitnému klonovaniu).

Čiže
<?php
$article
= new Article();
$theSameArticle = $article;
?>

je v PHP5 to isté ako

<?php
$article
= new Article();
$theSameArticle = &$article;
?>

v PHP4 to tak nie je.

ikona dgx:

Právě že to není to stejné. Pokud v PHP5 zavoláš $article = null, tak v první případě bude $theSameArticle obsahovat objekt Article a ve druhém případě bude rovno null.

Jakub Podhorský:

tohle jsem vůbec netušil...to je docela dost podivný chování...každopádně děkuju za upozornění

martinpav:

Prave priklad od DGX to to porusuje

<?php
$instance
= new SimpleClass() //nova instancia, v premennej ja referencia na objekt
$assigned  =  $instance; // priradenie REFERENCIE do druhej premennej, stale ukazuje na tu istu instanciu
$reference  =& $instance; // priradenie referencie na premennu $instance

$instance->var = '$assigned will have this value'; 

print '<hr>';
var_dump($instance);
var_dump($reference);
var_dump($assigned);
print
'<hr>';

$instance = null; // $instance aj $reference maju priradene NULL, cize $reference obsahuje len referenciu na premennu instance, nie na instanciu objektu. Toto mi pride ako chore. Logicky by sa mala priradit do $reference referencia na instanciu objektu.

var_dump($instance);
var_dump($reference);
var_dump($assigned);
?>

KKING:

Uz vim proc to tak implementovali a je to uplne uzasne..
uplne nadherne se s tim daji udelat vazby mezi objekdy bez pouziti jedineho &.

Diskuse je zrušena z důvodu spamu.

avatar © 2005-2024 Jakub Vrána. Publikované texty můžete přetiskovat pouze se svolením autora. Ukázky kódu smíte používat s uvedením autora a URL tohoto webu bez dalších omezení Creative Commons. Můžeme si tykat. Skripty předpokládají nastavení: magic_quotes_gpc=Off, magic_quotes_runtime=Off, error_reporting=E_ALL & ~E_NOTICE a očekávají předchozí zavolání mysql_set_charset. Skripty by měly být funkční v PHP >= 4.3 a PHP >= 5.0.