Çeşitli tartışma ve cevaplara genel bir bakış sunmaya çalışmak:
Kullanılabilecek tüm yolların yerini alabilecek soruya tek bir cevap yoktur isset. Bazı kullanım durumları diğer işlevler tarafından ele alınırken, diğerleri incelemeye dayanmaz veya kod golfünün ötesinde şüpheli bir değere sahiptir. Neden Uzak "kırık" veya "tutarsız" olmaktan başka kullanım durumları göstermek issetiçin bireyin tepki nullmantıksal davranıştır.
Gerçek kullanım durumları (çözümlerle birlikte)
1. Dizi tuşları
Diziler ile değişkenlerin koleksiyonları gibi tedavi edilebilir unsetve issetbunlar sanki onları tedavi. Ancak yinelenebildikleri, sayılabildikleri vb. İçin eksik bir değer, değeri olan değerle aynı değildir null.
Bu durumda cevap etmektir kullanmak array_key_exists()yerineisset() .
Bu, diziyi işlev bağımsız değişkeni olarak kontrol etmesi gerektiğinden, dizinin kendisi yoksa PHP yine de "bildirimleri" yükseltir. Bazı durumlarda, geçerli olarak her bir boyutun ilk olarak başlatılmış olması gerektiği söylenebilir, bu nedenle bildirim işini yapmaktadır. Diğer durumlarda, array_key_existsdizinin her bir boyutunu sırayla kontrol eden bir "özyinelemeli" işlev bundan kaçınır, ancak temel olarak aynı olur @array_key_exists. Aynı zamanda nulldeğerlerin işlenmesine teğettir .
2. Nesne özellikleri
Geleneksel "Nesne Odaklı Programlama" teorisinde, kapsülleme ve polimorfizm nesnelerin temel özellikleridir; PHP en gibi sınıf tabanlı OOP uygulanmasında, kapsüllü özellikler sınıf tanımının bir parçası olarak bildirilen ve verilen erişim düzeylerini ( public, protectedveyaprivate ).
Bununla birlikte, PHP ayrıca bir dizinin anahtarları gibi bir nesneye dinamik olarak özellikler eklemenize izin verir ve bazı insanlar sınıfsız nesneler kullanır (teknik olarak, yerleşik örnekler stdClass , hiçbir yöntemi veya özel işlevselliği olmayan ) kullanır. çağrışımsal dizilere giden yol. Bu, bir işlevin kendisine verilen nesneye belirli bir özelliğin eklenip eklenmediğini bilmek isteyebileceği durumlara yol açar.
Dizi anahtarlarında olduğu gibi, nesne özelliklerini denetlemeye yönelik bir çözüm, makul olarak yeterli olarak adlandırılan dile dahil edilmiştirproperty_exists .
Tartışmalı gerekçesiz kullanım örnekleri
3. register_globalsve küresel ad alanının diğer kirliliği
Bu register_globalsözellik, adları HTTP isteğinin yönleriyle (GET ve POST parametreleri ve çerezler) belirlenen global kapsama değişkenler ekledi. Bu, hata ayıklama ve güvensiz kodlara yol açabilir, bu nedenle PHP 4.2, Ağustos 2000'i piyasaya sürdüğü ve Mart 2012'de piyasaya sürülen PHP 5.4'te tamamen kaldırıldığı için varsayılan olarak devre dışı bırakılmıştır . Ancak, bazı sistemlerin bu özellik etkinken veya taklit edilmiş halde hala çalışıyor olması mümkündür. globalAnahtar kelime veya $GLOBALSdiziyi kullanarak genel ad alanını başka şekillerde "kirletmek" de mümkündür .
Öncelikle, register_globalskendisi beklenmedik bir üretmek için olası değildir nullGET, POST beri, değişken ve çerez değerleri her zaman (dizelerle olacak ''hala dönen truedan isset) ve oturumda değişkenler programcı kontrolü altında tamamen olmalıdır.
İkincisi, bir değişkenin değerle kirlenmesi null, ancak bu daha önceki bir başlatmanın üzerine yazıldığında bir sorundur. Başlatılmamış bir değişkenin "üzerine yazılması" nullancak iki durum arasında başka bir yerde kod ayrılması durumunda sorun yaratacaktır, bu yüzden bu olasılık tek başına böyle bir ayrım yapmaya karşı bir argüman .
4. get_defined_varsvecompact
Gibi PHP'de Birkaç nadiren kullanılan fonksiyonlar, get_defined_varsve compactbunlar bir dizide tuşları sanki değişken isimleri tedavi etme imkanı. Global değişkenler için, super-global dizi$GLOBALS benzer erişime izin verir ve daha yaygındır. İlgili erişim alanında bir değişken tanımlanmamışsa bu erişim yöntemleri farklı davranacaktır.
Bu mekanizmalardan birini kullanarak bir değişken kümesini dizi olarak ele almaya karar verdikten sonra, normal işlemlerde olduğu gibi aynı işlemleri gerçekleştirebilirsiniz. Sonuç olarak, bakınız 1.
Yalnızca bu işlevlerin nasıl davranmak üzere olduğunu tahmin etmek için var olan işlevsellik (örneğin, "tarafından döndürülen dizide bir anahtar 'foo' olacak get_defined_varsmı?") Gereksizdir, çünkü işlevi çalıştırabilir ve hiçbir kötü etki olmadan öğrenebilirsiniz.
4a. Değişken değişkenler ( $$foo)
Değişken kümesini ilişkilendirilebilir bir diziye dönüştüren işlevlerle tam olarak aynı olmasa da, "değişken değişkenleri" ("bu diğer değişkeni temel alan bir değişkene atama ") kullanan çoğu durumda bunun yerine ilişkilendirilebilir bir dizi kullanmak üzere değiştirilebilir ve değiştirilmelidir. .
Değişken adı, temel olarak, programcı tarafından bir değere verilen etikettir; çalışma zamanında belirlerseniz, bu gerçekten bir etiket değil, bazı anahtar / değer deposundaki anahtardır. Daha pratik olarak, bir dizi kullanmıyorsanız, sayma, yineleme vb. anahtar-değer deposu "dışında" bir değişkene sahip olmak da imkansız hale gelebilir, çünkü aşırı yazılabilir $$foo.
İlişkilendirilebilir dizi kullanacak şekilde değiştirildikten sonra kod, çözüm 1'e uygun olacaktır. Dolaylı nesne özelliği erişimi (ör. $foo->$property_name) Çözüm 2 ile ele alınabilir.
5. yazmak issetçok daha kolayarray_key_exists
Bunun gerçekten alakalı olduğundan emin değilim, ancak evet, PHP'nin işlev adları oldukça uzun soluklu ve bazen tutarsız olabilir. Görünüşe göre, PHP'nin tarih öncesi sürümleri bir işlev adının uzunluğunu karma anahtarı olarak kullandı, bu yüzden Rasmus, htmlspecialcharsalışılmadık sayıda karaktere sahip olacakları gibi işlev adlarını kasten oluşturdu ...
Yine de, en azından Java yazmıyoruz, değil mi? ;)
6. Başlatılmamış değişkenlerin bir türü vardır
Değişken temelleri üzerinde manuel sayfa , şu ifadeye yer:
Başlatılmamış değişkenler, kullanıldıkları bağlama göre türlerinde varsayılan bir değere sahiptir
Zend Engine'de "başlatılmamış ancak bilinen tip" konusunda bir fikir olup olmadığından ya da bu ifadenin çok fazla okunup okunmadığından emin değilim.
Açık olan şey, bu sayfada başlatılmamış değişkenler için o sayfada açıklanan davranışlar, değeri olan bir değişkenin davranışı ile aynı olduğundan, davranışlarında pratik bir fark yaratmadığıdır null. Bir örnek almak için, her iki $ave $bbu kod tamsayı olarak sona erecek 42:
unset($a);
$a += 42;
$b = null;
$b += 42;
(Birincisi, daha iyi kod yazmanızı sağlamak için bildirilmemiş bir değişken hakkında bir bildirim oluşturur, ancak kodun gerçekte nasıl çalıştığı konusunda herhangi bir fark yaratmaz.)
99. Bir fonksiyonun çalışıp çalışmadığını algılama
(Bunu son olarak tutmak, diğerlerinden daha uzun olduğu için. Belki daha sonra düzenleyeceğim ...)
Aşağıdaki kodu göz önünde bulundurun:
$test_value = 'hello';
foreach ( $list_of_things as $thing ) {
if ( some_test($thing, $test_value) ) {
$result = some_function($thing);
}
}
if ( isset($result) ) {
echo 'The test passed at least once!';
}
Eğer some_functiondönebilirsiniz null, bu ihtimalin var echoolsa bile ulaşmış olmayacak some_testdöndü true. Programlayıcının amacı, daha $resultönce hiç ayarlanmadığı zamanı tespit etmekti , ancak PHP bunu yapmalarına izin vermiyor.
Ancak, bu yaklaşımla ilgili bir dış döngü eklerseniz ortaya çıkan başka sorunlar vardır:
foreach ( $list_of_tests as $test_value ) {
// something's missing here...
foreach ( $list_of_things as $thing ) {
if ( some_test($thing, $test_value) ) {
$result = some_function($thing);
}
}
if ( isset($result) ) {
echo 'The test passed at least once!';
}
}
Çünkü $resultaçıkça hiçbir zaman başlatıldı ilk testi geçerken, daha sonraki testler geçti olsun ya da olmasın imkansız anlatmak için yapım bir değeri alacaktır. Bu, değişkenler düzgün bir şekilde başlatılmadığında son derece yaygın bir hatadır.
Bunu düzeltmek için, bir şeyin eksik olduğunu yorumladığım satırda bir şeyler yapmamız gerekiyor. En belirgin çözüm, asla geri dönemeyecek $resultbir "terminal değerine" ayarlamaktır some_function; bu ise null, kodun geri kalanı iyi çalışır. some_functionSon derece öngörülemeyen bir dönüş türü (muhtemelen kendi içinde kötü bir işarettir) olduğu için bir terminal değeri için doğal bir aday yoksa, $foundbunun yerine ek bir boolean değeri, örneğin kullanılabilir.
Düşünce deneyi tek: very_nullsabiti
PHP teorik nullolarak burada bir terminal değeri olarak kullanılmak üzere özel bir sabit - yanı sıra - sağlayabilir ; muhtemelen, bunu bir işlevden döndürmek yasadışı olurdu, ya da buna zorlanacaktı nullve muhtemelen bir işlev argümanı olarak iletmek için de geçerli olurdu. Bu, çok özel bir durumu biraz daha basit hale getirir, ancak kodu yeniden faktörlendirmeye karar verdiğinizde - örneğin, iç döngüyü ayrı bir işleve koymak için - işe yaramaz hale gelir. Eğer sabit fonksiyonlar arasında geçirilebilseydi, some_functionbunun geri dönmeyeceğini garanti edemezdiniz, bu yüzden artık evrensel bir terminal değeri olarak kullanışlı olmazdı.
Bu durumda başlatılmamış değişkenleri algılama argümanı, bu özel sabitin argümanına dayanır: Yorumu değiştirir unset($result)ve farklı bir şekilde ele $result = nullalırsanız, $resultbunun için bir "değer" girersiniz ve yalnızca belirli yerleşik işlevler tarafından algılanır.
İkinci deney deneyi: ödev sayacı
Sonuncunun ne istediğini düşünmenin bir başka yolu ifda "bir şey atadı mı $result?" Özel bir değer $resultolduğunu düşünmektense, bunu değişkenle ilgili "meta veri" olarak düşünebilirsin, biraz Perl'in "değişken renklendirme" gibi. Yani yerine issetsen diyebilir has_been_assigned_tove yerine unset, reset_assignment_state.
Ama öyleyse, neden bir boole'de duruyorsunuz? Testin kaç kez geçtiğini bilmek istiyorsanız ; meta verilerinizi bir tam sayıya genişletebilir get_assignment_countve reset_assignment_count...
Açıkçası, böyle bir özellik eklemek, dilin karmaşıklığı ve performansında bir değişime sahip olacaktır, bu nedenle beklenen kullanışlılığına dikkatlice tartılması gerekir. Bir very_nullsabitte olduğu gibi, sadece çok dar koşullarda yararlı olacaktır ve yeniden faktoringe benzer şekilde dirençli olacaktır.
Umarım açık olan soru, PHP çalışma zamanı motorunun neden normal kodu kullanarak açıkça yapmanıza izin vermek yerine bu tür şeyleri takip etmek istediğinizi önceden varsayması gerektiğidir.