เมื่อใดที่ฉันควรสร้างบริการหรือฟังก์ชั่นยูทิลิตี้


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 ในเนมสเปซ (ที่คุณจะเห็นยูทิลิตี้จำนวนมาก fucntions) พวกเขาไม่ได้ใช้บริการใดบริการหนึ่งและมักจะใช้บริการอื่นในบริการ มีการตรวจสอบบริการทั้งหมดเพื่อตรวจสอบนี้)

ดังนั้นเมื่อฉันควรสร้างบริการหรือฟังก์ชั่นยูทิลิตี้?


Ken Rickard จาก Slack Drupal #contribute channel กล่าวว่า: "ฉันจะสร้างบริการหากคุณคาดว่าโมดูลอื่น ๆ (หรือนักพัฒนาอื่น ๆ ) จะโต้ตอบกับรหัสนั้นวิธีการใช้งานยูทิลิตี้เป็นเพียงทางลัดส่วนตัวสำหรับตัวคุณเอง"
Adrian Cid Almaguer

นั่นคือสิ่งที่ฉันคิดเกี่ยวกับวิธีการยูทิลิตี้ แต่สำหรับบริการบางครั้งฉันคิดว่ามันเป็นเรื่องที่ต้องพิจารณา
Adrian Cid Almaguer

ฉันคิดว่ามันลงมามากกับสิ่งที่ชั้นเรียนทำและสิ่งที่จำเป็นต้องทำให้ว่างเพื่อให้สามารถใช้งานได้ ใช้Unicodeคลาสเป็นหลัก - นั่นคือคลาสยูทิลิตี้สแตติกไม่ใช่บริการเพราะมันไม่มีการอ้างอิงใด ๆ และไม่จำเป็นต้องบำรุงรักษาสถานะใด ๆ หากต้องการการพึ่งพาบริการรูปแบบ DI จะต้องการให้แปลงเป็นบริการและคุณต้องการใช้อินสแตนซ์ซิงเกิล (หรือสร้างจากโรงงาน) จากคอนเทนเนอร์เมื่อคุณต้องการ มิฉะนั้นคุณสามารถuseคลาสคงที่เมื่อมันทำให้รู้สึก
ไคลฟ์

เช่นนี้ฉันจะสร้างบริการหากคุณคาดหวังว่าโมดูลอื่น ๆ (หรือนักพัฒนาอื่น ๆ ) ในการโต้ตอบกับรหัสนั้นไม่ได้ส่งเสียงจริงกับฉัน ถ้าเป็นเช่นนั้นUnicodeจะเป็นการบริการโดยการออกแบบและไม่จำเป็นต้องเป็น อย่าลืมคลาสยูทิลิตี้ที่สามารถทำได้ง่ายขึ้นได้ง่ายขึ้นในบางประเด็นใช้โมดูลอื่นและรหัสอื่นในโมดูลของคุณเอง แต่ทุกอย่างขึ้นอยู่กับมุมมอง / ประสบการณ์ของคุณในฐานะนักพัฒนาส่วนใหญ่มันจะลงมาสู่สามัญสำนึกที่เรียนรู้วิธีที่ยากลำบาก
Clive

2
@NosSsweat แต่Unicode เป็นคลาส Drupal ที่มีเพียงวิธีคงที่! ความจริงที่ว่า core devs เลือกที่จะใช้มันเป็นคลาสแบบสแตติกแทนที่จะให้บริการอาจหมายถึงบางสิ่งที่คุณไม่คิด? คลาสยูทิลิตี้ไม่จำเป็นต้องถูกเขียนทับโดยธรรมชาติ - มันทำบางสิ่งถ้าสิ่งเหล่านั้นไม่ใช่สิ่งที่คุณต้องการคุณเขียนคลาสของคุณเองแทน โปรดจำไว้ว่าสิ่งต่าง ๆ ที่อาศัยอยู่ในคลาสยูทิลิตี้เป็นแบบ one-shot, "ฉันทำอย่างนี้และไม่มีอะไรอื่น" ประเภทของวิธีการที่ไม่จำเป็นต้องป้อนข้อมูลยกเว้นชุดของพารามิเตอร์
Clive

คำตอบ:


6

ในการใช้บริการทั่วไป ดูโพสต์บล็อกต่อไปนี้เมื่อตกลงเพื่อใช้ฟังก์ชันยูทิลิตี้คงที่:

ดังนั้นอย่าใช้สถิต?

