การจัดการกับประเภท neutered นัยใน Magento


15

เพียงแค่สงสัยว่าถ้าใครมีกลยุทธ์ที่ดีกว่าที่ฉันเคยคิดไว้สำหรับการตรวจสอบประเภทให้อยู่ร่วมกับตัวจัดการข้อผิดพลาดที่กำหนดเองของ Magento โดยเฉพาะฉันสงสัยเกี่ยวกับ "ข้อผิดพลาดร้ายแรงที่ตรวจจับได้" ซึ่งถูกโยนในกรณีที่พารามิเตอร์ไม่ตรงกันพิมพ์ นี่คือตัวอย่างจากMageชั้นเรียน:

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

เนื่องจากตัวจัดการข้อผิดพลาดสิ่งใดที่สามารถส่งผ่านไปยังวิธีการรวมถึงZend_Date(ซึ่งจะทำงานได้ดี แต่ดูสับสนมากในบันทึกข้อยกเว้นของคุณ) หรือ a Mage_Core_Model_Appซึ่งอันที่จริงจะมีข้อผิดพลาดร้ายแรง

เป็นไปได้ที่จะนำการตรวจสอบประเภทกลับมาใช้ใหม่ที่ด้านบนของวิธีการ$e instanceof Exceptionแต่กลยุทธ์ดังกล่าวเอาชนะวัตถุประสงค์ของการพิมพ์ดีด

ข้อเสนอแนะคำแนะนำใด ๆ

คำตอบ:


5

เป็นคำถามที่ดี +1

ทำวิจัยและทดสอบหลังจากชี้ไปในทิศทางที่ดีหลังจากที่ฉันได้พูดคุยกับ @mpw ในคำตอบแรกของฉัน ฉันเข้าใจผิดบางส่วนเป็นครั้งแรก

จะเพิ่มรหัสเพื่อชี้แจงให้ผู้อื่นเข้าใจปัญหาได้ดีขึ้น

ทราบก่อนที่จะออก

ฉันไม่เคยมีปัญหาเช่นนี้มาก่อน การพัฒนาใน Magento ด้วยการเปิดใช้งานโหมดผู้พัฒนาฉันไม่คิดเลยสักนิดเกี่ยวกับเรื่องนี้ ดังนั้นทุกครั้งที่ฉันผายลมมันจะปรากฏขึ้นและจะได้รับการแก้ไขตามนั้น

ปัญหาเกี่ยวกับตัวอย่างการอธิบาย

ข้อผิดพลาดร้ายแรงที่บอกว่าคุณจะถูกบันทึกไว้ (ถ้าเปิดใช้งาน) และรหัสจะดำเนินการต่อตามปกติเนื่องจากไม่มีข้อผิดพลาดเกิดขึ้นmageCoreErrorHandlerหรือโปรแกรมจะexitทำงาน

ตัวจัดการข้อผิดพลาดหลักของ Magento เป็นครั้งแรกสำหรับข้อผิดพลาดที่ไม่สามารถจับได้ 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);
    }
}

อย่างที่คุณเห็นในโหมดนักพัฒนาซอฟต์แวร์มันจะบอกสิ่งที่มีประโยชน์มันจะพ่นข้อผิดพลาด เมื่อปิดมันจะเข้าสู่ระบบ (ถ้าเปิดใช้งาน) และดำเนินการต่อ

การพิสูจน์

ของฉัน 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');
}

ผลลัพธ์

เปิดใช้งานการพัฒนาโหมด ผลลัพธ์ที่ถูกต้อง

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

Developermode ถูกปิดใช้งานผลลัพธ์ไม่ถูกต้อง

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

ดังนั้นในที่สุดก็จะข้ามข้อผิดพลาดและดำเนินการต่อในบรรทัดถัดไปของรหัส อาจจะด้วยผลลัพธ์ที่แปลกประหลาด (ตามที่ @mpw ชี้ให้เห็น)

ข้อสรุป

มันอาจจะเกิดขึ้นคนที่มีการพัฒนาในทางที่ผิดพลาดจะไปไม่มีใครสังเกตเห็นและมันจะในที่สุดก็ให้ผลที่ไม่คาดคิด

แน่นอนเมื่อพัฒนาอย่างมืออาชีพ ข้อผิดพลาดจะถูกสังเกตเห็นและให้ความสนใจเป็น payed วิธีการป้องกันสิ่งนี้ใน Magento เปิดใช้งานโหมดการพัฒนาในสภาพแวดล้อมของนักพัฒนา / ทดสอบเสมอ

IMHO ไม่ควรไปถึงจุดนี้ในการพูดคุยซึ่งการตรวจสอบตัวแปรเป็นครั้งที่สอง ควรทดสอบรหัสก่อนเผยแพร่ในสภาพแวดล้อมการผลิต มันไม่ควรจำเป็น

