Trattare con suggerimenti di tipo sterilizzato in Magento


15

Mi chiedo solo se qualcuno ha strategie migliori di quelle che ho pensato per far coesistere il controllo del tipo con il gestore di errori personalizzato di Magento. In particolare, mi chiedo un "Errore irreversibile irreversibile" come generato nel caso di una mancata corrispondenza dei parametri. Ecco un esempio dalla Mageclasse:

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

A causa del gestore degli errori, qualsiasi cosa può essere passata al metodo, incluso un Zend_Date(che funzionerà bene, ma sembra super confuso nel registro delle eccezioni) o un Mage_Core_Model_App, che in realtà avrà un errore fatale.

È possibile implementare nuovamente il controllo del tipo nella parte superiore di un metodo: $e instanceof Exceptionma tali tattiche vanificano lo scopo di un suggerimento.

Eventuali accenni suggerimenti?

Risposte:


5

Buona domanda +1

Ho fatto qualche ricerca e test dopo un buon punto nella direzione dopo la mia discussione con @mpw sulla mia prima risposta. L'ho capito in parte per la prima volta.

Aggiungerà del codice per chiarire in modo che altri comprendano meglio il problema.

Una nota prima del decollo

Non ho mai avuto problemi del genere fino a quando questo non è emerso. Sviluppare in Magento con la modalità sviluppatore abilitata non ci penso nemmeno un secondo su questo. Quindi ogni volta che scoreggerò , comparirà e sarà corretto di conseguenza.

Il problema con un esempio esplicativo

I tuoi errori fatali verranno registrati (se abilitati) e il codice continuerà come al solito perché non viene generato alcun errore mageCoreErrorHandlero il programma lo farà exit.

Primo gestore di errori core di Magento per errori non raggiungibili 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);
    }
}

Come puoi vedere, in modalità sviluppatore dirà qualcosa di utile, genera un errore. Quando è spento, accederà (se abilitato) e continuerà.

La prova

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

Il risultato

Developermode abilitato. Risultato corretto

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

Developermode disabilitato, risultato errato

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

Quindi alla fine salterà l'errore e continuerà sulla riga di codice successiva. Forse con risultati ancora più strani. (come sottolinea @mpw)

Conclusione

Si potrebbe accadere che qualcuno si sta sviluppando in un modo che gli errori passerà inosservata e sarà eventualmente dare risultati inattesi.

Naturalmente quando si sviluppa in modo professionale. Gli errori saranno notati e l'attenzione è pagato. Il modo per evitarlo in Magento è sempre abilitare la modalità di sviluppo in un ambiente di sviluppo / test.

IMHO non dovrebbe mai arrivare a questo punto di discussione, dove controllare una variabile una seconda volta (almeno così è come la descriverei) è la strada da percorrere. Il codice deve essere testato prima di essere rilasciato negli ambienti di produzione. Dovrebbe non essere necessaria.

Ripensamenti

Magento dovrebbe fermarsi dopo un errore fatale. Oppure genera un rapporto e mostralo al visitatore. In questo modo le successive righe di codice non verranno mai eseguite e le cose verranno notate.


> Di massima quando si sviluppa in modo professionale. Si noteranno errori e si presterà attenzione. Il modo per evitarlo in Magento è sempre abilitare la modalità di sviluppo in un ambiente di sviluppo / test. ¶ Sono d'accordo. Il mio obiettivo è che Magento rispetti le regole del linguaggio in modalità di produzione. Sembra che richiederà forse un modulo personalizzato. Grazie per la tua comprensione!
mpw,

Forse Magento dovrebbe generare un'eccezione in entrambi i casi. All'utente verrà presentata una pagina di log degli errori di Magento e in var / exception avrà un file di log corrispondente, lo stesso delle eccezioni regolari. Il grande vantaggio qui è che il codice non verrà eseguito senza preavviso. È possibile copiare il file delle funzioni sull'app / code / local e generare sempre un'eccezione
Jeroen

1
Ho deciso di contrassegnare questa come risposta. Anche se continuo a pensare che errori di smorzamento del genere siano pericolosi, sembra improbabile che ci sia un modo per assicurarsi che Magento rispetti i suggerimenti sul tipo senza aprire altri problemi. Il promemoria per mantenere attiva la modalità dev è buono per i futuri lettori, ed è il più importante da asporto
mpw

