it-swarm.dev

PHP'de döküm değişkenleri yazın, bunu yapmanın pratik nedeni nedir?

PHP, çoğumuzun bildiği gibi zayıf yazım . Yapmayanlar için PHP.net diyor:

PHP, değişken bildiriminde açık tür tanımı gerektirmez (veya desteklemez); bir değişkenin türü, değişkenin kullanıldığı bağlama göre belirlenir.

Sevin ya da nefret edin, PHP değişkenleri anında yeniden yayınlar. Bu nedenle, aşağıdaki kod geçerlidir:

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

PHP ayrıca aşağıdaki gibi açıkça bir değişken yayınlamanıza izin verir:

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

Her şey yolunda ... ama benim hayatım boyunca bunu yapmak için pratik bir neden düşünemiyorum.

Java gibi onu destekleyen dillerde güçlü yazmayla ilgili bir sorunum yok. Bu iyi ve bunu tamamen anlıyorum. Ayrıca, işlev parametrelerinde - tip ipuc işlevinin yararlı olduğunu tam olarak anlıyorum.

Tip dökümü ile ilgili sorun yukarıdaki alıntı ile açıklanmaktadır. PHP istekleri istediği gibi değiştirebilirse , sizden sonra bile bunu yapabilir bir türü zorla yayınlamaya ve belirli bir türe ihtiyacınız olduğunda anında yapabilir Bu, aşağıdakileri geçerli kılar:

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

Ne anlamı var?


Kullanıcı tanımlı tür dökümünün PHP'de anlamlı olduğu bir dünya teorik örneğini ele alalım :

  1. Cast değişkenini $foo, int(int)$foo Olarak zorlarsınız.
  2. $foo Değişkeninde bir dize değeri depolamaya çalışın.
  3. PHP bir istisna atar !! ← Bu mantıklı olurdu. Aniden kullanıcı tanımlı tipte dökümün nedeni var!

PHP bir şeyleri gerektiği gibi değiştirecek olması, kullanıcı tanımlı tür döküm belirsizliğini artırır.Örneğin, aşağıdaki iki kod örneği eşdeğerdir:

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

Başlangıçta bu soruyu sorduktan bir yıl sonra, tahmin edin kim kendini pratik bir ortamda daktilo kullanarak kullanıyor? Saygılarımla.

Gereksinim, bir restoran menüsü için bir web sitesinde para değerleri görüntülemekti. Sitenin tasarımı, takip eden sıfırların kırpılmasını gerektirdi, böylece ekran aşağıdaki gibi görünüyordu:

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

Değişkeni bir şamandıra olarak dökmek için bu atıkları yapmanın en iyi yolu:

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

PHP şamandıranın sonundaki sıfırları keser ve şamandırayı birleştirme dizesi olarak yeniden oluşturur.

45
Stephen

Zayıf yazılan bir dilde, yazılan işlemlerde belirsizliği gidermek için tür dökümü vardır, aksi takdirde derleyici/yorumlayıcı hangi işlemi kullanacağını varsaymak için düzen veya başka kurallar kullanır.

Normalde PHP bu kalıbı takip eder, ama kontrol ettiğim vakaların = PHP her birinde karşı sezgisel davrandığını söyleyebilirim.

JavaScript'i karşılaştırma dili olarak kullanan durumlar.

Dize Birleşimi

Açıkça bu PHP 'da bir sorun değil çünkü ayrı dize birleştirme (.) ve ekleme (+) operatörler.

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

Dize Karşılaştırması

Genellikle bilgisayar sistemlerinde "5", "10" dan büyüktür, çünkü sayı olarak yorumlamaz. PHP'de öyle değil ki, her ikisi de dizeler olsa bile, bunların sayı olduğunu fark eder ve bir döküm ihtiyacını ortadan kaldırır):

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

İşlev imza yazma

PHP, işlev imzalarında çıplak kemik tipi denetimi uygular, ancak maalesef çok kusurludur, muhtemelen nadiren kullanılabilir.

Yanlış bir şey yapıyor olabilir düşündüm, ama bir docs yorum dizi dışında yerleşik türlerin kullanılamaz doğrular PHP işlev imzaları - gerçi) hata mesajı yanıltıcı.

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?

Ve bildiğim diğer dillerden farklı olarak, anladığı bir tür kullansanız bile, null artık bu argümana geçirilemez (must be an instance of array, null given). Ne kadar aptalca.

Boole yorumu

[ Düzenleme ]: Bu yeni. Başka bir durum düşündüm ve yine mantık JavaScript'ten geri döndü.

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.

Sonuç olarak, aklıma gelen tek yararlı durum ... (drumroll)

Tip kesme

Diğer bir deyişle, bir tür değerine (dize diyelim) sahip olduğunuzda ve bunu başka bir tür (int) olarak yorumlamak istediğinizde ve bunu bu türdeki geçerli değer kümelerinden biri olmaya zorlamak istediğinizde:

$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

