如何做动作并获得返回值?


10

因此,存在以下情况。

我添加了一个从数据库中清除日志的操作:

add_action( 'myplugin_clean_logs', array( 'MyPlugin_Logs', 'clean_logs' ) );

现在,我想定期运行此操作:

wp_schedule_event( current_time( 'timestamp' ), 'daily', 'myplugin_clean_logs' );

并手动执行:

do_action( 'myplugin_clean_logs' );

该方法MyPlugin_Logs::clean_logs返回受影响的行的计数;如果其他方向相反,则返回false。

现在,我要显示已删除的行数。我会想象这样的事情:

$affected_rows = do_action( 'myplugin_clean_logs' );
echo $affected_rows . ' entries have been deleted.';

但是由于do_action不会返回任何值,因此我不知道如何获取返回值。

我是否应该在手动运行时直接执行该方法,但对计划事件使用操作?


1
您不想在计划的事件中回显任何内容,因此,是的,我将在手动运行时直接执行该方法(假设管理员会触发此操作,并且您想向他们显示输出)。
蒂姆·马隆

Answers:


13

很酷的一点是,过滤器与操作相同,只是它返回一个值,因此只需将其设置为过滤器即可:

add_filter( 'myplugin_clean_logs', array( 'MyPlugin_Logs', 'clean_logs' ) );

然后是这样的:

$affected_rows = '';
$affected_rows = apply_filters( 'myplugin_clean_logs', $affected_rows );

应该传递$affected_rowsclean_logs()(以及您可能已经迷上的任何其他函数myplugin_clean_logs)并将返回值分配回$affected_rows


4
被低估,因为这是黑客代码,而不是开发软件。如果动作只是过滤器的子集,那么就不需要它们了。Cron无法传递值,因此即使越野车核心代码允许您执行此类操作,也不应将其挂钩作为过滤器:)
Mark Kaplun

1
点了。我明白了这两种不同事物的意图,但是在这里看一下核心代码,整个do_action()过程无非是一个精心设计的技巧apply_filters():)
Caspar

并不是内核中唯一的不良设计,部分原因是导致混乱的问题,诸如此类的问题
Mark Kaplun 2016年

1
我们需要使用已有的东西,因此,尽管我了解Mark的观点,但我仍然认为这是一个合法的答案- 除非将来当然会改变核心方法,但由于大量的向后兼容性问题,我认为这种可能性不大它会引入。
蒂姆·马隆

3
谢谢@TimMalone。感谢@ mark-kaplun的反对。我的答案描述了如何解决do_action()不返回值的问题,而不是如何设计与do_action()意图一致的解决方案。如果某人能够做到他的要求,那么该答案就应该被接受。我的第一个想法是使用hooked方法(假设OP正在为此插件使用OOP设计)将其结果放入插件类的protected属性中,然后编写一个快速的getter以便稍后将其取出。但这只是个主意!
卡斯珀

-1

从未使用过此功能,也未测试过此功能,但是否可以使用? do_action_ref_array()

function myplugin_clean_logs_fn() {
    $args = array(
        'param1'        => 'val1',
        'param2'        => 'val2',
        'affected_rows' => 0,
    );
    do_action_ref_array( 'myplugin_clean_logs', &$args );
    return $args['affected_rows'];
}

// CALL IT
$affected_rows = my_plugin_clean_logs();
echo $affected_rows .' entr'. ($args['affected_rows']*1===1?'y':'ies') .' deleted.';

// SCHEDULE IT
add_action('myplugin_clean_logs_call_fn', 'myplugin_clean_logs_fn');
wp_schedule_event( current_time( 'timestamp' ), 'daily', 'myplugin_clean_logs_call_fn' );

// A SAMPLE FILTER
add_action('myplugin_clean_logs', function($args) {
    // Cleaning process
    // For each log affected, increment $args['affected_rows'] accordingly
}, 10, 3);

如果那行不通,为什么不过滤Caspar建议的内容呢?我的意思是,这就是过滤器的目的,在这种情况下,受影响的行数就是要过滤的东西。(我想念旧的MortCore。有人还记得它是如何通过仅一个三个参数函数来处理返回值,按引用传递和参数的吗?)


这是一个可怕的答案,因为通过引用传入和修改值确实是不好的做法。坦白说,这个答案在问题的上下文中确实没有提供任何价值,应该将其删除或更改为评论。另外,将匿名函数与挂钩一起使用也是一种不好的做法,因为这使它们无法取消挂钩。
Hybrid Web Dev

出于上述相同的原因,我同意这不是推荐的方法。如果您出于某种原因需要从某个操作中获取返回值,并且需要快速而又肮脏的东西,我希望使用Caspars解决方案。如果您正在开发某个具有生命周期超前的东西,那么我会寻找一种更可靠的方法。想到了,管理员通知又如何呢?developer.wordpress.org/reference/hooks/admin_notices
jgangso
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.