2009-07-09 22 views
14

Zdałem sobie sprawę, że chociaż większość moich doświadczeń polega na pisaniu aplikacji PHP, od czasu do czasu popełniam "błędy początkowe". To dlatego, że PHP jest językiem, który wyrósł bardzo organicznie i jako taki ma pewne dziwactwa, dziwactwa i pułapki, o których nie wiem.Zakłócenia i pułapki w PHP

Chciałbym, aby to pytanie było wiki dla wszystkich, którzy chcą poznać pułapki PHP i wyjątki od tego, w co moglibyśmy wierzyć, są zasady. Ale proszę, nie pisz ogólne reakcje, takie jak:

Niektóre funkcje odbierać argumenty jak $needle, $haystack, a niektóre jak $haystack, $needle.

Poinformuj o nazwach funkcji. Masz kilka odpowiedzi ode mnie jako przykłady. Aha, i dodaj jedną pułapkę na odpowiedź. W ten sposób zobaczymy, który z nich jest najbardziej pogardzany (przez głosowanie).

Nie chcę rozpoczynać wojny płomieniowej, zatrzymaj ją na temat. Jeśli chcesz napisać kilka złych rzeczy na temat PHP, zrób to jako komentarz do odpowiedniej odpowiedzi.

Mam nadzieję, że to wiki będzie pomocne dla nas wszystkich, początkujących i ekspertów.

Aktualizacja:

Po komentarzu Andrew Moore'a myślę, że odpowiedź powinna również zawierać roztwór lub obejście pitfall.

+0

Od PHP 5.3.3 nie można już używać nazwy klasy jako nazwy konstruktora, jeśli używasz przestrzeni nazw. Musisz użyć "__construct". Żadne ostrzeżenia nie zostaną wydane, ale wywołanie "nowej MyClass" nie spowoduje wykonania kodu w twoim konstruktorze. Hurray za niezłą pułapkę. – nus

Odpowiedz

1

Mimo że ciągi mogą być iterowane za pomocą pętli i indeksów for, nie można ich powtarzać za pomocą pętli foreach. Przykład:

$str = 'foo'; 
$max = strlen($str); 

for ($i=0; $i<$max; $i++) { 
    echo $str[$i]; 
} 
// outputs: foo 

foreach ($str as $char) { 
    echo $char; 
} 
// Warning: Invalid argument supplied for foreach() ... 
+4

foreach (str_split ($ str) AS $ char) {echo $ char; } –

+3

Jest tak, ponieważ łańcuchy nie są tablicami znaków w PHP. Pętla for działa tylko dlatego, że nawiasy klamrowe [] są cukrem syntaktycznym dla uzyskania dostępu do określonej postaci. Niestety daje to również wrażenie, że ciągi mogą być manipulowane jako tablice znaków, co jak widać w pętli foreach, jest nieprawdziwe. Jak zauważył Andrew, użycie str_split() jest prostym sposobem na rozbicie go na rzeczywistą tablicę, jeśli tego właśnie potrzebujesz. –

+0

nie ma nic wspólnego z oryginalnym postem ... – eddy147

10

Serializacja obiekty XML struktury procesu, a następnie unserializing ich nie przywrócić pierwotną strukturę XML:

$dom = new DOMDocument; 
$dom->loadXML('<test/>'); 

$dom = serialize($dom); 
$dom = unserialize($dom); 

var_dump($dom->saveXML()); 
// $ Warning: DOMDocument::saveXML(): Couldn't fetch DOMDocument in ... 
// $ NULL 

Podobnie obiektów SimpleXML.

8

Niezastrzeżone przez branżę pierwszeństwo operatorów.

$x = 1; 
echo 'foo: ' . $x+1 . ' bar'; 

wyświetli: "1 bar", zamiast oczekiwanego "foo: 2 bar". Rozwiązanie: Użyj nawiasów.

+7

Możliwe jest również użycie echo() do podjęcia kilku argumentów: echo 'foo:', $ x + 1, 'bar'; –

+0

Warto zauważyć, że istnieją * dwie * funky rzeczy na ten temat: nie tylko jest to pierwszeństwo, nie to, co chciałeś, ale także, ("foo: 1" + 1) nie łączy się; to najwyraźniej wynosi 1, a nie "foo: 11". – ojrac

+4

@ojrac, to dlatego, że operator konkatenacji w PHP jest. (kropka), nie + (plus) jak w wielu innych językach. + jest używane do dodawania arytmetycznego, a "foo: 1" jest oceniane na 0, aby dodać 1 do niego, a więc wynik końcowy to 1. –

