Dlaczego referencje są rzadko używane w PHP?


26

Mam trochę znajomości języka C ++ i wiem, że wskaźniki są tam często używane, ale zacząłem patrzeć na kod open source PHP i nigdy nie widzę kodu używającego referencji w metodach.

Zamiast tego kod zawsze używa wartości zwracanej zamiast przekazywać odwołanie do zmiennej do metody, która następnie zmienia wartość tej zmiennej i po prostu ją zwraca.

Czytałem, że używanie referencji zużywa mniej pamięci, więc dlaczego nie są używane w PHP?


19
Używanie parametrów przekazywania przez referencję to „programowanie efektów ubocznych” - użycie funkcji zwracającej pojedynczą wartość jest znacznie wyraźniejsze podczas odczytu kodu. To powiedziawszy, wiele podstawowych funkcji PHP używa referencji.
halfer

3
PHP domyślnie przekazuje obiekty przez odniesienie.

2
sortowanie tablic to główny przykład podstawowych funkcji PHP przekazywanych przez referencje
Mark Baker

2
Odnośniki do PHP nie są wskaźnikami i często są uciążliwe, jeśli nie oczekujesz ich w pełni w miejscu, w którym się pojawiają.
lanzz

2
Jeśli potrzebujesz wielu zwrotów, return array($foo, $bar);ilist($A, $B) = foobar();
Izkata

Odpowiedzi:


49

Twoje twierdzenie, że referencje są rzadko używane, jest nieprawidłowe. Jak już wspomniano inni, istnieje mnóstwo natywnych funkcji, które korzystają z referencji, godnymi uwagi przykładami są funkcje sortowania tablic i preg_match()/ preg_match_all(). Jeśli używasz którejkolwiek z tych funkcji w kodzie, używasz również odwołań.

Przechodząc dalej, odniesienia w PHP nie są wskaźnikami. Ponieważ pochodzisz ze środowiska C ++, rozumiem zamieszanie, ale odniesienia do PHP są zupełnie inną bestią, są aliasami do tablicy symboli . Wszelkie przyrosty wydajności, których można się spodziewać po referencjach w C ++, po prostu nie dotyczą referencji w PHP.

W rzeczywistości w większości scenariuszy przekazywanie przez wartość jest szybsze i wymaga mniej pamięci niż przekazywanie przez odniesienie. Zend Engine, rdzeń PHP, wykorzystuje mechanizm optymalizacji kopiowania przy zapisie , który nie tworzy kopii zmiennej, dopóki nie zostanie zmodyfikowana. Przekazywanie przez odwołanie zwykle przerywa wzorzec kopiowania przy zapisie i wymaga kopii, niezależnie od tego, czy zmodyfikujesz wartość, czy nie.

Nie bój się używać referencji w PHP, kiedy jest to konieczne, ale nie rób tego tylko jako próbę mikrooptymalizacji. Pamiętajcie, przedwczesna optymalizacja jest źródłem wszelkiego zła .

Dalsza lektura:


Dzięki za korektę @NikiC. Trochę leniwa odpowiedź na to ...
yannis

Aby ukończyć odpowiedź, dobrze byłoby wskazać, że wszystkie obiekty są przekazywane przez referencje w PHP.
Florian Margaine

@FlorianMargaine To nie do końca dokładne (patrz drugi link w dalszej lektury).
yannis

2
@FlorianMargaine Nie, oba są bardzo różne i ważne jest, aby zrozumieć, dlaczego tak jest.
phant0m

3
@FlorianMargaine Nie, załóżmy, że obiekty zostały przekazane przez referencję w PHP: f($obj)biorąc pod uwagę function f($x) { $x = new X; }, $objodnosi się do innego obiektu niż przed wywołaniem f(). Ponieważ jednak obiekty nie są przekazywane przez odwołanie, $ obj nie jest modyfikowany, jeśli miałbyś to zrobić za pomocą PHP. W ten sposób PHP robi to samo co Java.
phant0m

