Files
wpdev 76c01e44df refactor: 全部 128 個生產檔加入 declare(strict_types=1)(PR-H)
對齊 A v3.2.0。型別強制會把隱式轉換變成 TypeError,所以一次全檔加入
並跑完整測試(unit 451 / integration 398 全綠,無迴歸)。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TbG1keQQ7XBa7qMQY16KCY
2026-07-31 06:13:33 +08:00

168 lines
4.5 KiB
PHP
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
/**
* TMDO_Type_Caster - 型別轉換器
*
* 負責:
* - PHP → DB 序列化(寫入)
* - DB → PHP 反序列化(讀取)
* - wpdb format string 生成
* - 型別驗證與清理
*
* @package WP_Data_Optimizer
*/
declare(strict_types=1);
// phpcs:disable Squiz.Commenting,Generic.Commenting,WordPress.DB.PreparedSQL.NotPrepared,WordPress.DB.PreparedSQL.InterpolatedNotPrepared,WordPress.DB.PreparedSQLPlaceholders.ReplacementsWrongNumber,Generic.CodeAnalysis.UnusedFunctionParameter,Generic.CodeAnalysis.EmptyStatement,Squiz.PHP.DisallowMultipleAssignments,Squiz.PHP.DisallowSizeFunctionsInLoops,WordPress.WP.I18n.MissingTranslatorsComment,WordPress.PHP.NoSilencedErrors,WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents,Squiz.PHP.CommentedOutCode,Universal.NamingConventions.NoReservedKeywordParameterNames,WordPress.PHP.YodaConditions,Squiz.Commenting.InlineComment.InvalidEndChar -- PR-1 ported from UAE; cleanup PR scheduled.
defined( 'ABSPATH' ) || exit;
final class TMDO_Type_Caster {
/**
* PHP → DB 轉換(寫入)
*/
public static function to_db( $value, array $field_def ) {
$type = $field_def['type'] ?? 'text';
// null 值處理
if ( $value === null ) {
if ( ! empty( $field_def['required'] ) ) {
return $field_def['default'] ?? '';
}
return null;
}
switch ( $type ) {
case 'integer':
return (int) $value;
case 'decimal':
return (float) $value;
case 'boolean':
return self::to_bool( $value ) ? 1 : 0;
case 'date':
return self::format_date( $value, 'Y-m-d' );
case 'datetime':
case 'timestamp':
return self::format_date( $value, 'Y-m-d H:i:s' );
case 'json':
if ( is_string( $value ) ) {
// 若已是 JSON 字串則直接儲存(驗證後)
$decoded = json_decode( $value, true );
if ( json_last_error() === JSON_ERROR_NONE ) {
return $value;
}
}
return wp_json_encode( $value, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES );
case 'enum':
$options = $field_def['options'] ?? array();
$str = (string) $value;
return ( ! empty( $options ) && in_array( $str, $options, true ) ) ? $str : ( $field_def['default'] ?? '' );
case 'binary':
return $value;
case 'text':
return (string) $value;
case 'textarea':
return (string) $value;
default:
// 未知型別:嘗試序列化(向後相容 WordPress get_metadata 行為)
return maybe_serialize( $value );
}
}
/**
* DB → PHP 轉換(讀取)
*/
public static function from_db( $value, array $field_def ) {
$type = $field_def['type'] ?? 'text';
if ( $value === null ) {
return null;
}
switch ( $type ) {
case 'integer':
return (int) $value;
case 'decimal':
return (float) $value;
case 'boolean':
return (bool) (int) $value;
case 'date':
case 'datetime':
case 'timestamp':
return (string) $value;
case 'json':
$decoded = json_decode( (string) $value, true );
return ( json_last_error() === JSON_ERROR_NONE ) ? $decoded : $value;
case 'enum':
case 'text':
case 'textarea':
return (string) $value;
default:
// v2.13.3: object-injection-safe unserialize (fixes L-DESER-1).
return TMDO_Safe_Unserialize::run( $value );
}
}
/**
* wpdb format 字串(%s / %d / %f
*/
public static function get_wpdb_format( string $type ): string {
return match ( $type ) {
'integer', 'boolean' => '%d',
'decimal' => '%f',
default => '%s',
};
}
// ─────────────────────────────────────────────────────────
// 工具方法
// ─────────────────────────────────────────────────────────
private static function to_bool( $value ): bool {
if ( is_bool( $value ) ) {
return $value;
}
if ( is_numeric( $value ) ) {
return (int) $value !== 0;
}
$str = strtolower( trim( (string) $value ) );
return in_array( $str, array( 'true', 'yes', 'y', '1', 'on' ), true );
}
private static function format_date( $value, string $format ): ?string {
if ( $value === '' || $value === null ) {
return null;
}
// 接受 Unix timestamp
if ( is_numeric( $value ) ) {
return gmdate( $format, (int) $value );
}
$ts = strtotime( (string) $value );
if ( $ts === false ) {
return null;
}
return gmdate( $format, $ts );
}
}