Hangi upcasting'in (daha fazla değer içeren bir tür için) gerçekten size kazandığını göremiyorum.

Bu nedenle, yazarak önerilen kullanımınıza katılmıyorum (esasen statik yazarak öneriyorsunuz, ancak yalnızca force-cast bir türe gireceği belirsizliği ile Görünüşe göre döküm PHP çok çok az amaca sahiptir çünkü bu bir hata - bu karışıklığa neden olur), bence bu iyi bir soru.

32
Nicole

Zayıf/güçlü ve dinamik/statik tip kavramlarını karıştırıyorsunuz.

PHP zayıf ve dinamik, ancak sorununuz dinamik tip konseptinde. Bu, değişkenlerin bir türü olmadığı, değerlerin de olduğu anlamına gelir.

'Tür dökümü', farklı türde orijinal için yeni bir değer üreten bir ifadedir; değişkene hiçbir şey yapmaz (eğer varsa).

Düzenli olarak cast değerleri yazdığım tek durum sayısal SQL parametreleridir. SQL ifadelerine eklediğiniz herhangi bir giriş değerini sterilize etmeniz/bu değerlerden kaçmanız veya parametreli sorgular kullanmanız gerekir. Ancak, bir tamsayı OLMASI GEREKEN bir değer istiyorsanız, sadece atmak çok daha kolaydır.

Düşünmek:

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

ilk satırı dışarıda bırakırsam, $id SQL enjeksiyonu için kolay bir vektör olurdu. Oyuncular bunun zararsız bir tamsayı olmasını sağlar; bazı SQL ekleme girişimleri id=0

15
Javier

Bulduğum PHP türünde döküm için bir kullanım:

Android = PHP bir veritabanından veri almak için sunucudaki komut dosyaları) yapan Android $ === bir uygulama geliştiriyorum. veri = PHP nesne (veya ilişkilendirilebilir dizi) şeklinde ve uygulamaya bir JSON nesnesi olarak döndürülür.Tipi döküm olmadan böyle bir şey alırsınız:

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

Ancak, PHP tür döküm (int) PHP nesne depolanırken kullanıcının kimliğinde _, bunun yerine bu uygulamaya döndüm:

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

Sonra JSON nesnesi app ayrıştırıldığında, beni bir tamsayı kimliği ayrıştırmak zorunda kurtarır!

Bakın, çok faydalı.

4
Ryan

Bir örnek __toString yöntemine sahip nesnelerdir: $str = $obj->__toString(); vs $str = (string) $obj;. İkincisinde çok daha az yazım var ve ekstra şeyler noktalama işaretidir ve yazılması daha uzun sürer. Diğerlerinin de aynı fikirde olmasa da daha okunabilir olduğunu düşünüyorum.

Bir diğeri tek elemanlı bir dizi yapmaktır: array($item); vs (array) $item;. Bu, bir dizinin içine herhangi bir skaler tip (tamsayı, kaynak vb.) Koyacaktır.
Alternatif olarak, eğer $item bir nesnedir, özellikleri değerlerinin anahtarı olur. Ancak, nesne-> dizi dönüşüm biraz garip olduğunu düşünüyorum: özel ve korumalı özellikleri dizinin bir parçası olan ve yeniden adlandırılmış. PHP belgeleri : özel değişkenlerini alıntılamak için, sınıf adı değişken adının başına eklenir; korumalı değişkenlerin başında değişken adı '*' vardır.

Başka bir kullanım, GET/POST verilerini bir veritabanı için uygun türlere dönüştürmektir. MySQL bu işleyebilir ama daha ANSI uyumlu sunucular veri reddedebilir düşünüyorum. Yalnızca veritabanlarından bahsetmemin nedeni, diğer birçok durumda, verilerin bir noktada türüne göre gerçekleştirilen bir işlemin (yani int/float'larda genellikle hesaplamalar yapılması vb.) Olmasıdır.

3
Alan Pearce

Ayrıca, güvenilir olmayan verilerin bir şeyi kırmayacağından emin olmak için hızlı ve kirli bir yöntem olarak da kullanılabilir; örneğin, bok doğrulamasına sahip ve yalnızca sayıları kabul etmesi gereken uzak bir hizmet kullanılıyorsa.

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

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

Açıkçası bu kusurludur ve if deyiminde karşılaştırma operatörü tarafından örtük olarak ele alınır, ancak kodunuzun ne yaptığını tam olarak bilmenizi sağlar.

0
Gruffputs

Bu komut dosyası:

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

script.php?tags[]=one için iyi çalışır ancak script.php?tags=one için başarısız olur, çünkü _GET['tags'] ilk durumda bir dizi döndürür ancak ikincisinde değil. Komut dosyası bir dizi beklemek için yazıldığından (ve komut dosyasına gönderilen sorgu dizesi üzerinde daha az kontrole sahip olduğunuzdan), sorunu _GET Öğesinden uygun şekilde çevirerek çözülebilir:

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