我有一个插件中有一个棘手的bug,我正试图找出是谁的错。
插件在其init方法中使用检查DB是否必须更新。我使用的子主题设置了一个自定义本地setlocal()
. 因此get_option()
返回字符串而不是浮点值。
以下是如何再现错误的基本设置:
// set custom local
setlocale(LC_ALL, \'de_DE.UTF-8\');
// set current DB version
update_option("db_version", 5.39);
// get DB version
$db_version = get_option("db_version"); // (string) 5,39
// Update DB if necessary
if(!empty($db_version) and $db_version < 5.13) {
$wpdb->query("ALTER TABLE example CHANGE `cat_id` `cat_ids` VARCHAR(255) NOT NULL DEFAULT \'\'");
}
由于更新已经在系统中,它会抛出一个错误
((string) "5,39" < 5.13) === true
.
测试PHP行为
我写了一个小检查,看看是什么导致了错误:
<?php
setlocale(LC_ALL, \'de_DE.UTF-8\');
echo \'<pre>\';
$locale_info = localeconv();
echo \'decimal_point=\' . $locale_info[\'decimal_point\'] . "\\n"; // decimal_point=,
// Test like the DB update check in WP
$db_version = floatval(\'5.39\');
if(!empty($db_version) and $db_version < 5.13) // <==
echo "ERROR $db_version is not smaller than 5.13";
else
echo "SUCCESS $db_version > 5.13";
?>
我对结果感到惊讶:
成功5,39>5.13
如果我正确解释了我的测试,PHP会正确读取十进制值,并且即使在locale
已更改。但由于WP似乎忽略了小数点已设置为逗号值的情况,因此在使用时只返回字符串值get_option("db_version")
.
问题是数据库更新检查if(!empty($db_version) and $db_version < 5.13)
插件错误或使用错误setlocale()
对于WP项目?
如何解决这个问题,有什么好的建议吗?
最合适的回答,由SO网友:Jacob Peattie 整理而成
get_option()
始终返回字符串。这与setlocale()
已使用。选项都存储在option_value
第列,共列wp_options
, 这是一个文本列。当它试图在文本列中插入浮点时,可能正在为您的区域设置设置浮点格式。
您的问题是,您将版本号视为浮点数,这是不正确的。它们可能看起来像浮点数,但版本号是字符串。例如,浮点数5.2
高于5.15
, 但是5.15
版本号高于5.2
.
因此,您无法使用<
或>
在浮动上。您需要使用字符串,并且version_compare()
比较它们。因此,首先确保将值设置为字符串:
update_option( \'my_db_version\', \'5.13\' );
还要注意的是
db_version
是WordPress core已经使用的选项,您需要在选项前面加上项目特有的前缀。
然后可以比较如下值:
$current_version = get_option( \'my_db_version\' );
$new_version = \'5.39\'; // String
// If the current version is lower than the new version...
if ( version_compare( $current_version, $new_version ) < 0 ) {
// ...update to the new version.
update_option( \'my_db_version\', $new_version );
}