PHP5'ta, ben İstisnalar veya trigger_error / set_error_handler kullanmalıyım?

9 Cevap php

Iki şekilde yapmanın artıları / eksileri nelerdir. One Doğru (tm) var mı?

9 Cevap

Eğer tüm uygulama için istisnalar yerine hatalarını kullanmak istiyorsanız, ErrorException ile bunu yapabilir ve bir özel hata işleyicisi (bir örnek hata işleyicisi için ErrorException sayfasına bakınız). Bu yöntemin tek dezavantajı ölümcül olmayan hatalar hala yakalanamadı sürece her zaman ölümcül olan durumlar, atmak olacaktır. Lütfen error_reporting ayarları bunları bastırmak yoksa Temelde, hatta bir E_NOTICE tüm uygulamayı durduracak.

Benim düşünceme göre, ErrorException kullanarak çeşitli faydaları vardır:

  1. Bir özel durum işleyicisi set_exception_handler kullanarak, hatta hataları, güzel mesajlar görüntüleyebilir.
  2. Bu herhangi bir şekilde varolan kodu bozmayan ... trigger_error ve diğer hata fonksiyonları hala normal çalışacaktır.
  3. Bu gerçekten zor E_NOTICE s ve E_WARNING s tetikleyebilir aptalca kodlama hataları görmezden yapar.
  4. Sen try / catch @ hata kullanarak önlemek için güzel bir yoldur bir PHP hatası (sadece istisnalar) oluşturabilir sarma kodu kullanabilirsiniz bastırma hack:

    try {
        $foo = $_GET['foo'];
    } catch (ErrorException $e) {
        $foo = NULL;
    }
    
  5. Eğer yakalanmamış bir hata olduğunda kullanıcılara bir dostu mesajı görüntülemek istiyorsanız tek bir try / catch bloğunda tüm komut sarın. (Sadece yakalanmamış hataları ve istisnalar oturum çünkü, dikkatli yapın.)

Siz "Olağanüstü durumlar" özel durumlar kullanmak gerektiğini bir nedenle doFoo bu işi yapamaz ise () Eğer, bunu gerçekleştirmek için beklemek gereken bir yöntem doFoo çağırdığınızda o bir istisna yükseltmek gerektiğidir.

Eski php kod bir sürü hatası oluştu zaman yanlış veya boş dönen yaklaşım alacaktı, ancak bu zor şeyleri ayıklama yapar, istisnalar bu hata ayıklama çok daha kolay.

Örneğin size bu yöntemi çağrılırsa, Dogfood nesneler dizisi döndü ve bir şey nasıl arama kodu bir hata vardı, çünkü boş döndü olmadığını söylemek mümkün olacak yanlış gittiğinde null döndürür getDogFood denilen bir yöntem () vardı ki veya köpek maması kullanılabilir sadece orada?

PHP'nin dahili hata günlüğü kullanmak, eski kod kütüphaneleri ile ilgilenen ilgili olarak, size daha sonra rethrow genel Exception kullanabilirsiniz set_error_handler () fonksiyonu ile hata günlüğünü kılabilirsiniz.

Şimdi, onlarla ne karar için ücretsiz kod detaylı durumlar atma hepsi var ki, senin kodun bazı yerlerinde onları yakalamak isteyen ve alternatif yöntemler deneyin ya da kendi günlük işlevlerini kullanarak giriş yapabilirsiniz hangi Bir veritabanı, dosya, e-log olabilir - hangisi tercih. Kısacası - İstisnalar daha esnektir.

Ben özel durumlar kullanma fikrini seviyorum, ama genellikle üçüncü parti kütüphaneler yer var ve onlar istisnaları kullanmak istemiyorsanız o zaman bir sorun için 3-4 farklı yaklaşımlar ile sonuna kadar! Zend istisnalar kullanır. CakePHP özel hata işleyicisi kullanır, ve en PEAR kütüphaneleri PEAR :: Hata nesnesini kullanın.

Ben ki, bu konuda tek doğru yolu var OLDU. Özel hata işleyicileri rota muhtemelen bu durumun en çok esnektir. Sadece kendi kodunu kullanarak, ya da bunları kullanmak kütüphaneleri kullanılarak ya eğer İstisnalar olsa harika bir fikir vardır.

Ne yazık ki PHP dünyada biz hala PHP4 ölmek reddetmesi acı çekiyorsun, bu yüzden herkes hala hem 4'e çalışmak mümkün şeyleri yazarken onlar en iyi uygulamayı temsil olurken istisnalar gibi şeyler, yakalamak için son derece yavaş olmuştur ve 5.. yapar zaman, biz 6 yerine 5 arasında gerginlikler olacak olsa Umarım bu fiyaskosu artık sona eriyor ...

