Ç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 isset
için bireyin tepki null
mantı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 unset
ve isset
bunlar 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_exists
dizinin 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 null
değ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
, protected
veyaprivate
).
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_globals
ve 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. global
Anahtar kelime veya $GLOBALS
diziyi kullanarak genel ad alanını başka şekillerde "kirletmek" de mümkündür .
Öncelikle, register_globals
kendisi beklenmedik bir üretmek için olası değildir null
GET, POST beri, değişken ve çerez değerleri her zaman (dizelerle olacak ''
hala dönen true
dan 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ı" null
ancak 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_vars
vecompact
Gibi PHP'de Birkaç nadiren kullanılan fonksiyonlar, get_defined_vars
ve compact
bunlar 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_vars
mı?") 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, htmlspecialchars
alışı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 $a
ve $b
bu 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_function
dönebilirsiniz null
, bu ihtimalin var echo
olsa bile ulaşmış olmayacak some_test
dö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ü $result
açı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 $result
bir "terminal değerine" ayarlamaktır some_function
; bu ise null
, kodun geri kalanı iyi çalışır. some_function
Son 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, $found
bunun yerine ek bir boolean değeri, örneğin kullanılabilir.
Düşünce deneyi tek: very_null
sabiti
PHP teorik null
olarak 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ı null
ve 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_function
bunun 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 = null
alırsanız, $result
bunun 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 if
da "bir şey atadı mı $result
?" Özel bir değer $result
olduğunu düşünmektense, bunu değişkenle ilgili "meta veri" olarak düşünebilirsin, biraz Perl'in "değişken renklendirme" gibi. Yani yerine isset
sen diyebilir has_been_assigned_to
ve 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_count
ve 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_null
sabitte 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.