2

Buona domanda. Penso che questo sia un problema generale con E_RECOVERABLE_ERRORPHP.

Quello che hai nella tua domanda è il gestore delle eccezioni, non il gestore degli errori. Il gestore degli errori sta causando l'effettivo problema discusso qui con errori irreversibili irreversibili ( E_RECOVERABLE_ERROR) .

PHP 7 e HHVM lo hanno già risolto.

È peggio con Magento perché il gestore degli errori non si occupa di questo dalla classe di errore PHP 5.2.

Un tipo più utile di gestione degli errori sarebbe gestire questa classe di errori e trasformare questi errori in ErrorException s. Esempio (non da me, da qui ):

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

Quindi alla luce di Magento, il gestore degli errori predefinito è la funzione globale mageCoreErrorHandlerin app/code/core/Mage/Core/functions.php. Viene registrato tramite Mage::app()il init()metodo di Mage_Core_Model_App ( app/code/core/Mage/Core/Model/App.php) (tramite _initEnvironment()metodo protetto ).

Un osservatore sucontroller_front_init_before cui registra il proprio gestore di errori PHP in alto dovrebbe essere sufficiente (i gestori di errori in PHP sono impilabili):

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

errori irreversibili irreversibili vengono poi trasformati in eccezioni e puoi gestirli nel tuo codice di estensione o non sono rilevati e verranno visualizzati nel registro delle eccezioni (invece di far eseguire al tuo negozio gaga su tipi errati come il comportamento attuale, programmi morti non mentire ). In PHP 7 l'eccezione di cercare non è ErrorException allora, ma TypeException (che è un BaseException ) per l'ormai errori fatali catturabile .

Tutti gli altri errori vengono passati al gestore errori di Magento.

Nota: non l'ho provato, è un articolo di scrittura ma conosco il problema che stai chiedendo e l'analisi della gestione degli errori è stata eseguita su 1.5.1.0 e verificata su 1.9.1.0 tramite analisi del codice. L'impilamento del gestore errori dovrebbe funzionare. Aggiungo un piccolo esempio di codice che mostra la maggior parte delle parti funzionanti.

Non l'ho ancora impacchettato come estensione magento ma dovrebbe essere semplice con modman. Lo metterò su Github allora.

Appendice: demo del gestore degli errori

Il seguente esempio di codice ( demo online ) mostra l'accatastamento di gestori di errori e l'eccezione che genera errori irreversibili irreversibili :

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

Uscita del programma

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

Scrittura eccellente. Durante i test, si è verificato un calo misurabile delle prestazioni a causa della reimpostazione del gestore errori?
mpw,

Non l'ho fatto finora. C'è anche un'area correlata nel nucleo in cui nella modalità di sviluppo tutti gli avvisi / errori vengono convertiti in Eccezione (e non ErrorExceptuion - nemmeno registrato). Questo forse richiede un patchset per risolvere questo problema in modo sano. Per il gestore degli errori, non esiste un buon metodo di invio disponibile, anche qui in qualche modo tendo a patch core anche per portare un gestore di errori predefinito fisso.
Hacre

1

È già gestito per impostazione predefinita PHP aggiungendo (Exception $e) la definizione del parametro della funzione.

Non è possibile trasferire a questa funzione nient'altro che un'eccezione o estensione di eccezione.


Dai un'occhiata alla mageCoreErrorHandlerfunzione. Un errore innescato da parametri errati verrà gestito e soppresso in modalità non sviluppatore e verrà lanciato Exceptionin modalità sviluppatore.
mpw,

Qualcosa è seriamente sbagliato quando ciò accade in primo luogo. Magento ha la mageCoreErrorHandlercertezza che i visitatori non riceveranno un errore in faccia. Potresti costruirne uno try{}catch(){}per afferrarli da solo e se non riesci a trasmetterli.
Jeroen,

Considerando che non si generano eccezioni nel caso di un errore fatale irreversibile soppresso, cosa mi farebbe il tentativo / cattura?
mpw,

1
Finalmente sto arrivando, dopo un test locale ... Hai perfettamente ragione, l'errore viene eliminato e il codice continuerà. Aggiornerò la mia risposta e aggiungerò qualche pensiero in più
Jeroen,

Pubblicherò una nuova risposta, altrimenti la nostra conversazione non ha alcun senso
Jeroen,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.