PHP, jak większość z nas wie, ma słabe pisanie . Dla tych, którzy tego nie robią, PHP.net mówi:
PHP nie wymaga (ani nie obsługuje) jawnej definicji typu w deklaracji zmiennej; typ zmiennej jest określony przez kontekst, w którym zmienna jest używana.
Uwielbiam to lub nienawidzę, PHP ponownie rzuca zmienne w locie. Tak więc następujący kod jest prawidłowy:
$var = "10";
$value = 10 + $var;
var_dump($value); // int(20)
PHP pozwala również jawnie rzutować zmienną, na przykład:
$var = "10";
$value = 10 + $var;
$value = (string)$value;
var_dump($value); // string(2) "20"
To wszystko fajnie ... ale przez całe życie nie mogę wymyślić praktycznego powodu, aby to zrobić.
Nie mam problemu z mocnym pisaniem w językach, które go obsługują, takich jak Java. W porządku i całkowicie to rozumiem. Jestem także świadom - i w pełni rozumiem przydatność - podpowiedzi typu w parametrach funkcji.
Problem, który mam z rzutowaniem typu, jest wyjaśniony powyższym cytatem. Jeśli PHP może zamienić typy at-woli , może to zrobić nawet po zmuszają cast typu; i może to robić w locie, gdy potrzebujesz określonego typu operacji. To sprawia, że następujące są prawidłowe:
$var = "10";
$value = (int)$var;
$value = $value . ' TaDa!';
var_dump($value); // string(8) "10 TaDa!"
Więc o co chodzi?
Weź ten teoretyczny przykład świata, w którym rzutowanie typu zdefiniowane przez użytkownika ma sens w PHP :
- Zmuszasz rzutowaną zmienną
$foo
jakoint
→(int)$foo
. - Próbujesz zapisać wartość ciągu w zmiennej
$foo
. - PHP zgłasza wyjątek !! ← To miałoby sens. Nagle istnieje przyczyna rzutowania typu zdefiniowanego przez użytkownika!
Fakt, że PHP będzie zmieniać rzeczy w zależności od potrzeb, powoduje, że punkt definiowania typu zdefiniowanego przez użytkownika jest niejasny. Na przykład następujące dwa przykłady kodu są równoważne:
// example 1
$foo = 0;
$foo = (string)$foo;
$foo = '# of Reasons for the programmer to type cast $foo as a string: ' . $foo;
// example 2
$foo = 0;
$foo = (int)$foo;
$foo = '# of Reasons for the programmer to type cast $foo as a string: ' . $foo;
Rok po tym, jak pierwotnie zadałem to pytanie, zgadnij, kto używał rzutowania czcionek w praktycznym środowisku? Z poważaniem.
Wymaganiem było wyświetlanie wartości pieniężnych na stronie internetowej dla menu restauracji. Projekt witryny wymagał przycięcia końcowych zer, aby wyświetlacz wyglądał mniej więcej tak:
Menu Item 1 .............. $ 4
Menu Item 2 .............. $ 7.5
Menu Item 3 .............. $ 3
Najlepszy sposób, w jaki udało mi się to zrobić, aby rzutować zmienną jako zmiennoprzecinkową:
$price = '7.50'; // a string from the database layer.
echo 'Menu Item 2 .............. $ ' . (float)$price;
PHP przycina końcowe zera pływaka, a następnie przekształca go jako ciąg do konkatenacji.
źródło
(string)
casty ?$intval.'bar'
zgłasza wyjątek, nadal się nie zgadzam. Nie rzuca to wyjątku w żadnym języku. (Wszystkie języki, które znam, przeprowadzają automatyczną obsadę lub a.toString()
). Jeśli mówisz, że$intval = $stringval
zgłasza wyjątek, to mówisz o silnie napisanym języku. Nie chciałem brzmieć niegrzecznie, więc przepraszam, jeśli tak zrobiłem. Wydaje mi się, że jest to sprzeczne z tym, do czego jest przyzwyczajony każdy programista, i jest o wiele, znacznie mniej wygodne.Odpowiedzi:
W języku słabo typowanym istnieje rzutowanie w celu usunięcia niejednoznaczności w operacjach na maszynie, w innym przypadku kompilator / tłumacz użyłby kolejności lub innych reguł, aby założyć, której operacji użyć.
Normalnie powiedziałbym, że PHP podąża za tym wzorcem, ale w przypadkach, które sprawdziłem, PHP zachowywał się w każdym z nich intuicyjnie.
Oto te przypadki, w których JavaScript jest używany jako język porównawczy.
Łączenie ciągów
Oczywiście nie jest to problem w PHP, ponieważ istnieją osobne operatory konkatenacji (
JavaScript.
) i dodawania (+
).Porównanie ciągów
Często w systemach komputerowych „5” jest większe niż „10”, ponieważ nie interpretuje go jako liczby. Nie w PHP, który, nawet jeśli oba są łańcuchami, zdaje sobie sprawę, że są liczbami i eliminuje potrzebę rzutowania):
JavaScript PHPWpisywanie podpisów funkcji
PHP implementuje sprawdzanie typu podpisów funkcji od podstaw, ale niestety jest tak wadliwe, że prawdopodobnie rzadko jest użyteczne.
Myślałem, że robię coś złego, ale komentarz do dokumentacji potwierdza, że wbudowanych typów innych niż tablica nie można używać w podpisach funkcji PHP - chociaż komunikat o błędzie wprowadza w błąd.
PHPI w przeciwieństwie do jakiegokolwiek innego języka, który znam, nawet jeśli użyjesz typu, który on rozumie, wartości null nie można już przekazać do tego argumentu (
must be an instance of array, null given
). Jak głupio.Interpretacja boolowska
[ Edytuj ]: ten jest nowy. Pomyślałem o innym przypadku i znowu logika jest odwrócona od JavaScript.
JavaScript PHPPodsumowując, jedynym przydatnym przypadkiem, o którym mogę pomyśleć, jest ... (bęben)
Wpisz obcinanie
Innymi słowy, jeśli masz wartość jednego typu (powiedz ciąg znaków) i chcesz zinterpretować ją jako inny typ (int) i chcesz zmusić ją, aby stała się jednym z poprawnych zestawów wartości tego typu:
Nie widzę, co tak naprawdę zyskałoby upcasting (do typu, który obejmuje więcej wartości).
Tak więc, chociaż nie zgadzam się z proponowanym przez ciebie pisaniem (zasadniczo proponujesz pisanie statyczne , ale z dwuznacznością, że tylko jeśli zostanie ono wrzucone na siłę, spowoduje błąd - co spowodowałoby zamieszanie), myślę, że to dobre pytanie, ponieważ najwyraźniej casting ma bardzo mało celu w PHP.
źródło
E_NOTICE
a może wtedy? :)E_NOTICE
może być w porządku, ale dla mnie ten dwuznaczny stan dotyczy - skąd byś wiedział, patrząc na jeden kawałek kodu, gdyby zmienna była w tym stanie (została rzucona gdzie indziej)? Znalazłem też inny warunek i dodałem go do mojej odpowiedzi.echo "010" == 010
iecho "0x10" == 0x10
;-)Miksujesz koncepcje typu słabego / silnego i dynamicznego / statycznego.
PHP jest słaby i dynamiczny, ale twój problem dotyczy koncepcji typu dynamicznego. Oznacza to, że zmienne nie mają typu, wartości mają.
„Rzutowanie typu” jest wyrażeniem, które tworzy nową wartość innego typu oryginału; nie robi nic ze zmienną (jeśli jest zaangażowana).
Jedyną sytuacją, w której regularnie wpisuję wartości rzutowania, są liczbowe parametry SQL. Powinieneś zdezynfekować / uciec od dowolnej wartości wejściowej wstawionej do instrukcji SQL lub (znacznie lepiej) użyć sparametryzowanych zapytań. Ale jeśli chcesz jakąś wartość, która MUSI być liczbą całkowitą, o wiele łatwiej jest ją po prostu rzucić.
Rozważać:
gdybym pominął pierwszą linię,
$id
byłby to łatwy wektor do wstrzyknięcia SQL. Obsada upewnia się, że jest to nieszkodliwa liczba całkowita; każda próba wstawienia jakiegoś SQL spowodowałaby po prostu zapytanie oid=0
źródło
mysql_real_escape_string($id);
ale jeszcze nie?mysql_real_escape_string()
ma lukę polegającą na tym, że nic nie robi na ciągach takich jak „0x01ABCDEF” (tj. szesnastkowa reprezentacja liczby całkowitej). W niektórych kodowaniach wielobajtowych (nie na szczęście w Unicode) taki ciąg może być użyty do przerwania zapytania (ponieważ jest oceniany przez MySQL na coś, co zawiera cytat). Dlatego animysql_real_escape_string()
nieis_int()
jest najlepszym wyborem do radzenia sobie z wartościami całkowitymi. Rzutowanie jest.Znalazłem jedno zastosowanie do rzutowania typu w PHP:
Tworzę aplikację na Androida, która wysyła żądania HTTP do skryptów PHP na serwerze w celu pobrania danych z bazy danych. Skrypt przechowuje dane w postaci obiektu PHP (lub tablicy asocjacyjnej) i jest zwracany jako obiekt JSON do aplikacji. Bez typu casting otrzymałbym coś takiego:
Ale używając rzutowania typu PHP
(int)
na identyfikator użytkownika podczas przechowywania go w obiekcie PHP, otrzymuję to zamiast tego:Następnie, gdy obiekt JSON jest analizowany w aplikacji, ratuje mnie to przed analizowaniem identyfikatora na liczbę całkowitą!
Zobacz, bardzo przydatne.
źródło
Jednym z przykładów są przedmioty z metodą __toString:
$str = $obj->__toString();
vs$str = (string) $obj;
. W drugim jest znacznie mniej pisania, a dodatkowym elementem jest interpunkcja, która trwa dłużej. Myślę też, że jest bardziej czytelny, chociaż inni mogą się nie zgodzić.Innym czyni układ jednoelementową:
array($item);
vs(array) $item;
. Spowoduje to umieszczenie dowolnego typu skalarnego (liczba całkowita, zasób itp.) W tablicy.Alternatywnie, jeśli
$item
jest obiektem, jego właściwości staną się kluczami do jego wartości. Myślę jednak, że konwersja obiekt-> tablica jest nieco dziwna: prywatne i chronione właściwości są częścią tablicy i zmieniono jej nazwę. Cytując dokumentację PHP : zmienne prywatne mają nazwę klasy dodaną do nazwy zmiennej; zmienne chronione mają znak „*” dodany do nazwy zmiennej.Innym zastosowaniem jest konwersja danych GET / POST na odpowiednie typy dla bazy danych. MySQL może sobie z tym poradzić, ale myślę, że serwery bardziej zgodne z ANSI mogą odrzucić dane. Powodem, dla którego wspomniałem tylko o bazach danych, jest to, że w większości innych przypadków na danych zostanie wykonana operacja zgodnie z ich rodzajem w pewnym momencie (tj. Int / floats zwykle będą miały na nich obliczenia itp.).
źródło
int
lubfloat
nastąpi podczas budowania zapytania).(array) $item
jest schludny , ale przydatny?Ten skrypt:
będzie działać poprawnie,
script.php?tags[]=one
ale nie powiedzie sięscript.php?tags=one
, ponieważ_GET['tags']
zwraca tablicę w pierwszym przypadku, ale nie w drugim. Ponieważ skrypt został napisany w taki sposób, aby oczekiwał tablicy (i masz mniejszą kontrolę nad ciągiem zapytania wysłanym do skryptu), problem można rozwiązać, odpowiednio rzutując wynik z_GET
:źródło
Może być również użyty jako szybka i brudna metoda, aby zapewnić, że niezaufane dane nie spowodują uszkodzenia, np. Jeśli używasz zdalnej usługi, która ma sprawdzanie poprawności crap i musi akceptować tylko liczby.
Oczywiście jest to wadliwe i również domyślnie obsługiwane przez operator porównania w instrukcji if, ale jest pomocne w upewnieniu się, że dokładnie wiesz, co robi twój kod.
źródło
$_POST['amount']
zawiera ciąg śmieci, php oceni, że nie jest on większy niż zero. Gdyby zawierał ciąg reprezentujący liczbę dodatnią, oceniałby to prawda.Jednym z „zastosowań” zmiennych PHP rzutowanych w locie, które często widzę w użyciu, są podczas pobierania danych ze źródeł zewnętrznych (dane wejściowe użytkownika lub baza danych). Pozwala programistom (zauważ, że nie powiedziałem, że programiści) ignorować (a nawet nie uczyć się) różne typy danych dostępne z różnych źródeł.
Jeden programista (zauważ, że nie powiedziałem programisty), którego kod odziedziczyłem i nadal utrzymuję, nie wie, że istnieje różnica między łańcuchem
"20"
zwracanym w$_GET
super zmiennej, a operacją całkowitą,20 + 20
gdy dodaje go do wartość w bazie danych. Ma tylko szczęście, że PHP używa.
do łączenia łańcuchów, a nie+
jak każdy inny język, ponieważ widziałem, jak jej kod „dodaje” dwa ciągi (varcahr
z MySQL i wartość z$_GET
) i dostaje int.Czy to praktyczny przykład? Tylko w tym sensie, że pozwala programistom uciec od niewiedzy, z którymi typami danych pracują. Ja osobiście tego nienawidzę.
źródło