实现 Hooks、add_filter 和 apply_filters

时间:2021-01-16 14:35:00

标签: php

所以我尝试制作一个像 wordpress add_filter 和 apply_filters 这样的挂钩 API, 所以这是我的实现

我的问题是 apply_filters 没有过滤钩子

    $hook = new Hook();

    $hook->add_filter('filter',function($test) {
        return ' stackoverflow';
    });

    $hook->add_filter('filter',function($test) {
        return $test .' world';
    },1);

    echo $hook->apply_filters('filter','hello');
    // Result is hello world

我的代码有什么问题,我想要这样的结果

hello world stackoverflow

用于添加过滤器

public function add_filter(string $tag,mixed $object,int $priority = 10,int $args_limit = 1): void
{
    $hooks = static::$hooks;

    if(isset($hooks[$tag])) {
        static::$hooks[$tag]['sorted'] = false;
        static::$hooks[$tag]['priority'][] = $priority;
        static::$hooks[$tag]['object'][] = $object;
        static::$hooks[$tag]['args_limit'][] = $args_limit;
    } else {
        static::$hooks[$tag] = [
            'sorted' => true,
            'priority' => [$priority],
            'object' => [$object],
            'args_limit' => [$args_limit]
        ];
    }
}

以及应用过滤器

public function apply_filters(string $tag,mixed $value,mixed ...$args): mixed
{
    $hooks = static::$hooks;
    // Shift value to args
    array_unshift($args,$value);
    $num_args = count($args);

    if(isset($hooks[$tag])) {
        $hooks = $hooks[$tag];
        if(!$hooks['sorted']) {
            // Sort filter by priority
            array_multisort(
                $hooks['priority'], 
                SORT_NUMERIC, 
                $hooks['object'],
                $hooks['args_limit']
            );

            $hooks['sorted'] = true;
        }

        foreach($hooks['object'] as $key => $object) {
            $args_limit = $hooks['args_limit'][$key];
            
            if(0 === $args_limit) {
                $value = call_user_func($object);
            } elseif($args_limit >= $num_args) {
                $value = call_user_func_array($object,$args);
            } else {
                // Slice arguments if not meet from the second statement
                $value = call_user_func_array($object,array_slice($args,0,$args_limit));
            }
        }
        
    }

    return $value;
}

所以我试着看看wordpress的核心代码但是太复杂了。

谢谢

1 个答案:

答案 0 :(得分:0)

终于解决了! ,我只是忘了 $value 不会传递给回调

这是修复,以供将来参考

public function apply_filters(string $tag,mixed $value,mixed ...$args): mixed
{
    $hooks = static::$hooks;
    // +1 for $value parameter
    $num_args = count($args) + 1;

    if(isset($hooks[$tag])) {
        $hooks = $hooks[$tag];
        if(!$hooks['sorted']) {
            // Sort filter by priority
            array_multisort(
                $hooks['priority'], 
                SORT_NUMERIC, 
                $hooks['object'],
                $hooks['args_limit']
            );

            $hooks['sorted'] = true;
        }

        foreach($hooks['object'] as $key => $object) {
            $args_limit = $hooks['args_limit'][$key];
            
            if(0 === $args_limit) {
                $value = call_user_func($object);
            } elseif($args_limit >= $num_args) {
                $value = call_user_func($object,$value,...$args);
            } else {
                // Slice arguments if not meet from the second statement
                $slice = array_slice($args,0,$args_limit);
                $value = call_user_func($object,$value,...$slice);
            }
        }
    }

    return $value;
}
相关问题