PHP使用私有方法作为回调

Sil*_*cer 4 php wordpress private callback wordpress-plugin

我是第一次尝试PHP + WP。我打算使用WP插件挂钩。作为C ++程序员,我还打算将所有代码放入类中。目前,我有点受以下应该安装WP插件挂钩的代码段的困扰:

   class SettingsHandler
   {
      public function __construct()
      {
         add_filter('plugin_action_links', array($this, 'AddSettingsLink'), 10, 2);
      }

      private function AddSettingsLink($links, $file)
      {
         if ($file==plugin_basename(__FILE__))
         {
            $settings_link = '<a href="options-general.php?page=options_page">Settings</a>';
            array_unshift($links, $settings_link);
         }       
         return $links;
      }
   }

   $settingsHandler = new SettingsHandler();
Run Code Online (Sandbox Code Playgroud)

这给我一个错误消息:警告:call_user_func_array()期望参数1是有效的回调,无法访问E:\ xampp \ apps \ wordpress \ htdocs \ wp-includes \ plugin.php中的私有方法SettingsHandler :: AddSettingsLink() 199行

当我将回调切换为public时,错误消失了。似乎我不能使用私有方法作为PHP / WP中的回调。这将是非常糟糕的,因为它揭示了许多不应被其他任何人直接访问的回调方法。我可以将此类回调设为私有吗?

我还发现了以下运行良好的代码段:

   class a
   {
      public function __construct()
      {
         $str = " test test ";
         $result = preg_replace_callback('/test/', array($this, 'callback'), $str);
         echo $result;
      } 

      private function callback($m)
      {
         return 'replaced';
      }
   }

   $a = new a();
Run Code Online (Sandbox Code Playgroud)

为什么第二个片段在第一个片段失败的同时起作用?区别在哪里?

Gor*_*don 5

第二个版本有效,因为preg_match_all是从类范围内调用的,并且将立即执行回调。

但是add_filter函数仅将回调添加到全局$wp_filter数组。然后,在稍后阶段从定义方法的类外部调用该数组中的回调。因此,应用了可见性规则,使得无法访问该回调。

您可以通过将对方法的调用包装到匿名函数中来解决此问题,例如

public function __construct()
{
    add_filter(
        'plugin_action_links',
        function($links, $file) {
            return $this->AddSettingsLink($links, $file);
        },
        10,
        2
    );
}
Run Code Online (Sandbox Code Playgroud)

但是,由于$this该版本之前的匿名函数不可用,因此至少需要PHP 5.4(请参见手册中的changelog)。

另一个选择是让SettingsHandler工具__invoke将其变成Functor,例如,添加

public function __invoke($links, $file)
{
    return $this->AddSettingsLink($links, $file);
}
Run Code Online (Sandbox Code Playgroud)

并将ctor代码更改为

add_filter('plugin_action_links', $this, 10, 2);
Run Code Online (Sandbox Code Playgroud)

由于该类实现__invoke为公共入口点,因此该实例可用作回调。这样,您可以将私有内容保持私有。

附带说明一下,我将代码添加到类之外的过滤器中。将它放在ctor中会使该类的测试性较差(是的,我知道没有人测试WP插件,但仍然可以)。相反,将其放入您的插件文件中,然后从那里包含所有其他要求的内容,例如

// your-plugin.php
include 'SettingsHandler.php';
add_filter('plugin_action_links', new SettingsHandler, 10, 2);
Run Code Online (Sandbox Code Playgroud)

但这取决于你。

¹ 注意:显然,这在Wordpress中不起作用,因为它将尝试在此过程中的某个位置序列化闭包。通常,这是一种提供私有方法作为回调的工作模式。