8

PHP już wykonuje operacje kopiowania przy zapisie, w których nie tworzy nowej wartości, dopóki czegoś nie zmienisz, więc nie ma dużo pamięci zaoszczędzonej przez użycie referencji. Może to nawet zepsuć niektóre rzeczy, które PHP robi wewnętrznie, aby zmniejszyć zużycie pamięci, a nawet pogorszyć sytuację.

Dodaj do tego fakt, że referencje sprawiają, że ogólnie rzecz biorąc jest to zbyt magiczne. Domyślną wartością, a więc tym, czego oczekuje większość ludzi, jest przekazywanie wartości; kiedy przechodzę $ido funkcji, ogromnie komplikuje to, że trzeba dbać o to, czy ta funkcja w tajemniczy sposób zmienia się $ina coś zupełnie innego, a tym samym na wszelki wypadek tworzy kopie obronne. (Może już modyfikować, $ijeśli wartość jest obiektem, ale moim zdaniem nie powinna.)

Zasadniczo uważam, że przekazywanie przez odniesienie jest przydatne tylko w przypadku parametrów „wyjściowych”, czyli zmiennych, których oczekuję wrócić z funkcji niż piłkę, a la preg_match„ów &$matches. Nawet w przypadku funkcji, które wyraźnie modyfikują przekazywany obiekt, na przykład sortlub array_pop, co wydaje się nieco nieprzyjemne ... ale z tym utknęliśmy.


5

PHP jest językiem zorientowanym na sieć.
Strony internetowe są wyświetlane szybko i powinny być lekkie.
Zwykle program PHP żyje ułamek sekundy i zużywa kilkaset kilobajtów pamięci.
Nie ma sensu takie optymalizacje.


1
To. Nie potrzebuje wskaźników / referencji, ponieważ nie bałagan na tak niskim poziomie jak C ++.
Kenneth Worden

8
Dlaczego ten post dostaje 5+ ??? To a) nie odpowiada na pytanie b) jest niepoprawne

1
Czy referencje są wolne i zajmują zbyt dużo pamięci?
Rocket Hazmat

1
@RocketHazmat Tak, o dziwo, to prawda.
yannis

3

Niektóre powody w locie:

  • PHP jest językiem skryptowym i nie ma służyć jako podstawowe oprogramowanie wbudowane (w zasadzie pamięć jest czyszczona na końcu skryptu),
  • Od PHP5 przekazywanie przez odniesienie jest niejawne dla parametrów obiektu (więc PHP używa przekazywania przez odniesienie „na twoich plecach”).


2

Myślę, że to tylko wybór twórców, nie mający nic wspólnego z językiem. Dużo kodu PHP (wbudowanego i nie) używa referencji. Spójrz na funkcje tablic w PHP, wiele z nich używa referencji. preg_matchużywa referencji.

Myślę, że jednym z powodów, dla których programiści nie używają referencji, jest to, że może to być mylące. Wywołujesz funkcję, a jedna ze zmiennych może (ale nie musi) zostać zaktualizowana, ponieważ była referencją. Podczas debugowania może nie być jasne, dlaczego wartość $xjsut zmieniła się magicznie.


1

Podstawowym problemem związanym z tym pytaniem jest założenie, że jest to również powszechne w C ++. To nie jest Nie lubimy parametrów wyjściowych i używamy ich w jak najmniejszym stopniu - są one naprawdę powszechne w interfejsach API w stylu C.


0

Znam wiele funkcji php, które to robią. Spójrz na preg_match()przykład.$matcheszostanie przekazany przez odniesienie

Jeśli chcesz napisać dla siebie funkcję, która pobiera argumenty przez odwołanie, użyj następującej składni

function byref(&$a, &$b, $c) {
    $a += $c;
    $b += $c;
    return $a * $b;
}

$ a i $ b są przekazywane przez odniesienie $ c jest przekazywane przez wartość.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.