【问题标题】:Wordpress prepare-function needs that isset?WordPress准备功能需要那个isset?
【发布时间】:2015-12-19 11:30:57
【问题描述】:

在 wpdb-class 的天才函数“准备”中(在 includes/wp-dp.php 中)我无法解释为什么需要isset( $args[0] )

已经清楚的是1 < func_num_args() 然后第一个条目被移动。它仍然是0 < func_num_args(),因此必须存在第一个条目。 $args[0] 可以是NULL,但如果是这样,它就不能是一个数组,它在同一个“if”if ( isset( $args[0] ) && is_array($args[0]) ) 中进行测试。

那么我错过了什么?

function prepare( $query, $args = null ) {
    if ( is_null( $query ) )
        return;

    if ( func_num_args() < 2 )
        _doing_it_wrong( 'wpdb::prepare', 'wpdb::prepare() requires at least two arguments.', '3.5' );

    $args = func_get_args();
    array_shift( $args );
    // If args were passed as an array (as in vsprintf), move them up
    if ( isset( $args[0] ) && is_array($args[0]) )
        $args = $args[0];
    $query = str_replace( "'%s'", '%s', $query ); // in case someone mistakenly already singlequoted it
    $query = str_replace( '"%s"', '%s', $query ); // doublequote unquoting
    $query = preg_replace( '|(?<!%)%f|' , '%F', $query ); // Force floats to be locale unaware
    $query = preg_replace( '|(?<!%)%s|', "'%s'", $query ); // quote the strings, avoiding escaped strings like %%s
    array_walk( $args, array( $this, 'escape_by_ref' ) );
    return @vsprintf( $query, $args );
}

【问题讨论】:

  • WordPress 的代码并不是分析“为什么要这样做”的最佳选择,因为它充满了不需要或很糟糕的代码。不要误会我的意思,WordPress 作为一个工具很棒——但代码不是。整个 func_get_args() 方法是草率且不必要的 - 就像很多 WordPress 核心代码一样。
  • 您更喜欢哪种方法来获得相同的功能?

标签: php database wordpress


【解决方案1】:

首先我不知道您在哪个版本上获得此代码,但在上一个 WP 版本上没有 func_num_args 检查 - 也许您从临时版本 when they made this fix 获得此代码。在 WP 4.3.1 中,prepare 函数如下所示:

public function prepare( $query, $args ) {
    if ( is_null( $query ) )
        return;

    // This is not meant to be foolproof -- but it will catch obviously incorrect usage.
    if ( strpos( $query, '%' ) === false ) {
        _doing_it_wrong( 'wpdb::prepare', sprintf( __( 'The query argument of %s must have a placeholder.' ), 'wpdb::prepare()' ), '3.9' );
    }

    $args = func_get_args();
    array_shift( $args );
    // If args were passed as an array (as in vsprintf), move them up
    if ( isset( $args[0] ) && is_array($args[0]) )
        $args = $args[0];
    $query = str_replace( "'%s'", '%s', $query ); // in case someone mistakenly already singlequoted it
    $query = str_replace( '"%s"', '%s', $query ); // doublequote unquoting
    $query = preg_replace( '|(?<!%)%f|' , '%F', $query ); // Force floats to be locale unaware
    $query = preg_replace( '|(?<!%)%s|', "'%s'", $query ); // quote the strings, avoiding escaped strings like %%s
    array_walk( $args, array( $this, 'escape_by_ref' ) );
    return @vsprintf( $query, $args );
}

所以我们先翻译一下代码:

if ( strpos( $query, '%' ) === false )

如果已传递不带任何参数的查询,自定义错误处理程序将告诉用户他不应使用 prepare 进行此类查询。

$args = func_get_args();

非常简单,它获取发送给函数的所有参数。它会得到一个具有这种结构的数组:

Array(2) (
  [0] => $query,
  [1] => $args
)

紧接着:

array_shift( $args );

这将删除$args ($query) 的第一个值,因此我们最终会得到一个如下所示的新数组:

Array(2) (
  [0] => $args
)

然后是让你嗡嗡作响的测试:

if ( isset( $args[0] ) && is_array($args[0]) )

要了解为什么需要 isset,让我们假设您尝试像这样调用 prepare 函数:

$wpdb->prepare("SELECT * FROM table WHERE arg1 = %s");

那么调用的结果是什么?查询里面有一个%s,所以它会被认为是有效的。我们将得到一个仅包含查询的参数表,在它被移动之后,我们将得到一个空数组。然后,isset 将返回false,因为0 索引不存在,并且如果in_array 将被执行,它将显示以下错误(如果启用通知错误显示):

Notice:  Undefined offset: 0 in ***.php on line **

这里有一个小脚本来说明这一点:

function test_args($arg1, $arg2) {
    $args = func_get_args();
    echo '<b>func_get_args : </b>';
    var_dump($args);
    array_shift($args);
    echo '<b>array_shift : </b>';
    var_dump($args);
    echo '<b>isset($args[0]) : </b>';
    var_dump(isset($args[0]));
    echo '<b>is_array($args[0]) : </b>';
    var_dump(is_array($args[0]));
    echo '----<br />';
}
test_args('arg 1');

这将输出以下内容:


func_get_args : array(1) {
 [0]=>
 string(5) "arg 1"
}
array_shift : array(0) {
}
isset($args[0]) : bool(false)
is_array($args[0]) : 

Notice: Undefined offset: 0 in E:\www\test-args.php on line 17

这就是为什么这个isset检查是有效的。 虽然,由于$args 不再是可选的,因此我们也会收到准备函数的警告,因为我们只发送一个参数 - 在这里的开发过程中可能会丢失一些东西。我们错过了可选的 $argsfunc_num_args 检查 - 这两个以前的检查会使 isset 检查无用并防止显示任何错误。这应该在the WP bug report 上报告。

【讨论】:

  • 我明白了。那么isset只是为了避免Notice: Undefined offset: 0 in E:\www\test-args.php on line …
  • 是的,这就是它的用途。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-09-26
  • 2013-11-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-10-29
相关资源
最近更新 更多