ความคิดที่สอง

บางทีวีโอไอพีควรหยุดทำงานหลังจากเกิดข้อผิดพลาดร้ายแรง หรือสร้างรายงานและแสดงให้ผู้เยี่ยมชม วิธีนี้จะไม่รันโค้ดบรรทัดถัดไปและสิ่งต่าง ๆ จะถูกสังเกตเห็น


> หยาบเมื่อพัฒนาอย่างมืออาชีพ ข้อผิดพลาดจะถูกสังเกตและให้ความสนใจ วิธีการป้องกันสิ่งนี้ใน Magento เปิดใช้งานโหมดการพัฒนาในสภาพแวดล้อมของนักพัฒนา / การทดสอบอยู่เสมอ ¶ฉันเห็นด้วยกับสิ่งนั้น เป้าหมายของฉันคือการมีกฎภาษาเคารพวีโอไอพีในโหมดการผลิต ดูเหมือนว่ามันจะต้องมีโมดูลที่กำหนดเองบางที ขอบคุณสำหรับความเข้าใจของคุณ!
mpw

วีโอไอพีน่าจะมีข้อยกเว้นในทั้งสองกรณี ผู้ใช้จะได้รับการนำเสนอหน้า errorlog ของ Magento และใน var / exception จะมี logfile ที่ตรงกันเหมือนกับข้อยกเว้นปกติ สิ่งที่น่าจับตามองมากคือรหัสนั้นจะไม่ถูกดำเนินการโดยไม่ต้องแจ้งให้ทราบล่วงหน้า คุณสามารถคัดลอกไฟล์ฟังก์ชั่นไปยังแอพ / รหัส / ท้องถิ่นและโยนข้อยกเว้นเสมอ
Jeroen

1
ฉันตัดสินใจที่จะทำเครื่องหมายว่านี่เป็นคำตอบ แม้ว่าฉันจะยังคงคิดว่าข้อผิดพลาดในการทำ muffling เช่นนั้นเป็นสิ่งที่อันตราย แต่ก็ไม่น่าเป็นไปได้ที่จะมีวิธีทำให้ Magento เคารพคำใบ้ประเภทโดยไม่เปิดปัญหาอื่น ๆ การเตือนให้เปิดใช้โหมด dev เป็นสิ่งที่ดีสำหรับผู้อ่านในอนาคตและนั่นเป็นสิ่งที่สำคัญที่สุด
mpw

2

คำถามที่ดี. ฉันคิดว่านี่เป็นปัญหาทั่วไปE_RECOVERABLE_ERRORใน PHP

สิ่งที่คุณมีในคำถามของคุณคือตัวจัดการข้อยกเว้นไม่ใช่ตัวจัดการข้อผิดพลาด ข้อผิดพลาดการจัดการที่เป็นสาเหตุของปัญหาที่เกิดขึ้นจริงที่คุณพูดคุยที่นี่มีข้อผิดพลาดร้ายแรง catchable (E_RECOVERABLE_ERROR )

PHP 7 และ HHVM ได้แก้ไขสิ่งนี้แล้ว

มันแย่กว่ากับ Magento เนื่องจากตัวจัดการข้อผิดพลาดไม่ได้จัดการกับสิ่งนี้ตั้งแต่ PHP 5.2 คลาสข้อผิดพลาด

ชนิดที่มีประโยชน์มากขึ้นในการจัดการข้อผิดพลาดจะได้รับการจัดการกับข้อผิดพลาดระดับนี้และจะเปิดข้อผิดพลาดเหล่านี้เป็นErrorException s ตัวอย่าง (ไม่ใช่ฉันจากที่นี่ ):

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

ดังนั้นในแง่ของวีโอไอพี, ข้อผิดพลาดของตัวจัดการเริ่มต้นคือฟังก์ชั่นระดับโลกในmageCoreErrorHandler app/code/core/Mage/Core/functions.phpมันจะได้รับของที่ลงทะเบียนผ่านทางMage::app()โดยinit()วิธีการMage_Core_Model_App ( app/code/core/Mage/Core/Model/App.php) (ผ่านการป้องกัน_initEnvironment()วิธีการ)

สังเกตการณ์บนcontroller_front_init_beforeที่ลงทะเบียนจัดการข้อผิดพลาด PHP ของคุณเองบนควรจะพอเพียงแล้ว (จัดการข้อผิดพลาดใน PHP วางซ้อนกันได้):

$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แล้วจะกลายเป็นข้อยกเว้นและคุณสามารถจัดการกับพวกเขาในรหัสนามสกุลของคุณเองหรือพวกเขาจะไม่ถูกตรวจจับและจะเห็นได้ในบันทึกข้อยกเว้น (แทนที่จะต้อง gaga ร้านทำงานของคุณเกี่ยวกับประเภทที่ไม่ถูกต้องเช่นพฤติกรรมในปัจจุบันมีโปรแกรมที่ตายแล้ว อย่าโกหก ) ใน PHP 7 ข้อยกเว้นที่จะมองหาไม่ErrorExceptionแล้ว แต่TypeException (ซึ่งเป็นBaseException ) สำหรับตอนนี้ข้อผิดพลาดร้ายแรง catchable

