Umgang mit kastrierten Tippern in Magento

15

Ich frage mich nur, ob jemand bessere Strategien hat, als ich gedacht habe, damit die Typprüfung mit Magentos benutzerdefiniertem Fehlerbehandlungsprogramm koexistiert. Insbesondere frage ich mich, ob "Catchable Fatal Errors" (abfangbare schwerwiegende Fehler) vorliegen, die im Fall einer nicht übereinstimmenden typisierten Parameter ausgelöst wurden. Hier ist ein Beispiel aus der MageKlasse:

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

Aufgrund der Fehlerbehandlungsroutine kann alles an die Methode übergeben werden, einschließlich einer Zend_Date(die gut funktioniert, aber in Ihrem Ausnahmeprotokoll sehr verwirrend aussieht) oder einer Mage_Core_Model_App, die tatsächlich einen schwerwiegenden Fehler aufweist.

Es ist möglich, die Typprüfung am Anfang einer Methode erneut zu implementieren. Diese $e instanceof ExceptionTaktik kann jedoch den Zweck eines Tippfehlers nicht erfüllen.

Irgendwelche Hinweise Vorschläge?

mpw
quelle

Antworten:

5

Gute Frage +1

Habe nach meiner Diskussion mit @mpw über meine erste Antwort einige Nachforschungen und Tests nach einem guten Punkt in der Richtung durchgeführt. Ich habe es das erste Mal teilweise falsch verstanden.

Fügt zur Verdeutlichung einige Codes hinzu, damit andere das Problem besser verstehen.

Eine Notiz vor dem Start

Ich hatte nie solche Probleme, bis dies auftauchte. Entwickeln in Magento mit aktiviertem Entwicklermodus Ich denke keine Sekunde darüber nach. Jedes Mal , wenn ich furz , wird es angezeigt und dementsprechend korrigiert.

Das Problem mit einem erklärenden Beispiel

Ihre schwerwiegenden Fehler werden protokolliert (falls aktiviert) und der Code wird wie gewohnt fortgesetzt, da kein Fehler von mageCoreErrorHandleroder durch das Programm ausgelöst wird exit.

Erster Magento-Fehlerbehandler für nicht behebbare Fehler 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);
    }
}

Wie Sie sehen, wird im Entwicklermodus etwas Nützliches angezeigt und ein Fehler ausgegeben. Wenn es ausgeschaltet ist, wird es protokolliert (falls aktiviert) und fortgesetzt.

Der Beweis

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

Das Ergebnis

Entwicklermodus aktiviert. Richtiges Ergebnis

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

Entwicklermodus deaktiviert, falsches Ergebnis

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

Daher wird der Fehler möglicherweise übersprungen und in der nächsten Codezeile fortgefahren. Vielleicht mit noch seltsameren Ergebnissen. (wie @mpw darauf hinweist)

Fazit

Es könnte passieren , dass jemand in einer Art und Weise zu entwickeln , dass Fehler gehen unbemerkt und es wird schließlich zu unerwarteten Ergebnissen führen.

Natürlich, wenn man sich professionell entwickelt. Fehler werden bemerkt und Aufmerksamkeit geschenkt. Die Möglichkeit, dies in Magento zu verhindern, besteht immer darin, den Entwicklungsmodus in einer Entwickler- / Testumgebung zu aktivieren.

IMHO sollte es nie zu diesem Punkt der Diskussion kommen, an dem das Überprüfen einer Variablen ein zweites Mal (zumindest würde ich es so beschreiben) der richtige Weg ist. Code sollte vor der Freigabe in Produktionsumgebungen getestet werden. Es sollte nicht benötigt werden.

Bedenken

Vielleicht sollte Magento nach einem schwerwiegenden Fehler aufhören. Oder generieren Sie einen Bericht und zeigen Sie ihn dem Besucher. Auf diese Weise werden die nächsten Codezeilen niemals ausgeführt und Dinge werden bemerkt.

Jeroen
quelle
> Grob bei professioneller Entwicklung. Fehler werden bemerkt und Aufmerksamkeit geschenkt. Die Möglichkeit, dies in Magento zu verhindern, besteht immer darin, den Entwicklungsmodus in einer Entwickler- / Testumgebung zu aktivieren. ¶ Ich stimme dem zu. Mein Ziel ist es, dass Magento die Sprachregeln im Produktionsmodus einhält. Sieht so aus, als würde ein benutzerdefiniertes Modul benötigt. Vielen Dank für Ihren Einblick!
mpw
Vielleicht sollte Magento in beiden Fällen eine Ausnahme auslösen. Dem Benutzer wird eine Magento-Fehlerprotokollseite angezeigt, und in var / exception wird eine passende Protokolldatei angezeigt, genau wie bei regulären Ausnahmen. Der große Haken dabei ist, dass Code nicht ohne Vorankündigung ausgeführt wird. Sie können die Funktionsdatei in die App / code / local kopieren und immer eine Ausnahme
auslösen
1
Ich habe beschlossen, dies als Antwort zu markieren. Ich halte es immer noch für gefährlich, solche Fehler zu dämpfen, aber es scheint unwahrscheinlich, dass es eine Möglichkeit gibt, sicherzustellen, dass Magento die Schreibweisen respektiert, ohne andere Probleme zu verursachen. Die Erinnerung, den Dev-Modus eingeschaltet zu lassen, ist gut für zukünftige Leser, und das ist der wichtigste
Hinweis
2