/ Beni elinde kafasını tutuyor ...

Açıkçası, hiçbir "One Doğru" var, ama bu bir görüş çok sayıda var. ;)

Şahsen ben size giriş almak istiyorum istisnalar yapamayacağı şeyleri, yani bildirimler ve uyarılar (yani malzeme için trigger_error kullanmak, ancak bazı düzeyde onları yakalamak bile (hatalar / istisnalar yapmak aynı şekilde uygulamanın akışını durdurmak değil )).

Ben de çoğunlukla (durum oluşur hangi yöntemin çağırana) non-geri kazanılabilir olduğu varsayılır koşulları için özel durumlar kullanmak, ciddi hatalar yani. O olmayan bir kıvrık şekilde mümkün olmadığını, aynı anlamı ile bir değer döndüren bir alternatif olarak özel durumlar kullanmak yok. Ben bir arama yöntemi oluşturmak eğer yerine bir EntityNotFoundException (veya eşdeğer) atma arıyordu neyse bulamadık Örneğin, ben genellikle boş bir değer döndürür.

Yani başparmak benim kural şudur:

  • Sürece bir şey bulmak değil, makul bir sonuç, ben çok daha kolay bir try-catch-madde kullanarak işleme daha geri dönen ve boş değerler (veya başka bir varsayılan değer) kontrol bulabilirsiniz.
  • Öte yandan, bu kurtarmak için arayanın kapsamında değil ciddi bir hata bulmak değil, eğer, ben hala bir istisna atmak istiyorum.

(Hataları tetikleme aksine) ikinci durumda istisnalar atmak için nedeni, istisnalar düzgün adlandırılmış İstisna alt sınıflarını kullanmak düşünülürse, çok daha anlamlı olmasıdır. Ben istisnalar kullanmak için ne karar verirken PHP'nin Standard Kütüphane'nin istisnaları kullanarak iyi bir başlangıç ​​noktası olduğunu bulmak: http://www.php.net/~helly/php/ext/spl/classException.html

Ancak, daha fazla anlamsal belirli durum için doğru durumlar almak için onları genişletmek isteyebilirsiniz.

Bu duruma bağlıdır. Ben Validator ait ve bu tür şeyler için iş mantığı / uygulama iç bölümü yazma, ve trigger_error olduğumda İstisnalar kullanma eğiliminde.

Mantık düzeyinde İstisnaları kullanarak pro adlı uygulama böyle bir hata durumunda yapmak için izin vermektir. Sen uygulama yerine iş mantığı olan seçti izin hatayı sunmak için biliyorum.

Validator ait ve doğanın şeyleri trigger_error kullanarak yanlısı, diyelim ki, vardır

try {
    $user->login();
}  catch (AuthenticationFailureException $e) {
    set_error_handler("my_login_form_handler");
    trigger_error("User could not be logged in. Please check username and password and try again!");
} catch (PersistenceException $pe) { // database unavailable
    set_error_handler("my_login_form_handler"); 
    trigger_error("Internal system error. Please contact the administrator.");
}

nerede my_login_form_handler pretties kadar dize ve giriş formu üzerinde görünür bir alanda eleman yerleştirir.

Istisna fikri zarif ve hata işleme süreci o kadar pürüzsüz yapar. Eğer uygun istisna sınıfları var ve takım geliştirme, daha önemli bir şey "standart" istisnalar olduğunda ama bu geçerlidir. İstisnaları kullanmayı planlıyorsanız, bu yüzden daha iyi ilk istisna tiplerini standart ediyorum, ya da daha iyi bir seçim bazı popüler çerçevesinde istisnalar kullanmaktır. PHP (Eğer yapısal kodu ile birleştirilmiş kod nesne oryenterde yazabilirsiniz) için geçerlidir başka bir şey olduğunu size sınıfları kullanarak bütün uygulama yazıyorsanız. Eğer odaklı nesne yazıyorsanız, o zaman istisnalar kesin iyidir. Sonuçta ben hata işleme süreci trigger_error ve şeyler daha haricinde çok daha yumuşak olacağını düşünüyorum.

Intro

