Magento'da kısırlaştırılmış tip ipucu ile uğraşmak


15

Sadece biri Magento'nun özel hata işleyicisi ile birlikte var olmak için tip kontrolü için düşündüğümden daha iyi stratejileri olup olmadığını merak. Özellikle, bir typehinted parametre uyuşmazlığı durumunda atılan bir "Catchable ölümcül hatalar" merak ediyorum. İşte Magesınıftan bir örnek :

/**
 * Write exception to log
 *
 * @param Exception $e
 */
public static function logException(Exception $e)
{
    if (!self::getConfig()) {
        return;
    }
    $file = self::getStoreConfig('dev/log/exception_file');
    self::log("\n" . $e->__toString(), Zend_Log::ERR, $file);
}

Hata işleyici nedeniyle, yönteme herhangi bir şey iletilebilir Zend_Date(bunlar iyi çalışır, ancak istisna günlüğünüzde süper kafa karıştırıcı görünür) veya Mage_Core_Model_Appaslında ölümcül bir hataya sahip olan a.

Bir yöntemin en üstünde tür denetimini yeniden uygulamak mümkündür: $e instanceof Exceptionancak bu tür taktikler bir yazım nesnesinin amacını bozar.

Herhangi ipuçları öneri?

Yanıtlar:


5

İyi soru +1

@Mpw ile ilk cevabımda yaptığım tartışmadan sonra iyi bir noktadan sonra araştırma ve testler yaptım. İlk seferinde kısmen yanlış anladım.

Açıklamak için bazı kodlar ekleyecek, böylece diğerleri sorunu daha iyi anlayacaktır.

Kalkıştan önce bir not

Bu ortaya çıkana kadar hiç bu kadar sorun yaşamadım. Magento'da geliştirici moduyla geliştirme, bunun hakkında bir saniye bile düşünmüyorum. Bu yüzden her osurduğumda ortaya çıkacak ve düzeltilecek.

Açıklayıcı bir örnekle ilgili sorun

Hatalı hata söyleme günlüğe kaydedilecek (etkinse) ve hiçbir hata atılmadığı mageCoreErrorHandlerveya programın yapılamayacağı için kod her zamanki gibi devam edecektir exit.

Yenilmez hatalar için ilk Magento'nun temel hata işleyicisi app/code/core/Mage/Core/functions.php

/**
 * Custom error handler
 *
 * @param integer $errno
 * @param string $errstr
 * @param string $errfile
 * @param integer $errline
 */
function mageCoreErrorHandler($errno, $errstr, $errfile, $errline){
    /**
     * Some internal logic here for building the error message
     */

    $errorMessage .= ": {$errstr}  in {$errfile} on line {$errline}";
    if (Mage::getIsDeveloperMode()) {
        throw new Exception($errorMessage);
    } else {
        Mage::log($errorMessage, Zend_Log::ERR);
    }
}

Gördüğünüz gibi, geliştirici modunda yararlı bir şey söyleyecek, bir hata atıyor. Kapatıldığında oturum açar (etkinse) ve devam eder.

Kanıt

Benim testfile.php

require 'app/Mage.php';
Mage::app('admin')->setUseSessionInUrl(false);

// Test function which expect Customer_Model_Customer
function test(Customer_Model_Customer $customer)
{
    var_dump('Do not show me because ' . get_class($customer) . ' is not a customer.');
}

// Enabled developer mode
Mage::setIsDeveloperMode(true);

// Put a var in here
$noGood = Mage::app();

// Make some context
var_dump('hello');
try {
    // Call test function with a not accepted var
    test($noGood);

    // Tell if we get here
    var_dump('And we are here!');

} catch (Exception $e) {
    var_dump('You should die, because I am doing something which I should not do');
}

Sonuç

Geliştirme modu etkin. Doğru sonuç

string(5) "hello"
string(66) "You should die, because I am doing something which I should not do"

Geliştirme modu devre dışı, Yanlış sonuç

string(5) "hello"
string(61) "Do not show me because Mage_Core_Model_App is not a customer."
string(16) "And we are here!"

