Magentoでの去勢されたタイプヒンティングの処理


15

Magentoのカスタムエラーハンドラーと共存する型チェックについて、私が考えていたよりも優れた戦略があるかどうか疑問に思っています。具体的には、私はtypehintedパラメータの不一致の場合にスローされたとして「キャッチできる致命的エラー」に疑問を抱いています。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(正常に動作しますが、例外ログで非常に混乱するように見える)、または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');
}

結果

Developermodeが有効になっています。正しい結果

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が指摘するように)

結論

可能性があり、誰かがエラーが行くような方法で開発していることが起こり見過ごさ、それがされます最終的には予期しない結果を与えます。

もちろん、専門的な方法で開発する場合。エラーがしますことに気づいたと注意を払っています。Magentoでこれを防ぐ方法は、開発者/テスト環境で常に開発者モードを有効にすることです。

私見では、この議論のポイントに到達するべきではありません。変数をもう一度チェックすること(少なくともそれは私が説明する方法です)が進むべき方法です。実稼働環境でリリースする前にコードをテストする必要があります。すべきではないん。

考え直し

たぶん、Magentoのは、致命的なエラーが発生した後に停止する必要があります。または、レポートを生成して訪問者に表示します。この方法では、コードの次の行は実行されず、物事が認識されます。


>プロフェッショナルな方法で開発する場合、粗雑です。エラーが通知され、注意が払われます。Magentoでこれを防ぐ方法は、開発者/テスト環境で常に開発者モードを有効にすることです。¶私はそれに同意します。私の目標は、Magentoがプロダクションモードで言語ルールを尊重するようにすることです。おそらくカスタムモジュールが必要になるようです。あなたの洞察力をありがとう!
mpw

たぶん、Magentoは両方のケースで例外を投げるべきでしょう。利用者は、Magentoのエラーログページを提示されるとVARに/例外が一致するログファイル、通常の例外と同じになります。ここに偉大なキャッチが、コードは予告なしに実行することが文句を言わないということです。あなたはアプリ/コード/ localに機能ファイルをコピーして、常に例外をスローする可能性
のJeroen

1
私は答えとしてこれをマークすることに決めました。私はまだそのようなエラーを消音することは危険だと思うが、他の問題を開かずに確認してくださいMagentoの点のtypehintsを作るための方法がありますとは考えにくいです。DEVモードがオンに維持するためのリマインダーは、将来の読者のために良いの一つであり、それは最も重要なお持ち帰りだ
MPW

2

良い質問。これはE_RECOVERABLE_ERRORPHPの一般的な問題だと思います。

あなたは、あなたの質問を持っているとすると、例外ハンドラではなく、エラーハンドラです。エラーハンドラは、とあなたはここで議論し、実際の問題を引き起こしている捕捉可能な致命的なエラーE_RECOVERABLE_ERROR

PHP 7とHHVMが、これはすでに解決しています。

エラーハンドラは、PHP 5.2のエラークラスので、これに対処しないので、それは、Magentoのと悪化します。

エラー処理のより有用な種類は、このエラークラスに対処されるだろうとの中にこれらのエラーをオンにするErrorException秒。例(ない私が、ここから):

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

したがって、Magentoの観点から見ると、デフォルトのエラーハンドラはのグローバル関数mageCoreErrorHandlerですapp/code/core/Mage/Core/functions.php。それはによって登録の取得Mage::app()によるinit()方法Mage_Core_Model_Appapp/code/core/Mage/Core/Model/App.php(保護経由)_initEnvironment()メソッド)。

独自のPHPエラーハンドラーを最上位に登録するオブザーバーでcontroller_front_init_before十分です(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;
});

キャッチ可能な致命的なエラーは例外に変換され、独自の拡張コードでそれらに対処する、キャッチされずに例外ログに表示されます嘘をつかないでください)。PHP 7を探すために例外ではないがErrorExceptionその後、しかしTypeException(あるBaseException今のところ)捕捉可能致命的なエラー

他のすべてのエラーは、Magentoのエラーハンドラに渡されます。

注:私はこれを試したことはありません、それは書き込みです、しかし、私はあなたが尋ねている問題を知っていて、エラー処理分析は1.5.1.0に対して行われ、コード分析を通じて1.9.1.0に対して検証されました。エラーハンドラーのスタックは機能するはずです。ほとんどの部品が動作することを示す、少し拡​​張されたサンプルコードを追加します。

私はまだこれをmagento拡張としてパッケージ化していませんが、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

(Exception $e)関数パラメーター定義に追加することにより、デフォルトのPHPで既に処理されています。

この関数には、例外または例外の拡張以外のものを渡すことはできません。


mageCoreErrorHandler関数を見てください。誤ったパラメーターによってトリガーされたエラーは、非開発者モードで処理および抑制され、開発者モードでスローExceptionされます。
MPW

そのようなものが最初の場所で発生したときに何かが真剣に間違っています。Magentoは、mageCoreErrorHandler訪問者が自分の顔にエラーをスローしないようにする必要があります。あなたは自分の構築することができtry{}catch(){}、それらを自分でつかむために、あなたはそれらを渡すことができない場合。
Jeroen

抑制可能な致命的なエラーの場合に例外がスローされないことを考慮すると、try / catchで何が得られますか?
mpw

1
ローカルテストの後、ようやく手に入れました。あなたは非常に正しいです。エラーは抑制され、コードは続行されます。私の答えを更新し、いくつかの余分な考えを追加します
Jeroen

私は、私たちの会話は全く意味がありませんそれ以外の場合は、新しい答えを投稿します
イェルーン
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.