How to Realize Hook Mechanism in PHP

  • 2021-08-12 02:20:12
  • OfStack

I'm not familiar with the concept of "hook". I recently saw an php framework using this mechanism to extend the project, so I'll take a look at it.

The so-called Hook mechanism is a popular technology from Windows programming. The main idea is to bury (preset) a hook in advance where functions may be added. This hook has no practical significance. When we need to modify or add the logic of this place, we can mount the extended class or method to this point.

The basic idea of hook plug-in mechanism:

In the project code, where you think you want to extend (not extend for the time being), place a hook function, and when you need to extend it, mount the classes and functions that need to be implemented on this hook, and you can realize the extension.

This is the idea. It sounds general. Look at an example of online implementation.

The whole plug-in mechanism consists of three parts:

1. hook plug-in manager class: This is the core file and is an application global Global object. It has three main responsibilities

1 > Listen for all registered plug-ins and instantiate these plug-in objects.

2 > Register all plug-ins.

3 > When the hook condition is met, the corresponding object method is triggered.

2. Functional implementation of plug-ins: This is mostly done by third-party developers, but it needs to follow our (manager class definition) rules, which are stipulated by plug-in mechanisms and vary from plug-in mechanism to plug-in mechanism.

3. Plug-in trigger: That is, the trigger condition of hook. This is a small piece of code, which is placed where you need to call the plug-in to trigger this hook.

-------------------------------------

The first is the plug-in manager class PluginManager, which should be placed in the global reference and loaded first in all places where plug-ins are needed.


<?php
/**
*
*  Implementation core class of plug-in mechanism 

*/
class PluginManager
{
  /**
   *  Listen for registered plug-ins 
   *
   * @access private
   * @var array
   */
  private $_listeners = array();
   /**
   *  Constructor 
   *
   * @access public
   * @return void
   */
  public function __construct()
  {
    # Here $plugin The array contains information about the plug-ins that we retrieve have been activated by the user 
   # For the convenience of demonstration, we assume that $plugin Include at least 
   #$plugin = array(
    #  'name' => ' Plug-in name ',
    #  'directory'=>' Plug-in installation directory '
    #);
    $plugins = get_active_plugins();# Please implement this function by yourself 
    if($plugins)
    {
      foreach($plugins as $plugin)
      {// Assume that each plug-in folder contains 1 A actions.php File, which is the concrete implementation of the plug-in 
        if (@file_exists(STPATH .'plugins/'.$plugin['directory'].'/actions.php'))
        {
          include_once(STPATH .'plugins/'.$plugin['directory'].'/actions.php');
          $class = $plugin['name'].'_actions';
          if (class_exists($class))
          {
            // Initialize all plug-ins 
            new $class($this);
          }
        }
      }
    }
    # Do something about logging here 
  }

  /**
   *  Register plug-in methods (hooks) that need to be listened to 
   *
   * @param string $hook
   * @param object $reference
   * @param string $method
   */
  function register($hook, &$reference, $method)
  {
    // Gets the method to be implemented by the plug-in 
    $key = get_class($reference).'->'.$method;
    // Add a reference to a plug-in along with a method push Enter the listening array 
    $this->_listeners[$hook][$key] = array(&$reference, $method);
    # Do something about logging here 
  }
  /**
   *  Trigger 1 A hook 
   *
   * @param string $hook  The name of the hook 
   * @param mixed $data  Entry of hook 
   *  @return mixed
   */
  function trigger($hook, $data='')
  {
    $result = '';
    // Check whether the hook to be implemented is in the listening array 
    if (isset($this->_listeners[$hook]) && is_array($this->_listeners[$hook]) && count($this->_listeners[$hook]) > 0)
    {
      //  Loop call starts 
      foreach ($this->_listeners[$hook] as $listener)
      {
        //  Fetch the reference and method of plug-in object 
        $class =& $listener[0];
        $method = $listener[1];
        if(method_exists($class,$method))
        {
          //  Methods of calling plug-ins dynamically 
          $result .= $class->$method($data);
        }
      }
    }
    # Do something about logging here 
    return $result;
  }
}

Next is the implementation of a simple plug-in, DEMO_actions. This is a simple Hello World plug-in to output a sentence. In practice, say_hello may include operations on the database, or some other specific logic.


<?php
/**
*  This is 1 A Hello World Implementation of Simple Plug-in 
*/
/**
* Several default rules to note: 
*  1.  The file name of this plug-in class must be action
*  2.  The name of the plug-in class must be { Plug-in name _actions}
*/
class DEMO_actions
{
  // The parameters of the analytic function are pluginManager Reference to 
  function __construct(&$pluginManager)
  {
    // Register this plug-in 
    // No. 1 1 The parameter is the name of the hook 
    // No. 1 2 The parameters are pluginManager Reference to 
    // No. 1 3 Is the method executed by the plug-in 
    $pluginManager->register('demo', $this, 'say_hello');
  }

  function say_hello()
  {
    echo 'Hello World';
  }
}

Then there is where the plug-in call is triggered. For example, if I want to put say_hello on the front page of my blog, Index.php, then you write somewhere in index.php:


$pluginManager->trigger('demo','');

The first parameter represents the name of the hook, and the second parameter is the entry parameter of the corresponding method of the plug-in, which is empty because there is no input parameter in this example.

Such an example basically clearly expresses the implementation mode and logic of the "hook" plug-in mechanism.


Related articles: