PHP kodumda assert kullanmalı mıyım?


87

Bir iş arkadaşım, bir if ifadesi kullanıp bir istisna attığım yerlerde kütüphanelerimize birkaç kez assert komutunu ekledi . (Bundan önce iddia bile duymamıştım.) İşte onu nasıl kullandığına dair bir örnek:

assert('isset($this->records); /* Records must be set before this is called. */');

Yapardım:

if (!isset($this->records)) {
    throw new Exception('Records must be set before this is called');
}

Assert üzerindeki PHP belgelerini okurken , assert'in etkin olduğundan emin olmanız ve assert'i kullanmadan önce bir eylemci eklemeniz tavsiye ediliyor. Bunu yaptığı bir yer bulamıyorum.

Öyleyse, sorum şu, yukarıda verilen iyi bir fikir iddia kullanmak ve bunu if ve istisnalar yerine daha sık mı kullanmalıyım?

Başka bir not, bu kitaplıkları, parçası olmadığımız projeler de dahil olmak üzere çeşitli projelerde ve sunucularda kullanmayı planlıyoruz (kitaplıklar açık kaynaklıdır). Bu, assert kullanımında herhangi bir fark yaratır mı?


Gerçekten mi 'isset(kod satırı ile assert)? Sadece değil isset(tek alıntı olmadan ')?
Peter Mortensen

Yanıtlar:


79

Çoğu dilde geçerli olan temel kural (belirsiz bir şekilde bildiğim tek şey), assertbir koşulun her zaman doğru olduğunu iddia etmek için kullanılırken if, bazen başarısız olacağı düşünülebiliyorsa, uygun olduğu şeklindedir.

Bu durumda, assertbunun uygun olduğunu söyleyebilirim (durum hakkındaki zayıf anlayışıma dayanarak) çünkü recordsher zaman verilen yöntem çağrılmadan önce ayarlanmalıdır. Dolayısıyla, kaydın ayarlanamaması, bir çalışma zamanı koşulundan ziyade programdaki bir hata olacaktır. Burada, assertile korunan kodun ayarlanmadan assertçağrılmasına neden olabilecek olası bir program yürütme yolunun bulunmamasını (yeterli test ile) sağlamaya yardımcı olur records.

Kullanmanın avantajı assertolarak karşı ifyani assertgenel olarak üretim kodu, böylece genel azaltmada kapatılabilir. En iyi şekilde ele alınabilecek türden durumlar, ifüretim sistemindeki çalışma süresi sırasında olasılıkla ortaya çıkabilir ve bu nedenle, onları kapatamamaktan dolayı hiçbir şey kaybolmaz.


4
Buna ek olarak, üretim kodunuzdaki iddiaları devre dışı bırakmak istemeyebilirsiniz, çünkü bu "bu asla olmamalı" koşullarının bu şekilde kalmasını sağlamaya yardımcı olurlar. Kullanıcılarınızın var olmaması gereken bir yürütme yolunda ilerlemesine izin vermektense uygulamanızın bir iddiayı durdurmasına izin vermek daha iyi olabilir.
derekerdmann

2
@derekerdmann: Doğru. Bazı iddialar için bunları günlüğe kaydetmek (üretimde) veya uyarıyı yazdırmak (geliştirme ortamında) yeterli olabilir. Ancak çoğu zaman güvenlikle ilgili kodu koruduğunu iddia ettiğinden, etkinleştirebilirsiniz assert_options(ASSERT_BAIL). Yine de manuel if / throw geçici çözümlerinden daha hızlıdır.
mario

4
@derekerdmann Buna katılmıyorum (php'de assert () kullanma bağlamında). Assert () tüm dize argümanlarını PHP kodu olarak ele aldığı için bu büyük bir güvenlik açığı açığıdır, dolayısıyla (teorik olarak) isteğe bağlı kod enjekte etmek ve çalıştırmak mümkündür. IMHO, iddialar üretim sırasında kapatılmalı
Vitaliy Lebedev

2
@VitaliyLebedev, enjeksiyona duyarlı olmak istemiyorsanız, iddia etmek için dizeleri geçmeyin.
Damon Snyder

9
Partiye geç kaldı ama PHP.net şunu söylüyor: "İddialar yalnızca hata ayıklama özelliği olarak kullanılmalıdır."
Koen.

25

İddiaları "güçlü yorumlar" olarak düşünün. Şunun gibi bir yorumdan ziyade:

// Note to developers: the parameter "a" should always be a number!!!

kullanım:

assert('is_numeric(a) /* The parameter "a" should always be a number. */');

Anlamları tamamen aynıdır ve aynı hedef kitleye yöneliktir, ancak ilk yorum kolayca unutulur veya yok sayılır (kaç ünlem işareti olursa olsun), "güç yorumu" yalnızca insanların okuyup anlaması için mevcut değildir, aynı zamanda geliştirme sırasında sürekli olarak makine tarafından test edilir ve kodda ve çalışma alışkanlıklarında iyi bir iddia yönetimi kurarsanız göz ardı edilmeyecektir.

Bu şekilde görüldüğünde, iddialar if (hata) ve istisnalardan tamamen farklı bir kavramdır ve birlikte var olabilirler.

Evet, kodunuza yorum yazmalısınız ve evet, mümkün olduğunca "güçlü yorumlar" (iddialar) kullanmalısınız.


peki ya geliştirme aşamasında, iddiaya her zaman iyi koşul verirseniz, ancak üretimde iddia kapatılırsa - bazı kullanıcılar test ederken düşünmediğiniz başka bir koşulu geçerse? Ya da her zaman açık kalmanız gerekir, ancak bu, kendi çekinizi yazmakla aynı şey değil mi?
Dariux

O zaman programınız başarısız olur. Bunu, if ifadeleri ve dilinizin ve geliştirme ortamınızın hata işleme özellikleriyle doğru şekilde düzeltin. iddialar sorunları ortaya çıkarabilir, sorunları çözmenin daha iyi yolları vardır.
DaveWalley

PHP 7.2'den itibaren değerlendirme için assert'e bir dizge geçirmenin kullanımdan kaldırıldığını unutmayın. Üzücü, çünkü oldukça kullanışlı görünüyordu.
Jannie Theunissen

16

Tamamen geliştirme stratejinize bağlıdır. Çoğu geliştirici, assert()aşağı akış birim testinin farkında değildir ve bunu kullanır. Ancak proaktif ve yerleşik test planları bazen avantajlı olabilir.

assert kullanışlıdır, çünkü etkinleştirilip devre dışı bırakılabilir. Böyle bir iddia işleyicisi tanımlanmamışsa performansı düşürmez. Meslektaşınızın bir tane yok ve geliştirme ortamında geçici olarak etkinleştiren bazı kodlar geliştirmelisiniz (E_NOTICE / E_WARNINGs açıksa, iddia işleyicisi de olmalıdır). Bazen kodumun karışık değişken türlerini sindiremediği durumlarda kullanıyorum - normalde zayıf yazılmış bir PHP'de katı yazım yapmam, ancak rastgele kullanım durumları var:

 function xyz($a, $b) {
     assert(is_string($a));
     assert(is_array($b));

Örneğin, tür belirleyicilerin eksikliğini telafi edecek string $a, array $b. PHP5.4 onları destekler, ancak kontrol etmez.


"Php 5.4 bunlara sahip olacak ama kontrol etmeyecek" ne anlama geliyor?
Kzqai

1
PHP 5.4 iddialara sahiptir, destekler ve denetler.
DaveWalley

7

Assert, ifyalnızca geliştirme sırasında hata ayıklama için kullanılması amaçlandığından, normal akış denetimi gibi veya istisnaların yerine geçmez .


6

7'den önceki PHP'de assert ile ilgili önemli bir not. Assert yapısına sahip diğer dillerin aksine, PHP assert ifadelerini tamamen atmaz - bunu bir işlev olarak ele alır (bir iddia tarafından çağrılan bir işlevde bir debug_backtrace () yapın). İddiaları kapatmak, işlevi motorda hiçbir şey yapmamaya yönlendiriyor gibi görünüyor. PHP 7'nin zend.assertions'ı 1 (açık) veya -1 (kapalı) gibi daha normal değerler yerine 0 olarak ayarlayarak bu davranışı taklit etmek için yapılabileceğini unutmayın.

Sorun, o assert'in herhangi bir argüman almasından kaynaklanır - ancak argüman bir dizge değilse o zaman assert, assert'in açık veya kapalı olmasına bakılmaksızın ifadenin sonuçlarını alır. Bunu aşağıdaki kod bloğu ile doğrulayabilirsiniz.

<?php
  function foo($a) { 
    echo $a . "\n"; 
    return TRUE;
  }
  assert_options(ASSERT_ACTIVE, FALSE);

  assert( foo('You will see me.'));
  assert('foo(\'You will not see me.\')');

  assert_options(ASSERT_ACTIVE, TRUE);

  assert( foo('Now you will see'));
  assert('foo(\'both of us.\')');

Bunun bir hata olduğunu iddia etmenin amacı göz önüne alındığında ve assert PHP 4'te tanıtıldığından beri dilde olduğu için uzun süredir devam eden bir hata.

İddia etmek için aktarılan dizeler, bununla birlikte gelen tüm performans etkileri ve tehlikeleriyle birlikte değerlendirilir, ancak assert ifadelerinin PHP'de olması gerektiği gibi çalışmasını sağlamanın tek yolu budur (Bu davranış PHP 7.2'de kaldırılmıştır).

DÜZENLEME: Yukarıda PHP 7 ve 7.2'deki değişiklikleri not etmek için değiştirildi


1
PHP 7'de zend.assertionstamamen kapatılacak ini ayarı vardır / olacaktır assert().
Kontrollfreak

Bu harika bir haber - ancak oradaki belgelere göre, PHPUnit'e bir yama gibi görünüyor, PHP 5.x altında iddialar başarısız olduğunda AssertionException'ı atmak için bir assert callback işleyicisi ekliyor. Bu şekilde Birim testleri, PHP 5.x veya 7 üzerinde çalışıp çalışmadıklarına bakılmaksızın @expectedException AssertionException açıklamasını kullanabilir.
Michael Morris

3

Assert, hata ayıklama için yararlı olduğu için yalnızca geliştirmede kullanılmalıdır. Yani isterseniz bunları web sitenizi geliştirmek için kullanabilirsiniz, ancak canlı bir web sitesi için istisnalar kullanmalısınız.


7
Ancak yine de kodda iddialar olacaktır. Sadece bir üretim ortamında aktif olmayacaklar.
aaronasterling

1
Onları üretimde tutar ve bunun yerine hata işleyicimi buna göre ayarlardım.
Daniel W.

3

Hayır, iş arkadaşınız bunu genel amaçlı bir hata işleyici olarak kullanmamalıdır. Kılavuza göre:

İddialar yalnızca hata ayıklama özelliği olarak kullanılmalıdır. Bunları, her zaman DOĞRU olması gereken ve değilse bazı programlama hatalarını gösteren veya uzantı işlevleri veya belirli sistem sınırları ve özellikleri gibi belirli özelliklerin varlığını kontrol eden sağlık kontrolleri için kullanabilirsiniz.

Giriş parametresi kontrolleri gibi normal çalışma zamanı işlemleri için onaylar kullanılmamalıdır. Genel bir kural olarak, onaylama denetimi etkinleştirilmediyse kodunuz her zaman doğru çalışabilmelidir.

Otomatikleştirilmiş test takımlarına aşina iseniz, "assert" fiili genellikle bazı yöntem veya işlevlerin çıktısını doğrulamak için kullanılır. Örneğin:

function add($a, $b) {
    return $a + $b;
}

assert(add(2,2) == 5, 'Two and two is four, dummy!');
assert(is_numeric(add(2,2)), 'Output of this function to only return numeric values.');

İş arkadaşınız bunu genel amaçlı bir hata işleyici ve bu durumda bir girdi kontrolü olarak kullanmamalıdır. Kayıtlar alanının kitaplığınızdaki bazı kullanıcılar tarafından ayarlanmaması mümkün görünüyor.


3

İş arkadaşınız gerçekten Eyfel dilinden sözleşme yoluyla tasarım (DbC) uygulamaya çalışıyor ve şu kitabı temel alıyor: Nesne Yönelimli Yazılım Oluşturma, 2. Baskı.

İddia, kullandığı şekliyle, Hoare Mantığının {P} -bölümü veya Hoare Üçlü: {P} C {Q}, burada {P} önkoşuldur (ion) s ve {Q} son koşul iddia (iyon) s.

PHP'de hata içeren iddia özelliği hakkında verilen tavsiyeleri not alacağım. Buggy kodunu kullanmak istemezsiniz. Gerçekten istediğiniz şey, PHP'nin yapımcılarının assert'teki hatayı düzeltmesidir. Onlar yapana kadar, assert'i kullanabilirsiniz, ancak mevcut hatalı durumuna dikkat ederek kullanın.

Üstelik assert özelliği hatalıysa üretim kodunda kullanmamanızı öneririm. Yine de, uygun olduğunda geliştirme ve test kodunda kullanmanızı tavsiye ederim.

Son olarak - sözleşme yoluyla tasarım çalışması yaparsanız, Boolean iddiaları nesneye yönelik klasik kalıtım ışığında kullanmanın sonuçları olduğunu göreceksiniz - yani - bir ön koşulu asla zayıflatmamalı veya bir son koşulu zayıflatmamalısınız. Bunu yapmak, birbirleriyle etkileşime giren polimorfik alt nesneler için tehlikeli olabilir. Bunun ne anlama geldiğini anlayana kadar - onu yalnız bırakırım!

Dahası, PHP üreticilerinin sözleşme yoluyla kapsamlı bir tasarım çalışması yapmalarını ve bunu en kısa sürede PHP'ye koymalarını şiddetle tavsiye ederim! O zaman hepimiz, yanıtlarda (yukarıda) belirtilen sorunları ele alacak DbC'ye duyarlı bir derleyici / yorumlayıcıya sahip olmaktan faydalanabiliriz:

  1. Düzgün bir şekilde uygulanan sözleşmeye göre tasarıma duyarlı bir derleyici (umarız) hatasız olacaktır (mevcut PHP'nin iddia ettiği gibi).
  2. Düzgün bir şekilde uygulanmış, sözleşmeye dayalı tasarıma duyarlı bir derleyici, beyninizi konunun üzerine yıkmak yerine, polimorfik iddia mantığı yönetiminin nüanslarını sizin için halledecektir!

NOT: ifBir ön koşulu güçlendirmek veya bir son koşulu zayıflatmak için kullanılırsa, bir iddianın (ön koşul) yerine bir- ifadesini kullanmanız bile çok ciddi sonuçlara yol açacaktır. Bunun ne anlama geldiğini anlamak için, bilmek için sözleşmeye göre tasarım çalışmanız gerekecek! :-)

İyi eğitim ve öğrenim.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.