いつサービスまたはユーティリティ関数を作成する必要がありますか?


11

私は先週ずっとこの質問を念頭に置いていました:サービスまたはユーティリティ関数をいつ作成するべきですか?

Drupal Coreにはサービス機能とユーティリティ機能の両方がありますが、それらを区別することができません(サービスを作成する必要がある場合、またはユーティリティ機能を作成する必要がある場合)。

例として、InternalFunctionsクラスがあるModules Weightモジュールを取り上げます。

<?php

namespace Drupal\modules_weight\Utility;

class InternalFunctions {

  public static function prepareDelta($weight) {
    $delta = 100;

    $weight = (int) $weight;

    if ($weight > $delta) {
      return $weight;
    }

    if ($weight < -100) {
      return $weight * -1;
    }

    return $delta;
  }


  public static function modulesList($force = FALSE) {
    $modules = [];
    $installed_modules = system_get_info('module');

    $config_factory = \Drupal::service('config.factory');

    if ($force) {
      $show_system_modules = TRUE;
    }
    else {
modules.
      $show_system_modules = $config_factory->get('modules_weight.settings')->get('show_system_modules');
    }

    $modules_weight = $config_factory->get('core.extension')->get('module');

    foreach ($installed_modules as $filename => $module_info) {
      if (!isset($module_info['hidden']) && ($show_system_modules || $module_info['package'] != 'Core')) {
        $modules[$filename]['name'] = $module_info['name'];
        $modules[$filename]['description'] = $module_info['description'];
        $modules[$filename]['weight'] = $modules_weight[$filename];
        $modules[$filename]['package'] = $module_info['package'];
      }
    }
    uasort($modules, ['Drupal\Component\Utility\SortArray', 'sortByWeightElement']);

    return $modules;
  }

}

このクラスには2つの静的関数がありますが、どちらもユーティリティ関数であるかprepareDelta()、ユーティリティ関数でありmodulesList()、別のクラスに属していてサービスを持つ必要がありますか?

現時点で私が見つけた唯一の違いは、名前空間Drupal \ Component \ Utility(多くのユーティリティ機能が表示されます)内ではサービス内で使用せず、通常、サービスは内部で別のサービスを使用することです(私はしません)これを検証するためにすべてのサービスを確認してください)。

それで、サービスまたはユーティリティ関数をいつ作成する必要がありますか?


Slack DrupalのKen Rickard #contributeチャネルは、次のように述べています。
Adrian Cid Almaguer

それは私がユーティリティメソッドについて考えていたものですが、サービスについては、それがより重要であると思うことがあります。
Adrian Cid Almaguer 2017年

多くのことは、クラスが何をするか、そして操作するためにクラスが利用できるようにする必要があることに起因すると思います。Unicodeコアのクラスを取り上げます。これは依存関係がなく、状態を維持する必要がないため、サービスではなく静的ユーティリティクラスです。サービスの依存関係が必要な場合は、DIパターンでサービスに変換する必要があり、必要に応じてコンテナーからシングルトン(またはファクトリー生成)インスタンスを使用します。それ以外の場合はuse、それが理にかなっている場合は、静的クラスを使用できます。
クライブ

したがって、他のモジュール(または他の開発者)がそのコードと対話することを期待している場合は、サービスを作成します。それが事実ならUnicode、それは設計によるサービスであり、実際にそうである必要はありません。ユーティリティクラスは、いくつかの点で同じくらい簡単に、より簡単に、他のモジュールや独自のモジュール内の他のコードで使用できることを忘れないでください。しかし、それはすべて、開発者としてのあなた自身の見方/経験に依存します。それは主に常識に帰着し、難しい方法で学んだ
Clive

2
@NoSssweatしかしがUnicode あるだけの静的メソッドが含まれているDrupalのクラス!コア開発者がそれをサービスではなく静的クラスとして実装することを選択したという事実は、おそらくあなたは何かを意味しませんか?ユーティリティクラスは、その性質上、実際に上書きする必要はありません-いくつかのことを行いますが、それらが望んでいない場合は、代わりに独自のクラスを記述します。ユーティリティクラスに伝統的に存在する種類のものは、ワンショットの「私はこれで他に何もしない」タイプのメソッドであり、パラメータのセットを除いて入力を必要としないことを思い出してください
Clive

回答:


6

一般的な使用サービス。静的ユーティリティ関数を使用してもよい場合は、次のブログ投稿を参照してください。

静的を使用しないでください?

いいえ、有効なユースケースがあります。1つは、事前定義された項目のリストがある場合、静的ではインスタンスレベルではなくクラスレベルになるため、メモリの削減に役立つことです。

その他のケースは、外部の依存関係を必要としないユーティリティメソッドです(slugifyメソッドなど)。