7

Rozmiar całkowity zależy od platformy. Zwykle nie można używać 64-bitowych liczb całkowitych na maszynie 32-bitowej bez zewnętrznego modułu. Ponadto nie można zadeklarować liczb całkowitych bez znaku.

+0

To jest biblioteka BC. –

1

mój ulubiony:

<?php 
$a = 0; 
$b = 'x'; 
var_dump(FALSE == $a); 
var_dump($a == $b); 
var_dump($b == TRUE); 

echo' <br />Conclusion: TRUE equals FALSE (at least in PHP)'; 
+2

Można to również pokazać w innych językach skryptowych, nie tylko w PHP. Ma to związek z tym, jak "x" jest konwertowane na liczbę całkowitą w celu porównania. –

+2

Operator == wymusza typy danych. W każdym razie powinieneś używać ===. – spoulson

+0

"Operator == wymusza dane ..." nie zawsze, Czasami chcę traktować wartości zerowe, 0, "" jako fałszywe i wszystkie inne jako prawdziwe. –

2

Niektóre nowo wprowadzone funkcje PHP zawodzą, ponieważ nie ma gwarancji, będą one domyślnie obsługiwany w środowiskach hostingowych.

Największym zirytować z kopalni jest ustawieniem short_tags który umożliwia <? foobar(); ?> i <?=$var ?> składni tag. Twierdzę, że PHP powinno włączyć tę funkcję domyślnie, zamiast optować.

== EDIT ==

W PHP> = 5,4 ustawienie short_tags nie jest brany pod uwagę przy skróconej rachunku echa, jako taki będzie ona dostępna w każdym środowisku hosting, który obsługuje PHP 5.4, w górę.

+0

Zgadzam się, że krótkie znaczniki powinny być domyślne. – tj111

+7

krótkie tagi są złe. mieszają się z deklaracją XML. nie powinieneś go używać ... –

+2

Nieracjonalne. Deklaracja XML jest przypadkiem skrajnym. A potem powiesz mi, że krótkie tagi są "trudne do odczytania" i inne bzdury. Mówiąc prosto, " spoulson

8

Nienawidzę, jak można uzyskać problemy, jeśli zamkniesz pliki php za pomocą znacznika zamykającego ?> (co wydaje się być odwrotne). Na przykład umieść plik z białymi spacji po znaku?>, A następnie spróbuj zmienić nagłówki (zakładając brak bufora wyjściowego). UGH. Zajęło mi drogę do długo, aby nauczyć się nigdy bliskie pliki PHP z ?>

1

== EDIT == To nie jest już prawdą dla PHP> = 5,5!

Co ja czasami napotkasz jest błąd Fatal error: Can't use function return value in write context podczas korzystania z empty() konstrukt. Na przykład:

if (!empty(trim($_GET['s']))) { 
    // ... 
} 

empty() potrzebuje zmienną, cokolwiek innego spowoduje błędu.

Rozwiązanie:

$s = trim($_GET['s']); 
if (!empty($s)) { 
    // ... 
} 
+1

Jeszcze prostsze: 'if (! Trim ($ _ GET ['s'])) {...' – troelskn

4

niespójne konwencje nazewnictwa funkcji wbudowanych. Na przykład ten zestaw funkcji przetwarzania ciągów:

str_shuffle() 
str_split() 
str_word_count() 
strcasecmp() 
strchr() 
strcmp() 

Rozwiązanie: Pozostaw ręczny otwarty przez cały czas.

+0

Nawiasem mówiąc, częścią tego jest to, że początkowo próbowali emulować C za pomocą funkcji takich jak 'strstr()' i 'strcmp()'. –

0
$x = "a string"; 

if ($x == 142) 
{ 
    echo "lol, of course $x is a number"; 
} 
else 
{ 
    echo "$x is clearly not equal to 142"; 
} 

Kiedy run:

lol, of course a string is a number 

Musisz użyć ===

$x = "a string"; 

if ($x === 142) 
{ 
    echo "lol, of course $x is a number"; 
} 
else 
{ 
    echo "$x is clearly not equal to 142"; 
} 

Kiedy uruchomić:

a string is clearly not equal to 142 
+0

Wierzę, że ten przykład, chociaż zwykły w społeczności PHP, jest bardzo pomocny dla osób wywodzących się z języków programowania. Niektórzy nawet nie wiedzą, że istnieje coś takiego jak potrójny równy. –