Benim kişisel deneyim, genel bir kural olarak, ben yerine trigger_error benim kod İstisnalar kullanmayı tercih. İstisnalar kullanarak hataları tetikleme daha esnek olduğu için bu esas olarak. Ve, IMHO, bu da kendim için 3. parti geliştirici olarak değil sadece faydalıdır.

  1. Ben Exception sınıfını genişletmek (veya istisna kodları kullanın) açıkça benim kütüphane durumlarını ayırt etmek olabilir. Bu işleme kodu ve hata ayıklama beni ve 3. parti geliştiriciler yardımcı olur. This also exposes where and why it can fail kaynak kodu tarama için gerek kalmadan.
  2. Ben etkili script yürütülmesine durdurma olmadan benim Kütüphanesi yürütülmesini durduramaz.
  3. 3. parti geliştirici kutu zincir benim İstisnalar hata ayıklama için çok yararlıdır (PHP> 5.3. *) Ve benim kütüphane nedeniyle farklı sebeplerden dolayı başarısız olabilir taşıma durumlarda kullanışlı olabilir.

Ve ben o benim kütüphane başarısızlıklarla başa nasıl empoze olmadan tüm bu yapabilirsiniz. (Örn: Karmaşık hata işlevleri oluşturma). O bir try catch bloğu kullanmak ya da sadece bir genel durum işleyici kullanabilirsiniz

Note:

Bu noktaların bazıları, özünde, trigger_error için de uygulamak için biraz daha karmaşık geçerlidir. Deneyin catch blokları kullanımı gerçekten çok kolay ve çok kod dostu vardır.


Example

Ben bu bakış açımı göstermek olabilecek bir örnek olduğunu düşünüyorum:

class HTMLParser {
    protected $doc;
    protected $source = null;
    public $parsedHtml;
    protected $parseErrors = array();
    public function __construct($doc) {
        if (!$doc instanceof DOMDocument) {
            // My Object is unusable without a valid DOMDOcument object
            // so I throw a CriticalException
            throw new CriticalException("Could not create Object Foo. You must pass a valid DOMDOcument object as parameter in the constructor");
        }
        $this->doc = $doc;
    }

    public function setSource($source) {
        if (!is_string($source)) {
            // I expect $source to be a string but was passed something else so I throw an exception
            throw new InvalidArgumentException("I expected a string but got " . gettype($source) . " instead");
        }
        $this->source = trim($source);
        return $this;
    }

    public function parse() {
        if (is_null($this->source) || $this->source == '') {
            throw new EmptyStringException("Source is empty");
        }
        libxml_use_internal_errors(true);
        $this->doc->loadHTML($this->source);
        $this->parsedHtml = $this->doc->saveHTML();
        $errors = libxml_get_errors();
        if (count($errors) > 0) {
            $this->parseErrors = $errors;
            throw new HtmlParsingException($errors[0]->message,$errors[0]->code,null,
                $errors[0]->level,$errors[0]->column,$errors[0]->file,$errors[0]->line);
        }
        return $this;
    }

    public function getParseErrors() {
        return $this->parseErrors;
    }

    public function getDOMObj() {
        return clone $this->doc;
    }
}

Explanation

Içinde olmadan benim kütüphane hiç çalışmaz çünkü constructor Ben bir CriticalException if the param passed is not of type DOMDocument atmak.

(Not: Ben sadece __construct(DOMDocument $doc) yazabilirsiniz ama bu sadece bir örnektir).

In setsource() method I throw a InvalidArgumentException if the param passed is something other than a string. I prefer to halt the library execution here because source property benim sınıf temel bir özelliğidir ve geçersiz bir değer benim kütüphanede boyunca hatayı yaymak olacaktır.

parse() method is usually the last method invoked in the cycle. Even though I throw a XmlParsingException libxml'e bozuk bir belge bulursa, ayrıştırma tamamlanan ilk ve (bir ölçüde) sonuçları kullanilabilir.


Handling the example library

İşte bu kadar yapılmış kütüphane nasıl başa bir örnek:

$source = file_get_contents('http://www.somehost.com/some_page.html');
try {
    $parser = new HTMLParser(new DOMDocument());
    $parser->setSource($source)
           ->parse();
} catch (CriticalException $e) {
    // Library failed miserably, no recover is possible for it.
    // In this case, it's prorably my fault because I didn't pass
    // a DOMDocument object.
    print 'Sorry. I made a mistake. Please send me feedback!';
} catch (InvalidArgumentException $e) {
    // the source passed is not a string, again probably my fault.
    // But I have a working parser object. 
    // Maybe I can try again by typecasting the argument to string
    var_dump($parser);
} catch (EmptyStringException $e) {
    // The source string was empty. Maybe there was an error
    // retrieving the HTML? Maybe the remote server is down?
    // Maybe the website does not exist anymore? In this case,
    // it isn't my fault it failed. Maybe I can use a cached
    // version?
    var_dump($parser);
} catch (HtmlParsingException $e) {
    // The html suplied is malformed. I got it from the interwebs
    // so it's not my fault. I can use $e or getParseErrors() 
    // to see if the html (and DOM Object) is usable
    // I also have a full functioning HTMLParser Object and can
    // retrieve a "loaded" functioning DOMDocument Object
    var_dump($parser->getParseErrors());
    var_dump($parser->getDOMObj());
}
$var = 'this will print wether an exception was previously thrown or not';
print $var;

