언제 서비스 또는 유틸리티 함수를 작성해야합니까?


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

}

이 클래스에는 두 개의 정적 함수가 있지만 둘 다 유틸리티 함수이거나 prepareDelta()유틸리티 함수이며 modulesList()다른 클래스에 있고 서비스가 있어야합니까?

이 시점에서 내가 찾은 유일한 차이점은 네임 스페이스 Drupal \ Component \ Utility (많은 유틸리티 기능을 볼 수 있음) 내부에서 서비스 내부에서 사용하지 않으며 일반적으로 서비스 내부에서 다른 서비스를 사용하지 않는다는 것입니다. 이를 확인하기 위해 모든 서비스를 검토하십시오).

그렇다면 서비스 또는 유틸리티 기능을 만들어야 할 때?


Slack Drupal #contribute 채널의 Ken Rickard는 "다른 모듈 (또는 다른 개발자)이 해당 코드와 상호 작용할 것으로 예상되면 서비스를 만들 것입니다. 유틸리티 메서드는 개인용 바로 가기입니다."
Adrian Cid Almaguer

그것이 유틸리티 방법에 대해 생각한 것이지만 때로는 서비스에 대해 더 고려할 필요가 있다고 생각합니다.
Adrian Cid Almaguer

수업이하는 일과 운영하기 위해 필요한 것이 무엇인지에 대해 많은 생각이 듭니다. Unicode클래스를 코어로 가져 가십시오. 의존성이 없으며 상태를 유지할 필요가 없기 때문에 서비스가 아닌 정적 유틸리티 클래스입니다. 서비스 종속성이 필요한 경우 DI 패턴은 서비스로 변환해야하며 필요할 때 컨테이너에서 싱글 톤 (또는 팩토리 생성) 인스턴스를 사용해야합니다. 그렇지 않으면 use의미가있을 때 정적 클래스 만 사용할 수 있습니다 .
Clive

따라서 다른 모듈 (또는 다른 개발자)이 해당 코드와 상호 작용할 것으로 기대되는 경우 서비스를 만들 것입니다. 이 경우 Unicode설계 상 서비스가되며 실제로는 그럴 필요가 없습니다. 유틸리티 클래스는 다른 모듈과 다른 모듈에서 자신의 모듈에 쉽게 사용할 수 있다는 점을 잊지 마십시오. 그러나 모든 것은 개발자로서 자신의 관점 / 경험에 달려 있습니다. 대부분 어려운 상식을
Clive

2
@NoSssweat 그러나이 Unicode 있다 정적 메소드를 포함하는 드루팔 클래스! 핵심 개발자가 서비스가 아닌 정적 클래스로 구현하기로 선택한 사실은 아마도 당신이 생각하지 않는 것을 의미합니까? 유틸리티 클래스는 본질적으로 본질적으로 덮어 쓸 필요가 없습니다. 원하는 것들이 아닌 경우, 클래스를 직접 작성하십시오. 유틸리티 클래스에 전통적으로 존재하는 것은 일종의 매개 변수 인 "입력하지 않아도됩니다"라는 매개 변수 유형을 기억하십시오
Clive

답변:


6

일반적으로 서비스를 사용하십시오. 정적 유틸리티 기능을 사용할 수 있으면 다음 블로그 게시물을 참조하십시오.

정적을 사용하지 않습니까?

글쎄, 유효한 사용 사례가 있습니다. 하나는 사전 정의 된 항목 목록이있는 경우 static은 메모리가 클래스 레벨에 있고 어떤 인스턴스도 아니기 때문에 메모리를 줄이는 데 도움이 될 수 있다는 것입니다.

다른 경우에는 외부 의존성이 필요하지 않은 유틸리티 메소드 (예 : slugify 메소드)가 있습니다.

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

슬러그 방법은 매우 잘 정의 된 동작 만 수행합니다. 단위 테스트에서 동작을 고려하는 것은 쉽지만이 호출을 볼 때 너무 걱정하지 않아도됩니다.

이 방법들은 초기화가 필요하지 않기 때문에 단위 테스트도 가능합니다.

출처 : 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 구성 변수의 값에 영향을받을 수 있으므로이 var를 가져 와서 서비스를 호출하는 다른 함수를 만들었지 만 답변을 읽으면 modulesList 함수가 정적이 아닌 것처럼 보입니다.
Adrian Cid Almaguer

이 경우 modulesList 함수가 서비스 또는 종속성 주입을 가진 생성자를 가진 다른 클래스에 있어야합니까?
Adrian Cid Almaguer

동일한 서비스에 넣고 getModulesList ()를 보호 된 메소드로 선언 할 수 있다고 생각합니다.
4k4

그러나 요점은 누군가 getModuleList ()를 사용하려는 경우 가능하지 않으며 modulesList ()는 모듈에만 중요한 변수에 액세스 할 수 있다는 것입니다. 다른 방법으로 modulesList ()를 추가하고 모듈 구성 변수를 사용하는 설명을 추가 할 수 있습니까?
Adrian Cid Almaguer

두 방법 중 하나만 공개합니다. $force = NULL다른 사람이 구성 값을 FALSE로 대체할지 여부를 알 수 있도록 기본값을 설정할 수 있습니다 .
4k4

8

Slack Drupal #contribute 채널의 Ken Rickard는 "다른 모듈 (또는 다른 개발자)이 해당 코드와 상호 작용할 것으로 예상되면 서비스를 만들 것입니다. 유틸리티 메서드는 개인용 바로 가기입니다."

예, 서비스에 대한 멋진 점은 누구나 서비스를 덮어 쓸 수 있다는 것입니다. 따라서 다른 사람에게 특정 코드를 사용자 정의 할 수있는 기능을 제공하려는 경우. 기존 서비스 변경, 동적 서비스 제공을 참조하십시오 .

또한 PHP 단위 테스트를 위해 모의 테스트를 수행해야하는 경우 서비스로 만들어야합니다. 참조 드루팔 8 서비스 및 의존성 주입을 참조 단위가 더 복잡 드루팔 클래스를 테스트 .

Q & A :

서비스 유닛 테스트

다른 클래스에서 정적 메소드를 호출하는 메소드에 대한 단위 테스트 작성


감사합니다. 답변에 추가 할 내용이 있습니까?
Adrian Cid Almaguer

@AdrianCidAlmaguer가 추가되었습니다.
No Sssweat

1
고마워, 이제이 참조는 다른 사용자 (나도)에 도움이 될 수 있습니다 ;-)
Adrian Cid Almaguer

서비스를 모듈의 다른 파일에서 다시 사용하는 것으로 보이는 경우 서비스를 만들어야합니다 . 동일한 모듈에서 여러 번 사용되는 유틸리티 클래스를 갖는 것보다 서비스가 더 유용한 이유는 무엇입니까? (설명하기 위해 : 나는 논쟁의 여지가 없지만, 그 맥락에서 특별히 차이가없는 것 같습니다. 왜 당신이 서비스가 더 합리적이라고 생각하는지 듣고 싶습니다.)
Clive

1
네, @NoSssweat가 흥미 롭습니다. IMO는 Drupal 또는 Symfony보다 높은 수준의 원칙에 따라 진행됩니다. 좋은 표준 클래스 디자인을 코드에 적용한 다음 해당 클래스에 적합한 방법으로 해당 시점에 사용중인 프레임 워크에 결과를 슬롯에 넣습니다.
Clive
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.