Коли я повинен створити службу чи функцію утиліти?


11

Я мав на увазі це питання протягом усього останнього тижня: Коли я повинен створити службу чи функцію утиліти?

У Drupal Core у нас є і функції Служби, і Утиліта, але я не можу знайти їх різниці (коли мені потрібно створити службу або коли мені потрібно створити функцію утиліти).

Я візьму для прикладу модуль ваги модулів, де я маю клас InternalFunctions .

<?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 каже: "Я створив би сервіс, якщо ви очікуєте, що інші модулі (або інші розробники) взаємодіють із цим кодом. Корисні методи - це лише приватні ярлики для себе".
Адріан Сид Альмагюр

Це те, що я думав про корисні методи, але про послуги іноді думаю, що це більше питання.
Адріан Сид Алмагюр

Я думаю, що багато чого зводиться до того, що робить клас, і що йому потрібно зробити доступним для того, щоб діяти. Візьміть Unicodeклас в ядро ​​- це статичний клас корисності, а не сервіс, тому що він не має ніяких залежностей і не потребує підтримки будь-якого стану. Якщо для цього потрібна залежність від служби, шаблон DI вимагає перетворення її в службу, і ви використовуєте одноразовий (або фабрично створений) екземпляр з контейнера, коли вам це потрібно. В іншому випадку ви можете просто useстатичний клас, коли це має сенс.
Клайв

Як такий, я створив би сервіс, якщо ви очікуєте, що інші модулі (або інші розробники) взаємодіють із цим кодом , не відповідають мені. Якби це було так, це Unicodeбула б послуга за задумом, а цього насправді не потрібно. Не забувайте, що класи утиліти можуть так само легко, легше, в деяких відношеннях, використовуватися іншими модулями та іншим кодом у вашому власному модулі. Але все залежить від вашої власної точки зору / досвіду як розробника, воно здебільшого зводиться до здорового глузду, засвоєного важким шляхом
Клайв

2
@NoSssweat Але Unicode це клас Drupal, який містить лише статичні методи! Те, що основні розробники вирішили застосувати його як статичний клас, а не службу, ймовірно, означає щось, що ви не думаєте? Клас утиліти насправді не потрібно перезаписувати, за своєю природою - він робить деякі речі, якщо ці речі не такі, які ви хочете, ви замість цього пишете власний клас. Запам’ятайте такі речі, які традиційно живуть у класах корисних програм, - це одноразові методи, «я роблю це і нічого іншого», яким не потрібно введення, крім набору параметрів
Clive

Відповіді:


6

Послуги загального користування. Дивіться наступне повідомлення в блозі, коли нормально використовувати статичні функції утиліти:

Так ніколи не використовуйте статичну?

Ну ні, є дійсні випадки використання. Одне полягає в тому, що якщо у вас є список попередньо визначених елементів, статичні можуть допомогти зменшити пам'ять, оскільки він буде на рівні класу, а не в будь-яких випадках.

Інші випадки - це корисні методи, які не потребують зовнішніх залежностей, наприклад, слуховий метод.

<?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 це не обов'язково, тут вам слід ввести послугу безпосередньо.


Дякую за відповідь, вчора я трохи змінив код модуля (тому що я вніс деякі зобов'язання) і створив службу module_weight. У мене є сервіс, оскільки цим можуть користуватися інші модулі, і тепер це загальне, ви можете отримати всі модулі або лише список основних модулів. Але в модулі на цей список може впливати значення всередині змінної config_ show_system_modules, тому я зробив ще одну функцію, яка приймає цей var, а потім викликає служби, але читаючи вашу відповідь, здається, що функція moduleList не повинна стати статичною.
Адріан Сид Альмагюр

У цьому випадку ви маєте на увазі, що функція moduleList повинна знаходитися всередині сервісу або іншого класу з конструктором із введенням залежності?
Адріан Сид Альмагюр

Я думаю, ви можете помістити його в одну службу і оголосити getModulesList () як захищений метод.
4k4

але справа в тому, що якщо хтось хоче використовувати getModuleList (), це буде неможливо, і модуліListList () мають доступ до змінної, яка важлива лише для модуля. Можливо додавання модулівListList () як іншого методу та додавання в описі, що використовують змінну конфігурації модуля?
Адріан Сид Альмагюр

Я б оприлюднив лише один із двох методів. Можливо, ви можете встановити значення за замовчуванням $force = NULL, щоб ви знали, чи хтось хоче замінити значення конфігурації на FALSE.
4k4

8

Кен Рікард із каналу Slack Drupal #contribute каже: "Я створив би сервіс, якщо ви очікуєте, що інші модулі (або інші розробники) взаємодіють із цим кодом. Корисні методи - це лише приватні ярлики для себе".

Так, класна річ у сервісах - це те, що кожен може їх перезаписати. Тож якщо ви хочете надати іншим людям можливість налаштувати певний код. Див. Розділ Змінення існуючих послуг та надання динамічних послуг .

Крім того, вам слід зробити це послугою, якщо вам потрібно зробити Mock test для тестування модуля PHP. Див. Служби та введення залежності в Drupal 8 , див. Тестування блоку складніших класів Drupal .

Питання та відповіді:

Тест сервісного блоку

Написання одиничних тестів для методу, який викликає статичні методи з іншого класу


Дякую, чи є у вас кілька посилань, які слід додати до своєї відповіді?
Адріан Сид Альмагюр

@AdrianCidAlmaguer додано.
Без скидання

1
Дякую, тепер ця посилання може допомогти іншим користувачам (і мені теж) ;-)
Adrian Cid Almaguer

вам слід створити службу, якщо це щось, що ви знову бачите в різних файлах вашого модуля Чому послуга виявиться більш корисною (або кращою практикою), ніж мати клас утиліти, який кілька разів використовується в одному модулі? (для уточнення: я не сперечаюся, але, схоже, немає різниці в цьому контексті. Я хотів би почути, чому ви вважаєте, що служба має більше сенсу)
Клайв

1
Так, це цікавий @NoSssweat. IMO керується принципами вищого рівня, ніж Drupal або Symfony. Я думаю, ви застосуєте до свого коду гарний, стандартний, класний дизайн, а потім розмістіть результати в будь-якій структурі, яку ви використовуєте в той час, будь-яким методом, який має сенс для цього класу
Clive
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.