<?php
class Util
{
    public static function slug($string)
    {
        return strtolower(trim(preg_replace('/[^A-Za-z0-9-]+/', '_', $string)));
    }
}

slugメソッドは、非常に明確に定義された動作のみを実行します。単体テストで動作を考慮に入れるのは簡単で、この呼び出しを見てもそれほど心配する必要はありません。

これらのメソッドは初期化を必要としないため、ユニットテストを行うこともできます。

ソース:https : //stovepipe.systems/post/avoiding-static-in-your-code

(現在Drupalにある静的コードの量は、手続き型D7コードからの移行によるものであるため、例として現在の状態でDrupalを使用しないでください。)


質問の例について、ユーティリティクラスの残りの部分(質問には表示されていません)

<?php

namespace Drupal\modules_weight\Utility;

/**
 * Provides module internal helper methods.
 *
 * @ingroup utility
 */
class InternalFunctions {

...

  /**
   * Return the modules list ordered by the modules weight.
   *
   * @param bool $force
   *   Force to show the core modules.
   *
   * @return array
   *   The modules list.
   */
  public static function modulesList($force = FALSE) {
    // If we don't force we need to check the configuration variable.
    if (!$force) {
      // Getting the config to know if we should show or not the core modules.
      $force = \Drupal::service('config.factory')->get('modules_weight.settings')->get('show_system_modules');
    }
    // Getting the modules list.
    $modules = \Drupal::service('modules_weight')->getModulesList($force);

    return $modules;
  }

}

静的ラッパーでモジュール独自のサービスを呼び出します。

\Drupal::service('modules_weight')

これはおそらく、ユーティリティクラスが従来の手続き型コードで使用されているためです。OOPコードではこれは必要ありません。ここではサービスを直接注入する必要があります。


答えてくれてありがとう。昨日、モジュールコードを少し変更し(いくつかのコミットを行ったため)、modules_weightサービスを作成しました。これは他のモジュールでも使用でき、現在は一般的なサービスなので、すべてのモジュールまたはコアモジュールのリストのみを取得できます。しかし、モジュールでは、このリストはshow_system_modules構成変数内の値の影響を受ける可能性があるため、この変数を受け取ってサービスを呼び出す別の関数を作成しましたが、あなたの答えを読むと、modulesList関数は静的ではないようです。
Adrian Cid Almaguer、2017年

この場合、modulesList関数はサービス内にある必要がありますか、または依存性注入を備えたコンストラクターを持つ別のクラスにある必要がありますか?
Adrian Cid Almaguer、2017年

あなたはそれを同じサービスに入れてgetModulesList()を保護されたメソッドとして宣言できると思います。
4k4、2017年

しかし、要点は、誰かがgetModuleList()を使用したい場合は不可能であり、modulesList()はモジュールにとってのみ重要な変数にアクセスできるということです。おそらく別のメソッドとしてmodulesList()を追加し、モジュール構成変数を使用する説明に追加しますか?
Adrian Cid Almaguer、2017年

2つのメソッドのうち1つだけを公開します。おそらく、デフォルト値を設定して、$force = NULL誰かが設定値をFALSEで上書きしたいかどうかを知ることができます。
4k4

8

Slack DrupalのKen Rickardの#contributeチャネルは、次のように述べています。

はい、サービスの優れた点は、誰でも上書きできることです。したがって、特定のコードをカスタマイズする機能を他の人に提供したい場合。既存のサービスの変更、動的サービスの提供を参照してください。

さらに、PHPユニットテストのモックテストを行う必要がある場合は、サービスにする必要があります。参照のDrupal 8でのサービスと依存性注入を、参照ユニットは、より複雑なDrupalのクラスをテストします

Q&A:

サービス単体テスト

別のクラスから静的メソッドを呼び出すメソッドの単体テストを作成する


ありがとう、あなたの答えに追加するいくつかの参照がありますか?
Adrian Cid Almaguer

@AdrianCidAlmaguerが追加されました。
Sssweatなし

1
おかげで、今、この参照は他のユーザー(そして私も)を助けることができます;-)
Adrian Cid Almaguer 2017年

モジュールの別のファイルで再び使用している場合は、サービスを作成する必要があります。同じモジュールで複数回使用されるユーティリティクラスを使用するよりも、サービスの方が便利(または優れた方法)なのはなぜですか。(明確にするために:私は議論していませんが、そのコンテキストに特に違いはないようです。サービスがより理にかなっていると思う理由を聞きたいです)
Clive

1
ええ、それは@NoSssweatという興味深いものです。IMOそれはDrupalやSymfonyよりも高いレベルの原則によって導かれます。私はあなたがあなたのコードに良い標準のクラス設計を適用し、その結果を、そのクラスにとって意味のある方法によって、その時点で使用しているフレームワークに組み込んだと思います
Clive
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.