+0

Tak, zabrało mi trochę czasu na debugowanie tego problemu w moim kodzie. Znałem == wymuszone typy danych, ale nie wiedziałem ("ciąg znaków" == 234) byłby prawdziwy! – Tyler

+3

Przepraszam, ale to nie jest prawda. "ciąg" == 142 będzie oceniać jako fałsz. zobacz tabelę porównawczą na http://ch.php.net/manual/en/types.comparisons.php –

7

Wiele sposobów prowadzenia badań prawdy (not operator, empty(), is_null(), isset()) + słaby wpisując = this

Z pewnym dyscypliny można w większości uniknąć potrzeby odwoływania się do tej tabeli:

  • Dla ogólnych testów prawdę, można użyć logiczną porównanie if ($) {...} if (!$x) { ... }. Zachowuje się tak, jak operatory logiczne w większości języków.

  • Zawsze używaj empty(), jeśli chcesz przetestować dane wejściowe dla wartości fałszerstw (traktuje "0" jako fałsz).

  • Zawsze używaj isset() jeśli chcesz określić whethere zmienna jest ustawiona czy nie

  • Zastosowanie is_null() lub $x === NULL jeśli tylko trzeba sprawdzić dla NULL

6

jakie miałem wszystkie rodzaje przeszkadzać łącząc foreach z referencjami

$testarray = array(1 => "one", 2 => "two"); 
$item = "three"; 
$testarray[3] =& $item; 
foreach ($testarray as $key => $item) { 
    // do nothing 
} 
echo $testarray[3]; // outputs "two" 

To naprawdę rzuciło mi się podczas w erze PHP4 i chociaż w PHP5 jest lepiej, gdy zachowujesz się normalnie, jeśli nie używasz wyraźnych odniesień, od czasu do czasu udaje mi się złapać to.

+0

Czy wiesz, co się dzieje pod maską? Ciekaw jestem, dlaczego php to zwraca. – Harijoe

+1

The = & assignment powoduje, że ostatni wpis w tablicy jest odniesieniem do zmiennej $ item. Przy każdej iteracji pętli foreach oznacza to, że $ testarray [3] zmienia się na bieżącą wartość $ item. Ponieważ $ testarray [2] ma wartość "two", wartość ta jest powtarzana podczas iteracji po $ testarray [3] i pozostaje ostateczną wartością $ testarray [3] –

2

Funkcje mają różne funkcje w różnych systemach operacyjnych, a niektóre funkcje są dostępne tylko w określonych systemach operacyjnych.

Na przykład funkcja mail() w systemie Windows nie może przyjmować nazwy nadawcy w parametrze $to. Może zawierać tylko adres e-mail. W systemie Linux wszystko działa dobrze.

Kolejny przykład, funkcja strptime() jest dostępna tylko w systemie Linux, a nie w systemie Windows (to dostarczyło mi istniejącego projektu, który chciałem uruchomić na moim oknie systemu Windows).

Oczywiście niektóre funkcje mają sens tylko w niektórych systemach operacyjnych (takich jak funkcje Win32API), ale wiele z nich wydaje się, że powinny zachowywać się tak samo we wszystkich systemach operacyjnych, podczas gdy w rzeczywistości tak nie jest.

+0

Rodzina 'exec()' jest moją ulubioną w tej kategorii. –

2

Czasami chcesz przekazać wynik funkcji do innej funkcji bezpośrednio, która akceptuje tylko zmienne jako dane wejściowe.

Na przykład:

array_pop( explode('\\', get_class($this)) ) 

... spowoduje E_STRICT-error "Tylko zmienne powinny być przekazywane przez referencję". Aby dostać się jego pracy wystarczy dodać kolejną parę nawiasów wokół wewnętrznego (zwrócone) oświadczenie:

array_pop((explode('\\', get_class($this)))) 

(jeśli używasz nazw i rozszerzone zajęcia, linia ta zwraca tylko nazwę klasy (bez nazw) z powołania obiekt - nie klasa nadrzędna, która została rozszerzona i może pełnić tę funkcję.)

+0

Wystąpił właśnie ten błąd. Dziękuję za rozwiązanie. Nawiasem mówiąc, dodatkowe nawiasy nie są rozpoznawane jako poprawne przez PHPStorm. PS: Ten problem można również rozwiązać za pomocą metod '\ ReflectionObject' i' getName() '. – Kirzilla