it-swarm-id.com

Ketik variabel casting di PHP, apa alasan praktis untuk melakukan ini?

PHP, seperti yang kita ketahui, memiliki mengetik lemah . Bagi yang tidak, PHP.net mengatakan:

PHP tidak memerlukan (atau mendukung) definisi tipe eksplisit dalam deklarasi variabel; tipe variabel ditentukan oleh konteks di mana variabel digunakan.

Suka atau benci, PHP menampilkan ulang variabel saat itu juga. Jadi, kode berikut ini valid:

$var = "10";
$value = 10 + $var;
var_dump($value); // int(20)

PHP juga memungkinkan Anda untuk melemparkan variabel secara eksplisit, seperti:

$var = "10";
$value = 10 + $var;
$value = (string)$value;
var_dump($value); // string(2) "20"

Itu semua keren ... tetapi, untuk kehidupan saya, saya tidak dapat membayangkan alasan praktis untuk melakukan ini.

Saya tidak punya masalah dengan pengetikan yang kuat dalam bahasa yang mendukungnya, seperti Java. Tidak apa-apa, dan saya benar-benar memahaminya. Juga, saya menyadari - dan sepenuhnya memahami kegunaan - type hinting dalam parameter fungsi.

Masalah yang saya miliki dengan tipe casting dijelaskan oleh kutipan di atas. Jika PHP dapat menukar jenis sesuka , ia dapat melakukannya bahkan setelah Anda memaksa melemparkan suatu jenis; dan itu dapat melakukannya sambil jalan saat Anda membutuhkan jenis tertentu dalam sebuah operasi. Itu membuat yang berikut ini valid:

$var = "10";
$value = (int)$var;
$value = $value . ' TaDa!';
var_dump($value); // string(8) "10 TaDa!"

Jadi apa gunanya?


Ambil contoh teoretis dari dunia ini di mana casting tipe yang ditentukan pengguna masuk akal dalam PHP :

  1. Anda memaksa variabel pemain $foo sebagai int(int)$foo.
  2. Anda mencoba untuk menyimpan nilai string dalam variabel $foo.
  3. PHP melempar pengecualian !! ← Itu masuk akal. Tiba-tiba alasan casting tipe yang ditentukan pengguna ada!

Fakta bahwa PHP akan mengubah keadaan sesuai kebutuhan membuat titik dari tipe casting yang didefinisikan pengguna tidak jelas. Misalnya, dua contoh kode berikut ini setara:

// 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;

Setahun setelah awalnya mengajukan pertanyaan ini, tebak siapa yang mendapati dirinya menggunakan typecasting di lingkungan praktis? Hormat kami.

Syaratnya adalah untuk menampilkan nilai uang di situs web untuk menu restoran. Desain situs mengharuskan agar trailing zero dipangkas, sehingga tampilan tampak seperti berikut:

Menu Item 1 .............. $ 4
Menu Item 2 .............. $ 7.5
Menu Item 3 .............. $ 3

Cara terbaik yang saya temukan untuk melakukan itu adalah membuang variabel sebagai pelampung:

$price = '7.50'; // a string from the database layer.
echo 'Menu Item 2 .............. $ ' . (float)$price;

PHP memotong nol trailing float, dan kemudian menampilkan kembali float sebagai string untuk penggabungan.

45
Stephen

Dalam bahasa yang diketik dengan lemah, casting tipe ada untuk menghapus ambiguitas dalam operasi yang diketik, ketika sebaliknya kompiler/juru bahasa akan menggunakan urutan atau aturan lain untuk membuat asumsi operasi yang digunakan.

Biasanya saya akan mengatakan PHP mengikuti pola ini, tetapi dari kasus yang saya periksa, PHP telah berperilaku kontra-intuitif di masing-masing).

Berikut adalah kasus-kasus itu, menggunakan JavaScript sebagai bahasa perbandingan.

String Concatentation

Jelas ini bukan masalah di PHP karena ada string string yang terpisah (.) dan penambahan (+) operator.

JavaScript
var a = 5;
var b = "10"
var incorrect = a + b; // "510"
var correct = a + Number(b); // 15

