7부 – WordPress 및 객체 지향 프로그래밍: WordPress 예제 – 구현: WordPress 후크 관리

게시 됨: 2022-02-04

지금까지는 Plugin API와 상호작용한다는 것은 각 클래스의 생성자에서 add_action add_action() , add_filters() 를 호출하는 것을 의미했다.

지금까지 이 접근 방식은 작업을 단순하게 유지하고 WordPress를 사용한 객체 지향 프로그래밍에 대해 더 많이 배우는 데 집중할 수 있게 해주었기 때문에 충분히 좋았습니다. 그러나 이상적이지는 않습니다.

객체가 생성될 때 모든 후크를 등록하면 단위 테스트와 같은 작업이 까다로워집니다.

참고: 단위 테스트는 각 "단위"를 개별적으로 테스트해야 합니다. 현재 단위 테스트를 작성하지 않더라도 테스트 가능한 코드를 작성하면 테스트를 작성하기로 결정한 경우 나중에 리팩토링하는 시간을 많이 절약할 수 있습니다.

후크 관리자

여기서 한 단계 더 나아가 후크를 관리하기 위한 새 클래스를 도입하겠습니다. Hooks_Manager 라고 부를 것입니다. 이 클래스는 모든 후크의 등록을 담당할 것입니다. 따라서 register() 메서드를 사용하여 새 클래스를 만듭니다.

 class Hooks_Manager { /** * Register the hooks of the given object. * * @param object $object */ public function register( $object ) { // Register the hooks the specified object needs } }

구현하기 위해 후크를 등록해야 하는 각 클래스에 대한 인터페이스가 필요합니다.

 interface Hooks { /** * Return the actions to register. * * @return array */ public function get_actions(); }

인터페이스를 계약 으로 생각할 수 있습니다. 여기서 해당 인터페이스를 구현하는 클래스는 해당 인터페이스에 정의된 모든 메서드를 구현하도록 "계약적으로 바인딩"됩니다.

예를 들어, login_head 작업에 연결되는 Login_Error 클래스는 Hooks 인터페이스의 get_actions() 메서드를 구현 해야 합니다 .

 class Login_Error implements Hooks { public function get_actions() { return array( 'login_head' => array( 'add_errors', 10, 1 ), ); } }

Hooks_Managerregister() 메서드는 객체를 받아들이고 get_actions() 메서드를 호출하고 모든 작업을 등록합니다.

 public function register( $object ) { $actions = $object->get_actions(); foreach ( $actions as $action_name => $action_details ) { $method = $action_details[0]; $priority = $action_details[1]; $accepted_args = $action_details[2]; add_action( $action_name, array( $object, $method ), $priority, $accepted_args ); } }

액션과 필터를 모두 등록할 수 있도록 get_filters() 메서드를 인터페이스에 추가해 보겠습니다.

 interface Hooks { /** * Return the actions to register. * * @return array */ public function get_actions(); /** * Return the filters to register. * * @return array */ public function get_filters(); }

Login_Error 클래스로 돌아가서 이 새로운 get_filters() 메서드를 구현해야 합니다.

 class Login_Error implements Hooks { public function get_actions() { return array( 'login_head' => array( 'add_errors', 10, 1 ), ); } public function get_filters() { return array( 'authenticate' => array( 'track_credentials', 10, 3 ), 'shake_error_code' => array( 'add_error_code', 10, 1 ), 'login_errors' => array( 'format_error_message', 10, 1 ), ); } }

Hooks_Managerregister() 메소드 이름을 register_actions register_actions() ) 로 바꿀 것입니다. 또한 register_filters() 메서드를 추가합니다. 이 두 가지 방법은 각각 작업과 필터를 등록하는 역할을 합니다.

 class Hooks_Manager { /** * Register the actions of the given object. * * @param object $object */ private function register_actions( $object ) { $actions = $object->get_actions(); foreach ( $actions as $action_name => $action_details ) { $method = $action_details[0]; $priority = $action_details[1]; $accepted_args = $action_details[2]; add_action( $action_name, array( $object, $method ), $priority, $accepted_args ); } } /** * Register the filters of the given object. * * @param object $object */ private function register_filters( $object ) { $filters = $object->get_filters(); foreach ( $filters as $filter_name => $filter_details ) { $method = $filter_details[0]; $priority = $filter_details[1]; $accepted_args = $filter_details[2]; add_filter( $filter_name, array( $object, $method ), $priority, $accepted_args ); } } }

이제 register() 메서드를 다시 추가할 수 있습니다. 이 메서드는 단순히 register_actions()register_filters() ) 를 모두 호출합니다.

 class Hooks_Manager { /** * Register an object. * * @param object $object */ public function register( $object ) { $this->register_actions( $object ); $this->register_filters( $object ); } // ...

클래스가 액션과 필터를 모두 등록할 필요가 없다면 어떻게 될까요? Hooks 인터페이스에는 get_actions()get_filters() ) 의 두 가지 메서드가 있습니다. 해당 인터페이스를 구현하는 모든 클래스는 메서드를 모두 구현해야 합니다.

 class Cookie_Login implements Hooks { public function get_actions() { return array( 'auth_cookie_bad_username' => array( 'handle_bad_username', 10, 1 ), 'auth_cookie_bad_hash' => array( 'handle_bad_hash', 10, 1 ), 'auth_cookie_valid' => array( 'handle_valid', 10, 2 ), ); } public function get_filters() { return array(); } }

