Berurusan dengan mengisyaratkan tipe yang dikebiri di Magento

15

Hanya ingin tahu apakah ada yang punya strategi yang lebih baik daripada yang saya pikirkan untuk pengecekan tipe untuk hidup berdampingan dengan pengendali kesalahan khusus Magento. Secara khusus, saya bertanya-tanya tentang "Kesalahan Fatal yang Dapat Ditangkap" seperti yang dilemparkan dalam kasus ketidakcocokan parameter tipint. Berikut ini contoh dari Magekelas:

/**
 * 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);
}

Karena penangan kesalahan, apa pun dapat diteruskan ke metode, termasuk Zend_Date(yang akan berfungsi dengan baik, tetapi terlihat sangat membingungkan di log pengecualian Anda), atau Mage_Core_Model_App, yang sebenarnya akan memiliki kesalahan fatal.

Dimungkinkan untuk mengimplementasikan kembali pengecekan tipe di bagian atas metode: $e instanceof Exceptiontetapi taktik semacam itu mengalahkan tujuan tipuan.

Setiap petunjuk saran?

mpw
sumber

Jawaban:

5

Pertanyaan bagus +1

Melakukan beberapa penelitian dan tes setelah titik yang baik ke arah setelah diskusi saya dengan @ mw pada jawaban pertama saya. Saya salah memahaminya untuk pertama kalinya.

Akan menambahkan beberapa kode untuk memperjelas sehingga orang lain memahami masalah ini dengan lebih baik.

Sebuah catatan sebelum lepas landas

Saya tidak pernah memiliki masalah seperti itu sampai ini muncul. Berkembang di Magento dengan mode pengembang diaktifkan, saya bahkan tidak berpikir sedetik pun tentang ini. Jadi setiap kali saya kentut , itu akan muncul dan akan diperbaiki sesuai.

Masalah dengan sampel yang menjelaskan

Kesalahan fatal Anda akan dicatat (jika diaktifkan) dan kode akan terus seperti biasa karena tidak ada kesalahan yang dilemparkan oleh mageCoreErrorHandleratau program akan melakukannya exit.

Penangan kesalahan inti Magento pertama untuk kesalahan yang tidak dapat ditandingi 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);
    }
}

Seperti yang Anda lihat, dalam mode pengembang itu akan memberi tahu sesuatu yang bermanfaat, itu melempar kesalahan. Ketika dimatikan akan masuk (jika diaktifkan) dan melanjutkan.

Bukti

Saya 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');
}

Hasil

Developermode diaktifkan. Hasil yang benar

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

Developermode dinonaktifkan, Hasil salah

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

Jadi pada akhirnya akan melewatkan kesalahan dan melanjutkan pada baris kode berikutnya. Mungkin dengan hasil yang lebih aneh. (seperti yang ditunjukkan oleh @mpw)

Kesimpulan

Bisa saja terjadi bahwa seseorang berkembang sedemikian rupa sehingga kesalahan tidak diperhatikan dan pada akhirnya akan memberikan hasil yang tidak terduga.

Tentu ketika berkembang secara profesional. Kesalahan akan akan melihat dan perhatian yang diperhatikan. Cara untuk mencegah ini di Magento selalu memungkinkan developermode di lingkungan pengembang / uji.

IMHO seharusnya tidak pernah sampai ke titik diskusi ini, di mana memeriksa variabel untuk kedua kalinya (setidaknya itulah yang akan saya jelaskan) adalah cara untuk pergi. Kode harus diuji sebelum dirilis di lingkungan produksi. Seharusnya tidak diperlukan.

Pikiran kedua

Mungkin Magento harus berhenti setelah kesalahan fatal. Atau buat laporan dan tunjukkan kepada pengunjung. Dengan cara ini, baris kode berikutnya tidak akan pernah dieksekusi, dan hal-hal akan diperhatikan.

Jeroen
sumber
> Tentu kasar ketika berkembang secara profesional. Kesalahan akan diperhatikan dan diperhatikan. Cara untuk mencegah ini di Magento selalu memungkinkan developermode di lingkungan pengembang / uji. ¶ Saya setuju dengan itu. Tujuan saya adalah membuat aturan bahasa menghormati Magento dalam mode produksi. Sepertinya mungkin akan membutuhkan modul khusus. Terima kasih atas wawasan Anda!
mpw
Mungkin Magento harus memberikan pengecualian dalam kedua kasus. Pengguna akan disajikan halaman kesalahan log Magento dan dalam var / pengecualian akan memiliki logfile yang cocok, sama dengan pengecualian reguler. Yang menarik di sini adalah bahwa kode tidak akan dijalankan tanpa pemberitahuan. Anda dapat menyalin file fungsi ke aplikasi / kode / lokal dan selalu melemparkan pengecualian
Jeroen
1
Saya telah memutuskan untuk menandai ini sebagai jawabannya. Meskipun saya masih berpikir kesalahan meredam seperti itu berbahaya, sepertinya tidak mungkin ada cara untuk memastikan Magento menghormati tipuan tanpa membuka masalah lain. Pengingat untuk tetap mengaktifkan mode dev adalah yang bagus untuk pembaca masa depan, dan itu adalah takeaway yang paling penting
mpw
2

Pertanyaan bagus. Saya pikir ini adalah masalah umum E_RECOVERABLE_ERRORdalam PHP.

Apa yang Anda miliki dalam pertanyaan Anda adalah penangan pengecualian, bukan penangan kesalahan. Penangan kesalahan menyebabkan masalah aktual yang Anda diskusikan di sini dengan kesalahan fatal yang dapat ditangkap ( E_RECOVERABLE_ERROR) .

PHP 7 dan HHVM sudah menyelesaikan ini.

Ini lebih buruk dengan Magento karena penangan kesalahan tidak berurusan dengan ini sejak kelas kesalahan PHP 5.2.

Jenis penanganan kesalahan yang lebih bermanfaat adalah menangani kelas kesalahan ini dan mengubah kesalahan ini menjadi ErrorException s. Contoh (bukan oleh saya, dari sini ):

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

Jadi dalam terang Magento, penangan kesalahan default adalah fungsi global mageCoreErrorHandlerdi app/code/core/Mage/Core/functions.php. Itu bisa didaftarkan melalui Mage::app()olehinit() metode yang Mage_Core_Model_App ( app/code/core/Mage/Core/Model/App.php) (via dilindungi _initEnvironment()metode).

Sebuah pengamatcontroller_front_init_before yang mendaftarkan penangan kesalahan PHP Anda sendiri di atas sudah cukup maka (penangan kesalahan dalam PHP dapat ditumpuk):

$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;
});

kesalahan fatal yang dapat ditangkap kemudian diubah menjadi pengecualian dan Anda dapat menanganinya dalam kode ekstensi Anda sendiri atau tidak tertangkap dan akan terlihat di log pengecualian (alih-alih toko Anda menjalankan gaga pada jenis yang salah seperti perilaku saat ini, program yang mati jangan bohong ). Dalam PHP 7 pengecualian untuk mencari tidak ErrorException itu tapi TypeException (yang merupakan BaseException ) untuk kesalahan fatal yang sekarang dapat ditangkap .

Semua kesalahan lain diteruskan ke penangan kesalahan Magento.

Catatan: Saya belum mencoba ini, ini adalah artikel tetapi saya tahu masalah yang Anda tanyakan dan analisis penanganan kesalahan telah dilakukan terhadap 1.5.1.0 dan diverifikasi terhadap 1.9.1.0 melalui analisis kode. Penumpukan penangan kesalahan harus berhasil. Saya menambahkan sedikit contoh kode yang menunjukkan sebagian besar komponen berfungsi.

Saya belum mengemas ini sebagai ekstensi magento tetapi harus lurus ke depan dengan modman. Saya akan menaruhnya di github.

Lampiran: Demo Handler Demo

Contoh kode berikut ( demo online ) menunjukkan penumpukan penangan kesalahan dan pengecualian terhadap kesalahan fatal yang dapat ditangkap :

<?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

Output Program

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
hakre
sumber
Tulisan yang bagus. Selama pengujian Anda, apakah ada penurunan kinerja yang dapat diukur dari pengaturan ulang penangan kesalahan?
mpw
Saya belum sejauh ini. Ada juga area terkait di inti di mana pada mode pengembangan semua peringatan / kesalahan dikonversi ke Pengecualian (dan bukan ErrorExceptuion - bahkan tidak dicatat). Ini mungkin membutuhkan patchset untuk memperbaikinya dengan cara yang waras. Untuk penangan kesalahan, tidak ada metode pengiriman yang baik tersedia, juga di sini saya entah bagaimana cenderung untuk menambal inti bahkan untuk membawa penangan kesalahan default tetap masuk
hakre
1

Ini sudah ditangani oleh PHP default dengan menambahkan (Exception $e)definisi parameter fungsi.

Anda tidak bisa meneruskan hal lain ke fungsi ini selain Pengecualian atau perluasan Pengecualian.

Jeroen
sumber
Lihatlah mageCoreErrorHandlerfungsinya. Kesalahan yang dipicu oleh params yang salah akan ditangani dan dan ditekan dalam mode non-pengembang, dan melempar Exceptiondalam mode pengembang.
mpw
Sesuatu yang sangat salah ketika hal itu terjadi. Magento memiliki mageCoreErrorHandleruntuk memastikan bahwa pengunjung tidak akan mendapatkan kesalahan yang dilemparkan ke wajah mereka. Anda bisa membangun sendiri try{}catch(){}untuk mengambilnya sendiri, dan jika Anda tidak bisa meneruskannya.
Jeroen
Mengingat tidak ada pengecualian yang dilemparkan dalam kasus kesalahan fatal yang dapat ditutup-tutupi, apa yang akan saya dapatkan?
mpw
1
Saya akhirnya mendapatkannya, setelah tes lokal ... Anda benar, kesalahannya ditekan dan kode akan terus berlanjut. Saya akan memperbarui jawaban saya dan menambahkan beberapa pemikiran tambahan
Jeroen
Saya akan memposting jawaban baru kalau tidak, percakapan kami tidak masuk akal sama sekali
Jeroen