Gute Frage. Ich denke, dies ist ein generelles Problem E_RECOVERABLE_ERRORin PHP.

Was Sie in Ihrer Frage haben, ist die Ausnahmebehandlung, nicht die Fehlerbehandlung. Der Fehlerbehandler verursacht das eigentliche Problem, das Sie hier besprechen, mit auffindbaren schwerwiegenden Fehlern ( E_RECOVERABLE_ERROR) .

PHP 7 und HHVM haben dies bereits gelöst.

Es ist schlimmer mit Magento, weil der Error-Handler dies seit PHP 5.2 Fehlerklasse nicht mehr behandelt.

Eine nützlichere Art der Fehlerbehandlung wäre es, sich mit dieser Fehlerklasse zu befassen und diese Fehler in ErrorException s umzuwandeln . Beispiel (nicht von mir, von hier ):

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

So im Licht von Magento, die Standard - Fehlerbehandlung ist die globale Funktion mageCoreErrorHandlerin app/code/core/Mage/Core/functions.php. Es wird über Mage::app()die init()Methode der Mage_Core_Model_App ( app/code/core/Mage/Core/Model/App.php) (über eine geschützte _initEnvironment()Methode) registriert .

Ein Beobachter, aufcontroller_front_init_before dem Ihr eigener PHP-Error-Handler registriert ist, sollte dann ausreichen (Error-Handler in PHP sind stapelbar):

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

Abfangbare schwerwiegende Fehler werden dann zu Ausnahmen und Sie können sie in Ihrem eigenen Erweiterungscode behandeln oder sie werden nicht abgefangen und im Ausnahmeprotokoll angezeigt (anstatt Ihren Shop auf falschen Typen laufen zu lassen, wie es das aktuelle Verhalten ist, tote Programme) lüge nicht ). In PHP 7 ist die Ausnahme, nach der gesucht werden muss, nicht ErrorException, sondern TypeException (eine BaseException ) für die jetzt auffindbaren schwerwiegenden Fehler .

Alle anderen Fehler werden an den Fehlerbehandler von Magento weitergeleitet.

Hinweis: Ich habe dies nicht ausprobiert, es ist eine Zusammenfassung, aber ich kenne das Problem, nach dem Sie fragen, und die Fehlerbehandlungsanalyse wurde mit 1.5.1.0 durchgeführt und mit 1.9.1.0 durch Codeanalyse überprüft. Das Stapeln der Fehlerbehandlungsroutine sollte funktionieren. Ich füge einen kleinen erweiterten Beispielcode an, der die meisten Teile der Arbeit demonstriert.

Ich habe dies noch nicht als Magento-Erweiterung gepackt, aber es sollte mit Modman einfach sein. Ich werde es dann auf Github setzen.

Anhang: Fehlerbehandlungs-Demo

Das folgende Codebeispiel ( Online-Demo ) veranschaulicht das Stapeln von Fehlerbehandlungsroutinen und das Auslösen von Ausnahmen bei abfangbaren schwerwiegenden Fehlern :

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

Programmausgabe

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
quelle
Hervorragendes Schreiben. Gab es während Ihres Tests eine messbare Leistungsverschlechterung durch das Zurücksetzen des Fehlerbehandlungsprogramms?
mpw
Ich habe noch nicht so weit. Es gibt auch einen verwandten Bereich im Kern, in dem im Entwicklungsmodus alle Warnungen / Fehler in Exception konvertiert werden (und nicht ErrorExceptuion - nicht einmal protokolliert). Dies erfordert möglicherweise ein Patchset, um dies auf vernünftige Weise zu beheben. Für die Fehlerbehandlung, gibt es keine gute Versandmethode zur Verfügung, hier auch irgendwie neigen dazu, Patch Kern ich sogar einen festen Standardfehlerhandler in zu bringen.
hakre
1

Es wird bereits standardmäßig von PHP verarbeitet, indem es (Exception $e)in die Funktionsparameterdefinition eingefügt wird.

Sie können dieser Funktion nichts anderes als eine Ausnahme oder eine Erweiterung der Ausnahme übergeben.

Jeroen
quelle
Schauen Sie sich die mageCoreErrorHandlerFunktion an. Ein durch falsche Parameter ausgelöster Fehler wird im Nicht-Entwicklermodus behandelt und unterdrückt und im Entwicklermodus ausgelöst Exception.
mpw
Etwas ist ernsthaft falsch, wenn so etwas überhaupt passiert. Magento muss mageCoreErrorHandlersicherstellen, dass den Besuchern kein Fehler ins Gesicht geworfen wird. Sie könnten eine eigene bauen try{}catch(){}, um sie sich selbst zu schnappen, und wenn Sie sie nicht weitergeben können.
Jeroen,
Wenn im Falle eines unterdrückten, katastrophalen Fehlers keine Ausnahmen geworfen werden, was würde der Versuch / Fang mir bringen?
mpw
1
Ich bekomme es endlich, nach einem lokalen Test ... Sie haben ganz recht, der Fehler wird unterdrückt und der Code wird fortgesetzt. Ich werde meine Antwort aktualisieren und einige zusätzliche Gedanken hinzufügen
Jeroen
Ich werde eine neue Antwort posten, sonst ergibt unser Gespräch überhaupt keinen Sinn
Jeroen