예를 들어 Cookie_Login 클래스는 작업만 등록해야 하지만 이제는 빈 배열을 반환하기 위해 get_filters() 메서드를 구현해야 합니다.

인터페이스 분리 원칙(ISP) , SOLID의 "I"는 다음과 같이 명시합니다.

"어떤 클라이언트도 사용하지 않는 방법에 의존하도록 강요받아서는 안 됩니다."

우리가 지금 하고 있는 일이 정확히 해서는 안 되는 일이라는 의미입니다.

인터페이스 분리

인터페이스를 더 작고 더 구체적인 것으로 분할하여 이 문제를 해결할 수 있으므로 클래스는 관심 있는 메서드만 알면 됩니다.

 interface Actions { /** * Return the actions to register. * * @return array */ public function get_actions(); }
 interface Filters { /** * Return the filters to register. * * @return array */ public function get_filters(); }

get_actions()get_filters() 는 더 이상 필요하지 않습니다. Actions 인터페이스만 구현하고 get_filters() 를 제거할 수 있습니다.

 class Cookie_Login implements Actions { public function get_actions() { return array( 'auth_cookie_bad_username' => array( 'handle_bad_username', 10, 1 ), 'auth_cookie_bad_hash' => array( 'handle_bad_hash', 10, 1 ), 'auth_cookie_valid' => array( 'handle_valid', 10, 2 ), ); } }

반면에 조치 필터가 필요한 Login_Error 는 두 인터페이스를 모두 구현하기만 하면 됩니다. 클래스는 쉼표로 구분하여 둘 이상의 인터페이스를 구현할 수 있습니다.

 class Login_Error implements Actions, Filters { public function get_actions() { return array( 'login_head' => array( 'add_errors', 10, 1 ), ); } public function get_filters() { return array( 'authenticate' => array( 'track_credentials', 10, 3 ), 'shake_error_code' => array( 'add_error_code', 10, 1 ), 'login_errors' => array( 'format_error_message', 10, 1 ), ); } }

이제 인터페이스를 분리 Hooks_Managerregister() 메서드를 업데이트하여 변경 사항을 반영하기만 하면 됩니다.

 class Hooks_Manager { /** * Register an object. * * @param object $object */ public function register( $object ) { if ( $object instanceof Actions ) { $this->register_actions( $object ); } if ( $object instanceof Filters ) { $this->register_filters( $object ); } } // ...

그렇게 하면 지정된 객체가 구현하는 인터페이스를 기반으로 조건부로 register_actions() 만, register_filters() 만 또는 둘 다 호출합니다.

실제로 후크 관리자를 사용하려면:

 $hooks_manager = new Hooks_Manager(); $hooks_manager->register( $login_error ); $hooks_manager->register( $cookie_login );

그게 다야! 이제 해당 개체를 사용하여 전체 코드베이스에서 후크를 관리할 수 있습니다.

결론

물론 객체 지향 방식으로 후크를 관리하는 방법에는 여러 가지가 있으며 그 중 하나만 보여 드렸습니다. 실험하고 필요에 맞는 것을 찾아야 합니다.

이 시리즈의 마지막 부분에서는 객체 지향 방식으로 옵션을 처리하는 방법, 캡슐화, 추상화 및 확장하기 쉬운 유연한 플러그인을 만들기 위해 클래스를 분리하는 방법에 대해 설명합니다.

객체 지향 프로그래밍 시리즈의 8부를 읽으려면 여기를 클릭하십시오.

또한보십시오

  • WordPress 및 객체 지향 프로그래밍 – 개요
  • 2부 – WordPress와 객체 지향 프로그래밍: 실제 사례
  • 3부 – WordPress 및 객체 지향 프로그래밍: Α WordPress 예제 – 범위 정의
  • 4부 – WordPress 및 객체 지향 프로그래밍: WordPress 예제 – 디자인
  • 5부 – WordPress 및 객체 지향 프로그래밍: WordPress 예제 – 구현: 관리 메뉴
  • 6부 – WordPress 및 객체 지향 프로그래밍: WordPress 예제 – 구현: 섹션 등록