详解 WordPress `_doing_it_wrong()` 函数源码:开发过程中错误触发的意义。

咳咳,各位观众,各位大佬,晚上好!我是今晚的主讲人,咱们今天要聊聊 WordPress 里一个有点意思的小家伙:_doing_it_wrong()

这名字听着就挺委屈的,感觉自己干了啥错事儿似的。没错,它就是专门用来“抓包”那些在开发过程中“姿势不对”的代码的。

一、_doing_it_wrong():名字里就写满了故事

首先,咱们看看这函数的名字:_doing_it_wrong()。WordPress 团队的命名风格一向比较直白,这名字直接翻译过来就是“正在做错事”。

这个函数的作用也很简单粗暴:当你调用了某个被标记为“过时”、“不推荐”或者“使用方式不当”的函数、方法或代码时,它就会跳出来“提醒”你,让你知道自己犯了点小错误。

二、_doing_it_wrong() 的源码解析

咱们直接上代码,看看这小家伙到底是怎么工作的:

/**
 * Fires when the theme functions are being incorrectly called.
 *
 * @since 3.1.0
 * @since 5.5.0 Added the `$doing_it_wrong` argument.
 *
 * @param string $function      The function that was called.
 * @param string $message       A message explaining what the problem is.
 * @param string $version       The version of WordPress where the message was added.
 * @param string $doing_it_wrong Optional. Whether the _doing_it_wrong() was called. Default null.
 *                                Pass a value to explicitly enable/disable the backtrace.
 *
 * @return void
 */
function _doing_it_wrong( $function, $message, $version, $doing_it_wrong = null ) {
    // Allow plugins to prevent _doing_it_wrong().
    if ( has_filter( 'doing_it_wrong_run' ) && ! apply_filters( 'doing_it_wrong_run', true, $function, $message, $version ) ) {
        return;
    }

    $doing_it_wrong_trigger = true;
    if ( null !== $doing_it_wrong && ! $doing_it_wrong ) {
        $doing_it_wrong_trigger = false;
    }

    if ( WP_DEBUG && $doing_it_wrong_trigger ) {
        if ( is_scalar( $message ) ) {
            $message = html_entity_decode( (string) $message, ENT_QUOTES, get_option( 'html_type' ) );
        }

        $backtrace = wp_debug_backtrace_summary( null, 0, false );

        if ( is_user_logged_in() ) {
            $format = esc_html__( '%1$s was called <strong>incorrectly</strong>. %2$s. Please see <a href="%3$s" target="_blank">Debugging in WordPress</a> for more information.' ) . ' (This message was added in version %4$s.)';
            $message = sprintf( $format, '<code>' . $function . '</code>', $message, 'https://wordpress.org/documentation/article/debugging-in-wordpress/', $version );
        } else {
            $format = esc_html__( '%1$s was called <strong>incorrectly</strong>. %2$s. Debugging in WordPress.' ) . ' (This message was added in version %4$s.)';
            $message = sprintf( $format, '<code>' . $function . '</code>', $message, $version );
        }

        trigger_error( sprintf( '%s %s', $message, $backtrace ), E_USER_NOTICE );
    }
}

咱们来一行一行地解读一下:

  1. 函数定义:

    function _doing_it_wrong( $function, $message, $version, $doing_it_wrong = null )
    • $function: 出问题(被错误使用)的函数名。
    • $message: 解释为什么出问题的信息。
    • $version: WordPress 的哪个版本开始出现这个“问题”。
    • $doing_it_wrong: (可选)一个布尔值,用于显式启用/禁用回溯跟踪。默认值为 null。传入一个值可以控制是否显示调用栈。
  2. 过滤器 doing_it_wrong_run

    if ( has_filter( 'doing_it_wrong_run' ) && ! apply_filters( 'doing_it_wrong_run', true, $function, $message, $version ) ) {
        return;
    }

    WordPress 的强大之处就在于它的可扩展性。这里用了一个过滤器 doing_it_wrong_run,允许插件阻止 _doing_it_wrong() 的执行。也就是说,如果你真的知道自己在干什么,可以通过这个过滤器来“屏蔽”这些警告。

  3. $doing_it_wrong 参数处理

    $doing_it_wrong_trigger = true;
    if ( null !== $doing_it_wrong && ! $doing_it_wrong ) {
        $doing_it_wrong_trigger = false;
    }

    这段代码允许你通过$doing_it_wrong参数来控制是否触发错误。如果明确设置为false,则不会触发错误提示。这为开发者提供了更精细的控制。

  4. WP_DEBUG 检查:

    if ( WP_DEBUG && $doing_it_wrong_trigger ) {
        // ...
    }

    这行代码很重要。_doing_it_wrong() 只有在 WP_DEBUGtrue 的时候才会真正发挥作用。WP_DEBUG 是 WordPress 的一个调试模式,开启后会显示各种错误和警告信息。 在生产环境中,一般会将 WP_DEBUG 设置为 false,以避免向用户暴露敏感信息。

  5. 消息格式化:

    if ( is_user_logged_in() ) {
        $format = esc_html__( '%1$s was called <strong>incorrectly</strong>. %2$s. Please see <a href="%3$s" target="_blank">Debugging in WordPress</a> for more information.' ) . ' (This message was added in version %4$s.)';
        $message = sprintf( $format, '<code>' . $function . '</code>', $message, 'https://wordpress.org/documentation/article/debugging-in-wordpress/', $version );
    } else {
        $format = esc_html__( '%1$s was called <strong>incorrectly</strong>. %2$s. Debugging in WordPress.' ) . ' (This message was added in version %4$s.)';
        $message = sprintf( $format, '<code>' . $function . '</code>', $message, $version );
    }

    这段代码根据用户是否登录来格式化错误消息。如果用户已登录,消息会包含一个链接到 WordPress 官方文档的调试页面。

  6. 触发错误:

    trigger_error( sprintf( '%s %s', $message, $backtrace ), E_USER_NOTICE );

    这行代码才是真正“报警”的地方。trigger_error() 函数会触发一个用户级别的错误,类型是 E_USER_NOTICE。这个错误信息会被记录到 WordPress 的错误日志中,也会在页面上显示(如果 WP_DEBUGtrueWP_DEBUG_DISPLAY 也为 true)。

