2017-10-27 10 views
0

多くの人は、OOPで使われているグローバル関数はテストできないので、悪い考えだと主張しています。代わりに私は何を使うべきですか?いつも依存注射?
私はいくつか持っているツールボックス特に、便利な多くの小さな機能を持つ。例えば。文字列を変換したり、計算をしたり、厄介なHTMLなどを整理したりすることができます。コード内で使用すると非常に便利です。たとえば:代わりに、OOPのグローバル関数は何ですか?

public function copyUploadedFile($filename, $dst_dir) 
{ 
    $filename = convertToSimpleString($filename); 
    if (!$filename) $error = displayError('Filename is empty!'); 
    $extension = getFileExtension($filename); 
    $dst_dir = convertToSimpleString($dst_dir); 
    if (!isDir($dst_dir)) createDir($dst_dir); 
    .... 
} 

依存性の注入は、コードが複雑になり、常にさえ非常に小さな仕事のための新しいオブジェクトを作成するために強制的:あなたは2種類の機能を区別する必要があり、すべての

$file = new FileManager(new ErrorHandler, new StringConverter, new DirManager ...) 

public function __construct(ErrorHandler $error_handler, StringConverter $string_converter, DirManager $dir_manager, ...) 
{ 
    $this->error_handler = $error_handler; 
    $this->string_converter = $string_converter; 
    $this->dir_manager = $div_manager; 
    ... 
} 
+0

ユニットテストを書いていますか? – DanielO

+0

コードを書き直す必要があり、単体テストを行う予定です。 –

+0

単体テストの問題によると、スタティック関数とグローバル関数をスタブしてモックするライブラリAspectMock(https://github.com/Codeception/AspectMock)があります:https://github.com/Codeception/AspectMock –

答えて

0

まず: PHPのネイティブ関数とユーザー定義関数

いずれかのクラスでPHPの組み込み関数を使用すると、テスト容易性(および一般的な動作)に影響する唯一の関数は、何らかの外部グローバル状態にアクセスする関数になります。たとえば、time()php_sapi_name()のような関数は、アプリケーションの外部に存在するグローバルな状態に依存します。ベストプラクティスは、オブジェクトのメソッドまたはコンストラクター(依存関係注入)のパラメーターとして渡すことです。

:それが不可能な場合は、代替の時にクラスメソッドでラップし、ユニットテストを実行するときに、その動作を変更するためにリフレクションを使用することです。 array_key_exists()またはstrpost()などの機能については

、それらは実際には、既存のアプリケーションの状態を操作し、常に予測結果を持っています。彼らはあなたのコードのテスト容易性に悪影響を与えません。

しかし、あなたは実際にそれらについて話していませんでした。

ユーザー定義関数については、実際にはテスト可能ではありません。つまり、あなたはそれらを「信頼できる」(疑わしいアイデアです)として扱わなければならないか、またはそれらを避けなければなりません。

オブジェクト指向パラダイムを実際に使用することをお勧めしますが、これは手続き型パラダイムのコアコンセプトであり、実際にOOPコードが混乱する原因になるためです。

また、この講義を見て:https://www.youtube.com/watch?v=KHBrDWIKW8Q


さて、実用的な部分。

すべては、使用するトップレベルのAPIから始まります。私はそれを見るように、高レベルであなたのコードは次のようにちょっとになります。

try { 
    $file = new File($filename); 
    $storage->move($file, '/path/to/destination'); 
} catch (EmptyFilename $exception) { 
    echo 'File name is missing!'; 
} catch (DirectoryNotWritable $exception) { 
    echo 'Yeah no, you cant write there. Get lost!'; 
} 

「このファイルが実際に有効でアップロードされ、」一部は、ファイルの抽象化の責任でなければなりません。 $file->getExtension()のようなコードでも同じですが、 "移動ファイル"はストレージ抽象化の責任を負うべきです。

そして、あなたの記憶域の抽象化は、適切なエラーメッセージをフォーマットする責任を負うべきではありません。代わりに、例外をスローし、レンダリングに対処するためにコールスタック内の何かを高くする必要があります。

+0

答えをありがとう!上のコードは、グローバル関数の使用の問題を示す単なる例でした。はい、あなたは正しいです、もちろんそれは別のクラスに分けられるべきです。しかし、私が理解するように、**依存症注入**はこの場合の唯一の正しい解決策ですか? あなたのコードで "EmptyFilename"と "DirectoryNotWritable"とは何ですか?例外を拡張するクラス? –

+0

はい、例外です。私は個人的には、例外やインタフェースに接尾辞を追加するのは悪い方法だと思います。 –

1

依存性注入は、の反転パターンのパターンです。依存関係の制御は、呼び出されたものから呼び出し元のものへと反転されます。

主な利点:発信者チェーンの一番上にあるものは常にあなたです。すべての依存関係を制御し、アプリケーションの動作を完全に制御できます。依存関係を別のもの(例えば、あなたが作ったもの)で置き換えることができます。

たとえば、ライブラリXがロガーYを使用していて、ロガーZを使用するにはどうすればよいですか?依存性注入を使用すると、ライブラリX.

http://php-di.org/doc/understanding-di.html

間違って適用されるアンチパターンとなっているすべてのパターンのコードを変更する必要はありません。依存性注入は、外部からアプリケーションの「コア」に「注入可能物」(例えば、サービス、リポジトリ、データベース、テンプレートエンジン、ロガー)を注入するために使用される。 DIは「Newables」には使用されません。Newablesの例は、バリューオブジェクト、DTOおよびPOCOです。この種のオブジェクトは、DIなしで作成する必要があります(作成する必要があります)。

PHPは、OOPと手続き型の組み合わせをサポートしています。 file_get_contentsのようなグローバル関数はどこでも使用できます。しかし、問題(または質問)は:どのようにしたいユニットテストそれ?解決策:実際のファイルシステムを模擬するために仮想ファイルシステムとしてvfsStreamを使用してください。解決策:OOPインタフェース(1,2)を使用して模擬オブジェクトを注入する。

私はDIの主な利点の一つであると思う:

  • ユニットの(注射用)のクラスはもはやしっかりとその依存
  • に結合されている簡素化が
  • もちろんのより多くの理由がありますをテスト

新しい複雑さを管理するには、PHP-DIのようなツールをお勧めします。パフォーマンスを向上させるには、prodサーバーでキャッシングを有効にする必要があります。すべてがその価格を持っています。 - )

関連する問題