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.

Používejte diakritiku. Vstup se chápe jako čistý text, ale URL budou převedeny na odkazy a PHP kód uzavřený do <?php ?> bude zvýrazněn. Pokud máte dotaz, který nesouvisí s článkem, zkuste raději diskusi o PHP, zde se odpovědi pravděpodobně nedočkáte.

Jméno: URL: Reakce na: martinpav

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 &.

avatar © 2005-2022 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.