三、_doing_it_wrong() 的应用场景

_doing_it_wrong() 通常用在以下几种场景:

  • 过时函数: 当某个函数被标记为过时(deprecated)时,调用它就会触发 _doing_it_wrong()
  • 不推荐使用的函数: 有些函数虽然没有被标记为过时,但是因为存在更好的替代方案,所以不推荐使用。
  • 使用方式不当: 有些函数本身没有问题,但是如果使用方式不正确,也会触发 _doing_it_wrong()

举个栗子:

假设 WordPress 团队觉得 my_old_function() 这个函数已经过时了,他们可能会这样标记它:

function my_old_function() {
    _doing_it_wrong( 'my_old_function', 'This function is deprecated and should not be used. Use my_new_function() instead.', '5.0.0' );
    // 函数的原始逻辑
}

这样,只要有人调用 my_old_function(),就会在调试模式下看到类似这样的错误信息:

my_old_function was called incorrectly. This function is deprecated and should not be used. Use my_new_function() instead. Please see Debugging in WordPress for more information. (This message was added in version 5.0.0.)

四、_doing_it_wrong() 的意义

_doing_it_wrong() 虽然只是一个小小的函数,但是它在 WordPress 开发中却扮演着重要的角色:

  • 提高代码质量: 它可以帮助开发者及时发现代码中的问题,避免使用过时或不推荐使用的函数,从而提高代码质量。
  • 保持代码兼容性: 它可以提醒开发者注意 WordPress 版本的变化,避免使用在未来版本中可能被移除的函数,从而保持代码的兼容性。
  • 促进代码规范: 它可以引导开发者遵循 WordPress 的代码规范,使用正确的函数和方法,从而提高代码的可读性和可维护性。
  • 调试利器: 在开发过程中,开启WP_DEBUG后,_doing_it_wrong()能迅速定位问题所在,大大缩短调试时间。

五、_doing_it_wrong()_deprecated_function()_deprecated_argument() 的区别

WordPress 中还有两个类似的函数:_deprecated_function()_deprecated_argument()。它们和 _doing_it_wrong() 的区别在于:

  • _deprecated_function():专门用于标记整个函数为过时。
  • _deprecated_argument():专门用于标记函数的某个参数为过时。
  • _doing_it_wrong():更加通用,可以用于标记函数、参数、方法等任何代码为“使用方式不当”。

咱们用一个表格来总结一下:

函数 作用 适用对象
_doing_it_wrong() 标记代码使用方式不当 函数、参数、方法等
_deprecated_function() 标记整个函数为过时 函数
_deprecated_argument() 标记函数的某个参数为过时 函数的参数

六、如何优雅地处理 _doing_it_wrong() 警告

当你在开发过程中遇到 _doing_it_wrong() 警告时,应该怎么做呢?

  1. 仔细阅读警告信息: 警告信息会告诉你哪个函数被错误使用,以及为什么被错误使用。
  2. 查找替代方案: 根据警告信息,查找正确的替代方案。通常警告信息会告诉你应该使用哪个函数来代替。
  3. 更新代码: 将代码中的错误函数替换为正确的替代方案。
  4. 测试代码: 更新代码后,进行充分的测试,确保代码能够正常工作。
  5. 实在不行就屏蔽: 如果你真的有特殊原因,需要使用那些被标记为“不推荐”的函数,可以使用 doing_it_wrong_run 过滤器来屏蔽警告。但请谨慎使用这种方法,确保你真的知道自己在干什么。

    add_filter( 'doing_it_wrong_run', 'my_custom_doing_it_wrong_filter', 10, 4 );
    
    function my_custom_doing_it_wrong_filter( $run, $function, $message, $version ) {
       // 只屏蔽特定函数的警告
       if ( $function === 'my_old_function' ) {
           return false; // 阻止 _doing_it_wrong() 执行
       }
       return $run; // 其他情况正常执行
    }

    这段代码只有在my_old_function被错误调用时才会阻止_doing_it_wrong()的执行,其他情况则保持默认行为。

七、总结

_doing_it_wrong() 是 WordPress 提供的一个非常有用的调试工具,它可以帮助开发者及时发现代码中的问题,提高代码质量,保持代码兼容性。在开发过程中,如果遇到 _doing_it_wrong() 警告,一定要认真对待,及时修复代码,避免给未来的维护带来麻烦。

记住,_doing_it_wrong() 不是来找茬的,它是来帮你成为更好的 WordPress 开发者的!

好了,今天的讲座就到这里。希望大家以后在 WordPress 的开发道路上,能够尽量少地“doing it wrong”,多写出高质量的代码! 谢谢大家!

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注