【问题标题】:Dynamic method definition in a class类中的动态方法定义
【发布时间】:2014-10-28 14:45:33
【问题描述】:

我正在尝试创建一个 PrestaShop 模块,该模块使用钩子触发 POST 请求。

钩子是这样调用的:

if(is_callable(array($moduleInstance, 'hook'.$hook_name)) {
    $moduleInstance->{'hook'.$hook_name}($hook_args);
}

意思是捕捉钩子事件我需要在类中随时可用的方法。所以假设我想调用一个名为myCustomEvent 的钩子,我需要以下内容:

class myModule extends Module {

    public function hookmyCustomEvent($params) {

    }

}

但是,我想要做的是将钩子事件列表存储在数据库中,并在调用钩子时触发它们。但要做到这一点,我需要在类中定义一个方法。我想做的是有一种“魔术”/通配符方法,可以从hook开始捕获它们。

这可能吗?

编辑:

这些方法不存在,因为我本质上希望它们被动态调用,执行另一个方法。

例子的真实代码:

public function hookactionValidateOrder($params) {
    $this->fireWebhook('actionValidateOrder', $params);
}

public function hookactionOrderStatusUpdate($params) {
    $this->fireWebhook('actionOrderStatusUpdate', $params);
}

public function hookactionUpdateQuantity($params) {
    $this->fireWebhook('actionUpdateQuantity', $params);
}

private function fireWebhook($event, $data) {
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, Configuration::get('HOOK_URL'));
    curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: application/json'));
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($ch, CURLOPT_POST, 1);
    curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([
        'event' => $event,
        'data' => $data
    ]));
    curl_exec($ch);
    curl_close($ch);
}

【问题讨论】:

  • 检查这个:php.net/manual/en/language.oop5.overloading.php#object.call 并查看__call() 方法。
  • 如果所有hook<restOfTheName>方法都存在,您可以使用method_exists($instance, 'hook'.$hookName)is_callable。您也可以使用__call 来捕获对不存在的方法的调用,但这不是一个很好的解决方案
  • 这些方法不存在,我基本上想调用一个方法来在调用其中一个方法时触发一个 POST 请求,从而创建一个 webhook。
  • @BenFortune:为什么不创建一个 doHook 方法,将钩子名称作为参数传递给它,在该 doHook 方法中使用 switch 并处理每个钩子名称因此?为什么要实现一个缓慢且容易出错的__call方法?
  • @EliasVanOotegem 我无法控制方法名称,它们是硬编码到 PrestaShop 中的预定义挂钩。我使用$this->registerHook('actionValidateOrder') 激活钩子并使用public function hookactionValidateOrder(){} 在我的模块中创建一个方法。 doHook 永远不会被调用。

标签: php


【解决方案1】:
public function __call($methodName, array $params) {
    if (substr($methodName, 0, 4) === 'hook') {
        // this matches something starting with "hook" so pull your instructions from the db here
    }
}

类似的东西可以匹配一个方法,而无需将它显式定义为类方法,我认为这是你的意图?

【讨论】:

  • 我想要这样的东西,我刚刚听说过依赖魔术方法的坏话,想知道是否有更好的方法。
  • 魔术方法不是一个很好的解决方案,我猜你会得到很多反身的“魔术方法不好”的回复,但考虑到你在问题中描述的限制,我不知道另一种方法来解决它。你不能重新设计底层技术,所以你必须适应它。如果您从头开始构建整个系统,那么您肯定希望找到一种比使用魔术方法更好的方法来实现它。
  • @BenFortune:听起来你在处理一个网络服务……难道没有你可以解析的 wsdl 吗?
  • @EliasVanOotegem 这不是网络服务,而是硬编码到 PrestaShop 中的类似事件的功能。假设有人下订单,它会触发一个事件/钩子,您可以“捕捉”并为其创建一个动作。在我的例子中,我创建了一个 POST 请求,我可以使用它来与我的后端服务同步。
【解决方案2】:

要对动态定义执行方法调用,请使用 call_user_funccall_user_func_array

call_user_func( array($moduleInstance, 'hook'.$hook_name) , $hook_args );

至于您要求执行以hook 开头的所有方法,我建议如下:

class MyModule
{
    /* ... */
    public function executeHooks()
    {
        $methods = get_class_methods($this);

        foreach ($methods as $method) {
            if (substr($method, 0, 4) == 'hook') {
                // Method is a hook
                call_user_func( array($this, $method) );
            }
        }

    }
    /* ... */
}

【讨论】:

  • getHooks() 永远不会被触发,因为每个单独的方法都会在钩子事件调用时触发。
  • 更新了初始化方法的答案:P
  • 这些方法不存在,我希望它们可以动态调用。我已经更新了 OP 以澄清。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-11-04
  • 1970-01-01
  • 2017-09-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多