2010-06-03 20 views
17

Miałem świetny pomysł użycia niestandardowego programu obsługi błędów, który doprowadził mnie do króliczej nory.Tylko zmienne mogą być przekazywane przez odniesienie

następujący kod daje (z lub bez niestandardowej obsługi błędów): Fatal error: Tylko zmienne mogą być przekazywane przez referencję

function foo(){ 
    $b=array_pop(array("a","b","c")); 
    return $b; 
} 
print_r(foo()); 

następujący kod daje (tylko z niestandardowych obsługi błędów): (2048) Tylko zmienne powinny być przekazywane przez referencję

function foo(){ 
    $a=explode('/' , 'a/b/c'); 
    $c=array_pop(array_slice($a,-2,1)); 
    return $c; 
} 
print_r(foo()); 

drugi martwi mnie, ponieważ mam dużo "zwartego" kodu. Tak więc, albo rezygnuję z idei używania niestandardowej procedury obsługi błędów (w celu ulepszenia modułu logowania) lub rozszerzenia całego mojego kodu.

Ktoś ma lepsze pomysły? Również WTF?

UPDATE:

Dzięki odpowiedzi nauczyłem się czegoś o tym, jak PHP czy obsługę błędów. Zamieszanie E_ALL, nie włączając E_STRICT (php 5), nie jest fajne.

Co więcej, tworzenie własnych niestandardowych procedur obsługi błędów umożliwia domyślnie E_STRICT i tam, gdzie zaczynają się problemy.

Morał z tej historii polega na użyciu własnego programu do obsługi błędów, aby złapać je ALL i użyć stałych błędu (E_STRICT, E_USER_WARNING, E_USER_ERROR itd.) Do wykonania filtrowania.

Co mam powiedzieć na temat "problemu z korupcją pamięci" ze zmiennymi referencjami i określonymi funkcjami? Podwójnie bez płynu. Będę (co nie znaczy, że powinieneś) ignorować E_STRICT w moim programie obsługi błędów, a życie toczy się dalej.

+0

$ b = current (array_reverse (array ("a", "b", "c"))); // tak, to głupie, ale działa :) – MSpreij

Odpowiedz

0

Spróbuj tego:

function foo(){ 
    $a = array("a","b","c"); 
    $b = array_pop($a); 
    return $b; 
} 
+0

Jeśli czytasz do końca pytania ... – zaf

18

array_pop() stara się zmienić tę wartość, która jest przekazywana jako parametr. Teraz w twoim drugim przykładzie jest to wartość zwracana przez array_slice(). Pod względem silnika jest to "wartość tymczasowa" i takiej wartości nie można przekazać za pomocą odniesień. co trzeba to tymczasowa zmienna:

function foo(){ 
    $a=explode('/' , 'a/b/c'); 
    $b=array_slice($a,-2,1); 
    $c=array_pop($b); 
    return $c; 
} 
print_r(foo()); 

Następnie odniesienie do $ b mogą być przekazywane do array_pop(). Zobacz http://php.net/references, aby uzyskać więcej informacji na temat referencji.

1

array_pop() zmienia wartość przekazaną do niej, z której pochodzi błąd. Funkcji nie można zmienić. Innymi słowy, musisz najpierw przypisać tablicę do zmiennej (patrz: manual), a następnie uruchomić array_pop().

Kod trzeba to:

function foo(){ 
    $a = array("a","b","c"); 
    $b = array_pop($a); 
    return $b; 
} 

EDIT: Obie funkcje, które wymieniłeś mają ten sam problem. Przypisz tablicę do zmiennej i przekaż zmienną do array_pop().

4

To jest problem z korupcją pamięci (według zespołu programistów PHP). Wystarczy rzucić w cesji:

function foo(){ 
    $b = array_pop($arr = array("a","b","c")); 
    return $b; 
} 
print_r(foo()); 

:

function foo(){ 
    $a = explode('/' , 'a/b/c'); 
    $c = array_pop($arr = array_slice($a,-2,1)); 
    return $c; 
} 
print_r(foo()); 

Drugi produkuje E_STRICT. Możesz sobie z tym poradzić w inny sposób, jeśli chcesz (jeśli nie chcesz zmieniać tych funkcji).

+0

Widziałem gdzieś tę sztuczkę. Czy dotyczy to wszystkich lub niektórych funkcji? – zaf

+0

Możesz rzucić zadanie w dowolnej * funkcji *. Ale nie w * konstruktach językowych *, takich jak 'puste'. – webbiedave

+0

To poważnie przeszkadza mojej kung-fu-ness. – zaf

9

Oto, co otrzymuję próbując drugi fragment kodu php w php-cli po ustawieniu error_reporting na E_ALL | E_STRICT

[email protected]:~/workspace/universcine.com$ php -a 
Interactive shell 

php > function foo(){ 
php {  $a=explode('/' , 'a/b/c'); 
php {  $c=array_pop(array_slice($a,-2,1)); 
php {  return $c; 
php { } 
php > print_r(foo()); 
PHP Strict standards: Only variables should be passed by reference in php shell code on line 3 
PHP Stack trace: 
PHP 1. {main}() php shell code:0 
PHP 2. foo() php shell code:1 

Jak widać, to tylko surowe normy tutaj. Możesz łatwo pozwolić, aby niestandardowy moduł obsługi błędów zignorował je (na podstawie wartości, jaką otrzymasz: na przykład 2048, tutaj).

od PHP 5.3, E_ALL nie obejmuje E_STRICT, spójrz na to:

php > foreach(array("E_ALL", "E_DEPRECATED", "E_STRICT", "E_NOTICE", "E_PARSE", "E_WARNING") as $const) echo $const . " :\t" . constant($const) ."\t". decbin(constant($const)). "\n"; 
E_ALL :  30719 111011111111111 
E_DEPRECATED : 8192  10000000000000 
E_STRICT :  2048  100000000000 
E_NOTICE :  8     1000 
E_PARSE :  4     100 
E_WARNING : 2     10 

od PHP 5.4, E_ALL obejmuje E_STRICT:

E_ALL :   32767 111111111111111 
E_DEPRECATED :  8192  10000000000000 
E_STRICT :   2048  100000000000 
E_NOTICE :   8     1000 
E_PARSE :   4     100 
E_WARNING :  2     10 
+0

Czy E_ALL nie zawiera E_STRICT ??? – zaf

+0

Nie, nie, zredagowałem mój post, aby dodać objaśniający fragment kodu. Zobacz brakujący 1 w E_ALL? Jeśli dodasz E_STRICT, otrzymasz 111111111111111! Oznacza wygraną! – greg0ire

+0

w PHP 5.3 E_ALL zawiera E_STRICT – johannes

1

myślę, że teraz (od php 5) powinno być:

function &foo(){ //NOTICE THE & 
    $b=array_pop(array("a","b","c")); 
    return $b; 
} 
print_r(foo()); 

i

function &foo(){ //NOTICE THE & 
    $a=explode('/' , 'a/b/c'); 
    $c=array_pop(array_slice($a, $b = -2, $c = 1)); //NOW NO DIRECT VALUES ARE PASSED IT MUST BE VARIABLES 
    return $c; 
} 
print_r(foo()); 

ale jestem tylko początkujący :)

+0

Dzięki za odpowiedź. Nie mam czasu, aby spróbować, ale czy mówisz, że dodanie "&" sprawia, że ​​to działa? I co robi? Sprawdzę to jutro. – zaf

Powiązane problemy