ข้อผิดพลาดอื่น ๆ ทั้งหมดจะถูกส่งไปยังตัวจัดการข้อผิดพลาดของ Magento

หมายเหตุ: ฉันไม่ได้ลองสิ่งนี้มันเป็นบทความ แต่ฉันรู้ว่าปัญหาที่คุณถามและการวิเคราะห์การจัดการข้อผิดพลาดได้ทำกับ 1.5.1.0 และตรวจสอบกับ 1.9.1.0 ผ่านการวิเคราะห์รหัส การจัดการตัวจัดการข้อผิดพลาดควรทำงาน ฉันผนวกรหัสตัวอย่างเพิ่มเติมเล็กน้อยที่แสดงถึงการทำงานส่วนใหญ่

ฉันยังไม่ได้บรรจุสิ่งนี้เป็นส่วนขยายของวีโอไอพี แต่ควรตรงไปตรงมากับ modman ฉันจะเอามันใส่ GitHub แล้ว

ภาคผนวก: การสาธิตตัวจัดการข้อผิดพลาด

ตัวอย่างโค้ดต่อไปนี้ ( การสาธิตออนไลน์ ) แสดงให้เห็นถึงการซ้อนตัวจัดการข้อผิดพลาดและข้อผิดพลาดที่เกิดจากข้อผิดพลาดร้ายแรงที่จับได้ :

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

เอาต์พุตโปรแกรม

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

เขียนดีมาก ในระหว่างการทดสอบของคุณมีการลดประสิทธิภาพที่วัดได้จากการตั้งค่าตัวจัดการข้อผิดพลาดอีกครั้งหรือไม่
mpw

ฉันยังไม่ได้ไกล นอกจากนี้ยังมีพื้นที่ที่เกี่ยวข้องในแกนกลางซึ่งในโหมดการพัฒนาคำเตือน / ข้อผิดพลาดทั้งหมดจะถูกแปลงเป็นข้อยกเว้น (และไม่ใช่ErrorExceptuion - ไม่ได้บันทึกไว้ด้วย) อาจต้องใช้ชุดข้อมูลแก้ไขเพื่อแก้ไขปัญหานี้อย่างมีสติ สำหรับการจัดการข้อผิดพลาดไม่มีวิธีการที่ดีจัดส่งที่มีอยู่ที่นี่ฉันอย่างใดมีแนวโน้มที่จะหลักแพทช์แม้จะนำมาจัดการข้อผิดพลาดเริ่มต้นการแก้ไขใน.
hakre

1

มันได้รับการจัดการโดย PHP เริ่มต้นแล้วโดยการเพิ่ม(Exception $e)คำจำกัดความของพารามิเตอร์ฟังก์ชั่น

คุณไม่สามารถส่งผ่านสิ่งอื่นไปยังฟังก์ชันนี้ได้ยกเว้นการยกเว้นหรือการยกเว้นเพิ่มเติม


ดูmageCoreErrorHandlerฟังก์ชั่น ข้อผิดพลาดที่ถูกเรียกใช้โดย params ที่ไม่ถูกต้องจะได้รับการจัดการและระงับในโหมดที่ไม่ใช่นักพัฒนาซอฟต์แวร์และExceptionอยู่ในโหมดนักพัฒนาซอฟต์แวร์
mpw

มีบางอย่างผิดปกติเกิดขึ้นในครั้งแรก Magento มีเป้าหมายmageCoreErrorHandlerเพื่อให้แน่ใจว่าผู้เข้าชมจะไม่ได้รับข้อผิดพลาดในหน้าของพวกเขา คุณสามารถสร้างของตัวเองtry{}catch(){}เพื่อคว้ามันด้วยตัวคุณเองและถ้าคุณไม่สามารถผ่านมันไปได้
Jeroen

เมื่อพิจารณาถึงข้อยกเว้นจะไม่ถูกโยนในกรณีของข้อผิดพลาดร้ายแรงที่ถอดออกได้แมวพยายาม / จับฉันจะได้อะไร
mpw

1
ในที่สุดฉันก็รับมันหลังจากการทดสอบในท้องถิ่น ... คุณพูดถูกข้อผิดพลาดจะถูกระงับและรหัสจะดำเนินต่อไป ฉันจะอัปเดตคำตอบของฉันและเพิ่มความคิดพิเศษ
Jeroen

ฉันจะโพสต์คำตอบใหม่ไม่เช่นนั้นการสนทนาของเราจะไม่มีเหตุผลเลย
Jeroen
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.