PHP 5.4 Przekazywanie według czasu połączenia - Łatwa poprawka?

219

Czy jest jakiś sposób, aby łatwo rozwiązać ten problem, czy naprawdę muszę przepisać cały starszy kod?

Błąd krytyczny PHP: Usunięto przekazanie odwołania według czasu połączenia w ... w linii 30

Dzieje się tak wszędzie, ponieważ zmienne są przekazywane do funkcji jako odwołania w całym kodzie.

Bardiir
źródło

Odpowiedzi:

344

Powinieneś oznaczać wywołanie przez odwołanie w definicji funkcji, a nie rzeczywiste wywołanie. Ponieważ PHP zaczęło wyświetlać błędy przestarzałości w wersji 5.3, powiedziałbym, że dobrym pomysłem byłoby przepisanie kodu.

Z dokumentacji :

W wywołaniu funkcji nie ma znaku odniesienia - tylko w definicjach funkcji. Same definicje funkcji są wystarczające, aby poprawnie przekazać argument przez odwołanie. Od PHP 5.3.0, otrzymasz ostrzeżenie, że „call-time pass-by-reference” jest przestarzałe podczas korzystania &w foo(&$a);.

Na przykład zamiast używać:

// Wrong way!
myFunc(&$arg);               # Deprecated pass-by-reference argument
function myFunc($arg) { }

Posługiwać się:

// Right way!
myFunc($var);                # pass-by-value argument
function myFunc(&$arg) { }
Tim Cooper
źródło
9
Wycofanie następuje od PHP 5.0.0, który dawał E_COMPILE_WARNINGbłąd poziomu, dla odniesienia: php.net/manual/en/…
hakre
5
Miałem ten błąd, ale musiałem usunąć & insted dodawania do zmiennej.
Diana
2
Użyłem tego w starym kodzie dla obiektu o nazwie event (& $ event) i musiałem usunąć znak ampersand, aby komunikat o błędzie zniknął.
Natalia
1
przez wszystkie lata pracy jako programista nigdy nie potrzebowałem używać & na php. nigdy przenigdy. właśnie tego szukałem. świetnie
Juan Vilar
8
dla osób w komentarzach należy pamiętać, że usunięcie & może spowodować nieoczekiwane wyniki, ponieważ wszelkie zmiany w zmiennej nie będą już udostępniane, ale będą widoczne tylko dla lokalnego zasięgu funkcji. Więc jeśli nie wiesz, co robi kod, zalecam naprawienie go w sposób opisany powyżej zamiast usuwania znaku &
xorinzor,
8

Dla każdego, kto, podobnie jak ja, czyta to, ponieważ musi zaktualizować gigantyczny starszy projekt do wersji 5.6: jak wskazują tutaj odpowiedzi, nie ma szybkiej poprawki: naprawdę musisz znaleźć każde wystąpienie problemu ręcznie i naprawić .

Najwygodniejszy sposób, w jaki znalazłem znalezienie wszystkich problematycznych linii w projekcie (bez użycia pełnoprawnego analizatora kodu statycznego, co jest bardzo dokładne, ale nie znam takich, które od razu zabiorą cię do właściwej pozycji w edytorze) używałem Visual Studio Code, który ma wbudowany ładny linter PHP, a także jego funkcję wyszukiwania, która pozwala na wyszukiwanie według Regex. (Oczywiście można do tego użyć dowolnego edytora IDE / Code, który przeszukuje PHP i wyszukuje Regex.)

Za pomocą tego wyrażenia regularnego:

^(?!.*function).*(\&\$)

możliwe jest przeszukiwanie całego projektu pod kątem występowania &$tylko w wierszach, które nie są definicją funkcji.

Nadal pojawia się wiele fałszywych trafień, ale ułatwia to pracę.

Przeglądarka wyników wyszukiwania VSCode sprawia, że ​​przechodzenie i znajdowanie obraźliwych linii jest bardzo łatwe: wystarczy kliknąć każdy wynik i zwrócić uwagę na te, które linijka podkreśla na czerwono. Te, które musisz naprawić.

Pekka
źródło
1
Właśnie tego szukałem!
Sonny,
4
Dokładniejszego wyrażenia regularnego używam w tym celu:(?<!function)[:> ][a-zA-Z0-9_]+(?<!foreach|array)\s?\([^()]*&\$
Mojo
wystarczy użyć phpcs, wykopie każdy plik, który ma to dla Ciebie.
Thomas Cheng
6

PHP i referencje są nieco nieintuicyjne. Odpowiednio użyte odnośniki w odpowiednich miejscach mogą zapewnić dużą poprawę wydajności lub uniknąć bardzo brzydkich obejść i nietypowego kodu.

Następujące spowoduje błąd:

 function f(&$v){$v = true;}
 f(&$v);

 function f($v){$v = true;}
 f(&$v);

Żadne z nich nie musi zawieść, ponieważ mogą one przestrzegać poniższych zasad, ale bez wątpienia zostały usunięte lub wyłączone, aby zapobiec wielu nieporozumieniom.

Jeśli zadziałały, oba obejmują redundantną konwersję do referencji, a druga obejmuje również redundantną konwersję z powrotem do zmiennej o ograniczonym zasięgu.

Drugi umożliwiał przekazanie referencji do kodu, który nie był przeznaczony do pracy z referencjami. Jest to wyjątkowo brzydkie ze względu na łatwość konserwacji.

To nic nie da:

 function f($v){$v = true;}
 $r = &$v;
 f($r);

Mówiąc dokładniej, zamienia referencję z powrotem w normalną zmienną, ponieważ nie poprosiłeś o referencję.

To zadziała:

 function f(&$v){$v = true;}
 f($v);

Widzisz, że przekazujesz nie-referencję, ale chcesz referencji, więc zamienia ją w referencję.

Oznacza to, że nie można przekazać referencji do funkcji, w której referencja nie jest wyraźnie proszona o uczynienie z niej jednego z niewielu obszarów, w których PHP ściśle przekazuje typy lub w tym przypadku bardziej typu meta.

Jeśli potrzebujesz bardziej dynamicznego zachowania, zadziała to:

 function f(&$v){$v = true;}
 $v = array(false,false,false);
 $r = &$v[1];
 f($r);

Tutaj widzisz, że chcesz referencję i już ją masz, więc zostaw ją w spokoju. Może również łańcuch odniesienia, ale wątpię w to.

jgmjgm
źródło