Perbandingan String

Seringkali dalam sistem komputer "5" lebih besar dari "10" karena tidak menafsirkannya sebagai angka. Tidak demikian halnya di PHP, yang, walaupun keduanya adalah string, menyadari bahwa itu adalah angka dan menghilangkan kebutuhan untuk pemeran):

JavaScript
console.log("5" > "10" ? "true" : "false"); // true
PHP
echo "5" > "10" ? "true" : "false";  // false!

Fungsi mengetik tanda tangan

PHP mengimplementasikan pemeriksaan tipe kosong pada tanda tangan fungsi, tapi sayangnya itu sangat cacat sehingga jarang digunakan.

Saya pikir saya mungkin melakukan sesuatu yang salah, tetapi komentar pada dokumen mengonfirmasi bahwa tipe bawaan selain array tidak dapat digunakan dalam tanda tangan fungsi PHP - meskipun pesan kesalahan menyesatkan.

PHP
function testprint(string $a) {
    echo $a;
}

$test = 5;
testprint((string)5); // "Catchable fatal error: Argument 1 passed to testprint()
                      //  must be an instance of string, string given" WTF?

Dan tidak seperti bahasa lain yang saya tahu, bahkan jika Anda menggunakan jenis yang dimengerti, null tidak bisa lagi diteruskan ke argumen itu (must be an instance of array, null given). Bodoh sekali.

Interpretasi Boolean

[ Edit ]: Yang ini baru. Saya memikirkan kasus lain, dan sekali lagi logikanya terbalik dari JavaScript.

JavaScript
console.log("0" ? "true" : "false"); // True, as expected. Non-empty string.
PHP
echo "0" ? "true" : "false"; // False! This one probably causes a lot of bugs.

Jadi sebagai kesimpulan, satu-satunya kasus berguna yang dapat saya pikirkan adalah ... (drumroll)

Ketik pemotongan

Dengan kata lain, ketika Anda memiliki nilai satu jenis (katakanlah string) dan Anda ingin menafsirkannya sebagai jenis lain (int) dan Anda ingin memaksanya untuk menjadi salah satu set nilai yang valid dalam jenis itu:

$val = "test";
$val2 = "10";
$intval = (int)$val; // 0
$intval2 = (int)$val2; // 10
$boolval = (bool)$intval // false
$boolval2 = (bool)$intval2 // true
$props = (array)$myobject // associative array of $myobject's properties

Saya tidak bisa melihat upcasting apa (untuk tipe yang mencakup lebih banyak nilai) yang benar-benar akan memberi Anda keuntungan.

Jadi sementara saya tidak setuju dengan usulan penggunaan pengetikan (Anda pada dasarnya mengusulkan pengetikan statis , tetapi dengan ambiguitas bahwa hanya jika itu force-cast ke dalam suatu jenis akan itu melempar kesalahan - yang akan menyebabkan kebingungan), saya pikir itu pertanyaan yang bagus, karena casting tampaknya memiliki sangat tujuan kecil di PHP.

32
Nicole

Anda sedang mencampur konsep tipe lemah/kuat dan dinamis/statis.

PHP lemah dan dinamis, tetapi masalah Anda terletak pada konsep tipe dinamis. Itu berarti, variabel tidak memiliki tipe, nilai tidak.

'Casting tipe' adalah ekspresi yang menghasilkan nilai baru dari tipe yang berbeda dari aslinya; itu tidak melakukan apa pun pada variabel (jika ada yang terlibat).

Satu situasi di mana saya secara teratur mengetikkan nilai-nilai cor adalah pada parameter SQL numerik. Anda seharusnya membersihkan/menghindar dari nilai input apa pun yang Anda masukkan ke dalam pernyataan SQL, atau (jauh lebih baik) menggunakan query parameter. Tetapi, jika Anda ingin beberapa nilai yang HARUS berupa bilangan bulat, jauh lebih mudah untuk hanya melemparkannya.

Mempertimbangkan:

function get_by_id ($id) {
   $id = (int)$id;
   $q = "SELECT * FROM table WHERE id=$id LIMIT 1";
   ........
}