Sonuçta hatayı atlayacak ve bir sonraki kod satırında devam edecektir. Belki de garip sonuçlarla. (@mpw'nin işaret ettiği gibi)

Sonuç

O olabilir birisi hataları gidecek şekilde gelişmektedir gerçekleşmesi farkedilmeden ve edecek sonunda beklenmedik sonuçlar verir.

Elbette profesyonel bir şekilde gelişirken. Hatalar olacak şekilde fark ve dikkat ödenir. Magento'da bunu önlemenin yolu, geliştirici / test ortamında geliştirme modunu her zaman etkinleştirmektir.

Bir değişkeni ikinci kez kontrol etmenin (en azından ben bunu nasıl tarif edeceğim) gitmenin yolu olduğu bu tartışma noktasına asla ulaşmamalıdır. Kod, üretim ortamlarında yayınlanmadan önce test edilmelidir. O gerektiğini değil ihtiyaç.

Düşüne taşına verilen kararlar

Belki de Magento ölümcül bir hatadan sonra durmalıdır. Veya bir rapor oluşturun ve ziyaretçiye gösterin. Bu şekilde sonraki kod satırları hiçbir zaman yürütülmez ve bazı şeyler fark edilir.


> Profesyonel bir şekilde gelişirken kaba. Hatalar fark edilir ve dikkat edilir. Magento'da bunu önlemenin yolu, geliştirici / test ortamında geliştirme modunu her zaman etkinleştirmektir. ¶ Buna katılıyorum. Amacım Magento'nun üretim modunda dil kurallarına saygı duymasını sağlamak. Belki de özel bir modül gerektirecektir. Fikriniz için teşekkürler!
mpw

Belki Magento her iki durumda da bir istisna atmalıdır. Kullanıcıya bir Magento hata günlüğü sayfası sunulacak ve var / istisnada, normal istisnalarla aynı eşleşen bir günlük dosyası olacaktır. Burada büyük yakalamak kodu haber verilmeksizin yürütülmeyecek olmasıdır. İşlevler dosyasını uygulamaya / kod /
Jeroen

1
Bunu cevap olarak işaretlemeye karar verdim. Yine de bunun gibi muffling hatalarının tehlikeli olduğunu düşünmeme rağmen, Magento'nun diğer sorunları açmadan daktilolara saygı duymasını sağlamanın bir yolu yok gibi görünüyor. Geliştirme modunu açık tutmanın hatırlatıcısı gelecekteki okuyucular için iyi bir not ve bu en önemli paket
mpw

2

İyi soru. Bu E_RECOVERABLE_ERRORPHP ile genel bir sorun olduğunu düşünüyorum .

Sorunuzla ilgili olarak, hata işleyici değil istisna işleyicisidir. Hata işleyici, burada ele alınabilir ölümcül hatalarla ( E_RECOVERABLE_ERROR) tartıştığınız asıl soruna neden oluyor .

PHP 7 ve HHVM bunu zaten çözdü.

Magento ile daha da kötüsü çünkü PHP 5.2 hata sınıfından beri hata işleyici bununla ilgilenmez.

Bu hata sınıfıyla ilgilenmek ve bu hataları ErrorException'a dönüştürmek için daha kullanışlı bir hata işleme türü olurdu . Örnek (benim tarafımdan değil, buradan ):

set_error_handler(function($errno, $errstr, $errfile, $errline) {
    if ($errno === E_RECOVERABLE_ERROR) {
        throw new ErrorException($errstr, $errno, 0, $errfile, $errline);
    }
    return false;
});

Yani Magento ışığında, varsayılan hata işleyicisi küresel fonksiyondur mageCoreErrorHandleriçinde app/code/core/Mage/Core/functions.php. Bu yoluyla kayıtlı s olsun Mage::app()tarafından init()yöntemine Mage_Core_Model_App ( app/code/core/Mage/Core/Model/App.php(korumalı aracılığıyla) _initEnvironment()yöntemiyle).

Kendi PHP hata işleyicinizi üstüne kaydeden bir gözlemcicontroller_front_init_before yeterli olacaktır (PHP'deki hata işleyicileri istiflenebilir):

$previous = set_error_handler(function($errno, $errstr, $errfile, $errline) use (&$previous) {
    if ($errno === E_RECOVERABLE_ERROR) {
        throw new ErrorException($errstr, $errno, 0, $errfile, $errline);
    }
    if ($previous) {
        return call_user_func($previous, $errno, $errstr, $errfile, $errline);
    }
    return false;
});

catchable ölümcül hataları daha sonra istisnalara dönüştürülür ve bunlarla kendi uzantı kodunuzda ilgilenebilirsiniz veya yakalanmazlar ve istisna günlüğünde görünürler (mevcut davranışınız gibi yanlış türlerde mağazanızın gaga çalıştırması yerine, ölü programlar yalan söyleme ). PHP 7 aramaya istisna olarak değil ErrorException sonra ancak TypeException (a olan BaseException şimdilik) catchable ölümcül hatalar .

Diğer tüm hatalar Magento hata işleyicisine aktarılır.

Not: Bunu denemedim, bir yazım ama sorduğunuz sorunu biliyorum ve hata işleme analizi 1.5.1.0'a karşı yapılmış ve kod analizi yoluyla 1.9.1.0'a karşı doğrulanmıştır. Hata işleyici yığınının çalışması gerekir. Çoğu parçanın çalıştığını gösteren biraz genişletilmiş örnek kod ekleyin.

Henüz bunu bir magento uzantısı olarak paketlemedim, ancak modman ile düz olmalıdır. Sonra github üzerine koyacağım.

Ek: Hata İşleyici Demosu

Aşağıdaki kod örneği ( çevrimiçi demo ), hata işleyicilerinin yığınlanmasını ve yakalanabilir ölümcül hataya özel durum atmayı gösterir :

<?php
/**
 * error handler demonstration
 *
 * stackable error handle with previous call and catchable error exceptions
 *
 * @author hakre <http://hakre.wordpress.com>
 * @link /magento//a/64972/4115
 */

set_error_handler(function() {
    $args = func_get_args();
    var_dump("me is the previous error handler", $args);
});

$previous = set_error_handler(function($errno, $errstr, $errfile, $errline) use (&$previous) {
    if ($errno === E_RECOVERABLE_ERROR) {
        throw new ErrorException($errstr, $errno, 0, $errfile, $errline);
    }
    if ($previous) {
        return call_user_func($previous, $errno, $errstr, $errfile, $errline);
    }
    return false;
});

$test = function(callable $test) {};

$a = $undefined; // provoke little warning

$test(new stdClass); // provoke catchable fatal error

Program Çıkışı

string(32) "me is the previous error handler"
array(4) {
  [0]=>
  int(8)
  [1]=>
  string(29) "Undefined variable: undefined"
  [2]=>
  string(45) "/tmp/execpad-0eca072b619d/source-0eca072b619d"
  [3]=>
  int(28)
}

Fatal error: Uncaught exception 'ErrorException' with message 'Argument 1 passed to {closure}() must be callable, object given, called in /tmp/execpad-0eca072b619d/source-0eca072b619d on line 30 and defined' in /tmp/execpad-0eca072b619d/source-0eca072b619d:26
Stack trace:
#0 /tmp/execpad-0eca072b619d/source-0eca072b619d(26): {closure}(4096, 'Argument 1 pass...', '/tmp/execpad-0e...', 26, Array)
#1 /tmp/execpad-0eca072b619d/source-0eca072b619d(30): {closure}(Object(stdClass))
#2 {main}
  thrown in /tmp/execpad-0eca072b619d/source-0eca072b619d on line 26

Mükemmel yazma. Testiniz sırasında, hata işleyiciyi yeniden ayarlamaktan ölçülebilir bir performans düşüşü oldu mu?
mpw

Şimdiye kadar değil. Geliştirme moduna tüm uyarı / hata dönüştürülür çekirdekte ilgili bir alan bulunmaktadır İstisna (ve ErrorExceptuion - hatta yapmadınız). Bu belki de bunu aklı başında bir şekilde düzeltmek için bir yama seti gerektirir. Hata işleyici için, iyi bir gönderme yöntemi yoktur, burada da bir şekilde sabit bir varsayılan hata işleyici getirmek için çekirdeği
yamalamaya meyilliyim

1

(Exception $e)İşlev parametresi tanımına eklenerek zaten varsayılan PHP tarafından işlenir .

Bu işleve bir İstisna veya İstisna kapsamından başka bir şey iletemezsiniz.


İşleve bir göz atın mageCoreErrorHandler. Hatalı parametreler tarafından tetiklenen bir hata geliştirici olmayan modda işlenir ve bastırılır ve geliştirici modunda atılır Exception.
MPW

İlk etapta böyle bir şey olduğunda ciddi bir yanlışlık olur. Magento, mageCoreErrorHandlerziyaretçilerin yüzlerine bir hata alamayacağından emin olmalıdır. try{}catch(){}Onları kendiniz kapmak için kendiniz bir tane inşa edebilirsiniz ve eğer onları geçemezseniz.
Jeroen

Bastırılabilir bir çıkarılabilir ölümcül hata durumunda hiçbir istisna yapılmadığı düşünüldüğünde, dene / yakala beni ne elde eder?
MPW

1
Sonunda, yerel bir testten sonra anlıyorum ... Çok haklısın, hata bastırıldı ve kod devam edecek. Cevabımı güncelleyeceğim ve fazladan düşünceler ekleyeceğim
Jeroen

Yeni bir cevap
Jeroen
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.