ไม่มีกรณีการใช้งานที่ถูกต้อง หนึ่งคือถ้าคุณมีรายการของรายการที่กำหนดไว้ล่วงหน้าคงที่สามารถช่วยลดหน่วยความจำเพราะมันจะอยู่ในระดับชั้นเรียนและไม่ได้อยู่ในกรณีใด ๆ

กรณีอื่น ๆ เป็นวิธีการอรรถประโยชน์ที่ไม่ต้องการการพึ่งพาจากภายนอกเช่นวิธีการ 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;
  }

}

เรียกใช้บริการของโมดูลเองใน static wrapper:

\Drupal::service('modules_weight')

นี่อาจเป็นเพราะคลาสยูทิลิตี้ถูกใช้ในรหัสขั้นตอนดั้งเดิม ในรหัส OOP นี้ไม่จำเป็นที่นี่คุณควรฉีดบริการโดยตรง


ขอบคุณสำหรับคำตอบเมื่อวานนี้ฉันเปลี่ยนรหัสโมดูลเล็กน้อย (เพราะฉันทำบางอย่าง) และฉันสร้างบริการ modules_weight ฉันมีบริการเพราะโมดูลนี้สามารถใช้งานได้โดยผู้อื่นและตอนนี้เป็นทั่วไปคุณสามารถรับโมดูลทั้งหมดหรือเฉพาะรายการโมดูลหลัก แต่ในโมดูลรายการนี้อาจได้รับผลกระทบจากค่าที่อยู่ในตัวแปร config ของ 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

Ken Rickard จาก Slack Drupal #contribute channel กล่าวว่า: "ฉันจะสร้างบริการหากคุณคาดว่าโมดูลอื่น ๆ (หรือผู้พัฒนารายอื่น) ในการโต้ตอบกับรหัสนั้นวิธีการอรรถประโยชน์เป็นเพียงทางลัดส่วนตัวสำหรับตัวคุณเอง"

ใช่สิ่งดีๆเกี่ยวกับบริการคือทุกคนสามารถเขียนทับพวกเขาได้ ดังนั้นหากคุณต้องการให้ผู้อื่นสามารถปรับแต่งโค้ดเฉพาะชิ้นส่วนได้ ดูการดัดแปลงบริการที่มีอยู่ให้บริการแบบไดนามิก

นอกจากนี้คุณควรให้บริการถ้าคุณจำเป็นต้องทำการทดสอบจำลองสำหรับการทดสอบหน่วย PHP ดูการบริการและการฉีดอยู่ใน Drupal 8ดูหน่วยการทดสอบที่มีความซับซ้อนมากขึ้นเรียน Drupal

ถาม & ตอบ:

ทดสอบหน่วยบริการ

การเขียนการทดสอบหน่วยสำหรับวิธีการที่เรียกใช้วิธีการคงที่จากคลาสอื่น


ขอบคุณคุณมีข้อมูลอ้างอิงเพื่อเพิ่มคำตอบของคุณหรือไม่
Adrian Cid Almaguer

@AdrianCidAlmaguer เพิ่ม
ไม่มี Sssweat

1
ขอบคุณตอนนี้การอ้างอิงนี้สามารถช่วยผู้ใช้คนอื่น (และฉันด้วย) ;-)
Adrian Cid Almaguer

คุณควรสร้างบริการถ้ามันเป็นสิ่งที่คุณเห็นว่าคุณใช้อีกครั้งในไฟล์ต่าง ๆ ในโมดูลของคุณเหตุใดบริการจึงมีประโยชน์มากกว่า (หรือมีแนวปฏิบัติที่ดีกว่า) กว่ามีคลาสยูทิลิตี้ที่ใช้หลายครั้งในโมดูลเดียวกัน (เพื่อชี้แจง: ฉันไม่ได้โต้เถียง แต่ดูเหมือนจะไม่มีความแตกต่างในบริบทนั้นโดยเฉพาะฉันชอบที่จะได้ยินว่าทำไมคุณคิดว่าการบริการมีเหตุผลมากกว่านี้)
Clive

1
ใช่มันเป็น @NoSssweat ที่น่าสนใจ IMO นำโดยหลักการระดับสูงกว่า Drupal หรือ Symfony ฉันคิดว่าคุณใช้การออกแบบคลาสที่ดีมาตรฐานกับโค้ดของคุณจากนั้นเสียบผลลัพธ์ลงในเฟรมเวิร์กที่คุณใช้ในขณะนั้นด้วยวิธีใดก็ตามที่เหมาะสมกับคลาสนั้น
Clive
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.