jika saya meninggalkan baris pertama, $id akan menjadi vektor yang mudah untuk injeksi SQL. Para pemain memastikan bahwa itu adalah bilangan bulat yang tidak berbahaya; setiap upaya untuk memasukkan beberapa SQL hanya akan menghasilkan permintaan untuk id=0

15
Javier

Satu penggunaan untuk tipe casting di PHP yang saya temukan:

Saya sedang mengembangkan aplikasi Android yang membuat permintaan http ke PHP skrip pada server untuk mengambil data dari database. Script menyimpan data dalam bentuk objek PHP (atau array asosiatif) dan dikembalikan sebagai objek JSON ke aplikasi. Tanpa tipe casting saya akan menerima sesuatu seperti ini:

{ "user" : { "id" : "1", "name" : "Bob" } }

Tapi, menggunakan PHP type casting (int) pada id pengguna ketika menyimpannya objek PHP, saya malah mengembalikannya ke aplikasi:

{ "user" : { "id" : 1, "name" : "Bob" } }

Kemudian ketika objek JSON diuraikan dalam aplikasi, itu menyelamatkan saya dari keharusan mengurai id ke Integer!

Lihat, sangat bermanfaat.

4
Ryan

Salah satu contohnya adalah objek dengan metode __toString: $str = $obj->__toString(); vs $str = (string) $obj;. Mengetik yang kedua jauh lebih sedikit, dan hal-hal tambahan adalah tanda baca, yang membutuhkan waktu lebih lama untuk mengetik. Saya juga berpikir itu lebih mudah dibaca, meskipun yang lain mungkin tidak setuju.

Lainnya sedang membuat array elemen tunggal: array($item); vs (array) $item;. Ini akan menempatkan semua jenis skalar (integer, sumber daya, dll.) Di dalam array.
Altenatif, jika $item adalah sebuah objek, propertinya akan menjadi kunci nilai-nilainya. Namun, saya pikir konversi objek-> array agak aneh: properti pribadi dan dilindungi adalah bagian dari array, dan diganti namanya. Mengutip dokumentasi PHP : variabel pribadi memiliki nama kelas yang diawali dengan nama variabel; variabel yang dilindungi memiliki '*' yang diawali dengan nama variabel.

Penggunaan lain adalah mengubah data GET/POST menjadi tipe yang sesuai untuk basis data. MySQL dapat menangani ini sendiri, tetapi saya pikir server yang lebih sesuai dengan ANSI mungkin menolak data. Alasan saya hanya menyebutkan database adalah bahwa dalam kebanyakan kasus lain, data akan memiliki operasi yang dilakukan di atasnya sesuai dengan jenisnya di beberapa titik (mis. Int/floats biasanya akan memiliki perhitungan yang dilakukan pada mereka, dll.).

3
Alan Pearce

Ini juga dapat digunakan sebagai metode cepat dan kotor untuk memastikan data yang tidak dipercaya tidak akan merusak sesuatu misalnya jika menggunakan layanan jarak jauh yang memiliki validasi sampah dan hanya boleh menerima angka.

$amount = (float) $_POST['amount'];

if( $amount > 0 ){
    $remoteService->doacalculationwithanumber( $amount );    
}

Jelas ini cacat dan juga ditangani secara implisit oleh operator perbandingan dalam pernyataan if, tetapi sangat membantu dalam memastikan Anda tahu persis apa yang dilakukan kode Anda.

0
Gruffputs

Skrip ini:

$tags = _GET['tags'];
foreach ($tags as $tag) {
    echo 'tag: ', $tag;
}

akan berjalan dengan baik untuk script.php?tags[]=one tetapi akan gagal untuk script.php?tags=one, karena _GET['tags'] mengembalikan array dalam kasus pertama tetapi tidak dalam array kedua. Karena skrip ditulis untuk mengharapkan array (dan Anda kurang memiliki kendali atas string kueri yang dikirim ke skrip), masalahnya dapat diselesaikan dengan memberikan hasil dari _GET:

$tags = (array) _GET['tags'];
foreach ($tags as $tag) {
    echo 'tag: ', $tag;
}
0
beldaz