Sen daha bu almak ve yuva try catch blokları, zincir istisnalar, vb kararlı bir istisna zinciri yolu, seçici günlüğü, aşağıdaki çalıştırın seçici kod .. olabilir

Bir yan not olarak, İstisnalar kullanarak PROGRAM yürütme durdurmak anlamına gelmez, sadece benim nesnenin bağlı kod bypass edilmesi anlamına gelir. Onun istediği gibi onunla yapmak için bana veya 3. parti geliştirici kalmış.

İstisnalar bir hata durumunu / istisnai bir durum sinyal modern ve sağlam yoldur. Onları kullanın :)

Using exceptions are not a good idea in the era of 3rd party application integration .

Eğer başka bir şey, ya sizinki ile başkasının uygulaması ile app entegre etmeye an, tüm uygulama anı bir durma noktasına gelecek, çünkü bazı 3. parti eklenti bir sınıfı, bir istisna atar. Eğer tam teşekküllü hata kaldırmaz olsa bile, kendi app uygulanan günlüğü, bir 3. parti eklenti birinin rasgele nesne bir istisna atar, ve tüm uygulama orada duracaktır.

EVEN if you have the means in your application to make up for the error of that library you are using ....

Hybridauth, arada - örnek bir vaka sosyal giriş sağlayıcı bir hata döndürdü, ve gereksiz tüm app öldürür çünkü bir istisna atar bir 3. parti sosyal giriş kitaplık olabilir. Yani, Orada bütün bir uygulaması var, ve orada sizin için ek işlevsellik getiren bir kütüphane var - bu durumda, sosyal oturum açma - ve durumda dönüş bir sürü şey var olsa bile, bir sağlayıcı (kendi kimliğini değil giriş sistemi, artı 20 ya da öylesine diğer sosyal giriş sağlayıcılar) gibi, tüm uygulama bir taşlama durma noktasına gelecektir. Ve bu sorunları çözmek için 3. parti kitaplığı değiştirmek zorunda sona erecek ve gelişimini hızlandırmak için bir 3. parti kitaplığı kullanarak nokta kaybolur.

Bu PHP işleme hataları felsefesi açısından ciddi bir tasarım kusurdur. Bugün geliştirilen uygulamaların çoğu diğer ucunda altında bir kullanıcı var - o yüz sağlar. Bir intranet kullanıcı olun, bu bir sistem yöneticisi olmak, internet üzerinden bir kullanıcı olabilir, bu önemli değil - bir kullanıcı genellikle yoktur.

Ve, bir uygulama geri bir önceki sayfaya gitmek ve yapmak için çalışıyoruz ne ilişkin karanlıkta bir çekim var daha başka bu noktada yapabileceğim bir şey var olmadan yüzünüze ölmek sahip bir kullanıcı olarak, kötü, geliştirme tarafında kötü bir uygulamadır. Sadece geliştiriciler nedeniyle bir kullanıcının yüzünde atılan (kullanılabilirlik güvenliğe) birçok nedenden bilmek gereken bir iç hata cabası.

Sonuç olarak, sadece belirli bir 3. parti kitaplığı (bu durumda hybridauth) gitmesine değil, sadece bu nedenle, benim uygulamada kullanmak izin vermek zorunda olacak im. Rağmen bu hybridauth çok iyi bir kütüphane, ve görünüşte iyi çaba yetenekleri phletora ile, bunun üzerine harcanmıştır.

Bu nedenle, kodunuzu istisnaları kullanmaktan kaçınmalıdır. Eğer şu anda yapıyorsun kod, uygulama çalıştırmak ve bir kütüphane, bu diğer projelerinde kod tamamını veya bir kısmını eklemek istediğiniz olasıdır, veya parçaları entegre olacak üst düzey kodu BİLE sizin veya başka bir kod veya 3. parti kod ile bunu bütünlüğü. Eğer bir kod parçası sağlar ne sorunu işlemek için uygun araçlara sahip olsa bile yüzünüzde ölen bütün uygulamalar / entegrasyonları - İstisnaları kullanıldığında Ve eğer aynı durum ile sona erecek.