PHP项目数字马来西亚林吉特与eMYR

wen PHP项目 1

本文目录导读:

PHP项目数字马来西亚林吉特与eMYR

  1. 核心概念:单位转换
  2. PHP 格式化与处理函数
  3. 数据库设计建议
  4. 与 eMYR 智能合约/API 交互(伪代码)
  5. 关键注意事项与坑

在 PHP 项目中处理 马来西亚林吉特 (MYR)电子马来西亚令吉 (eMYR) 时,主要涉及货币格式化显示数字货币单位换算以及API 集成(用于支付或余额查询)。

这里提供一份完整的 PHP 解决方案,涵盖格式化、单位转换以及伪代码级别的 eMYR 交互示例。


核心概念:单位转换

这是最容易出错的地方。

  • MYR (标准货币): 单位是 Ringgit,最小单位是 Sen (1 MYR = 100 Sen)。
    • 在 PHP 浮点数或数据库存储中,通常表示为 50
  • eMYR (数字货币): 这是马来西亚国家银行 (BNM) 的试点数字货币(数字林吉特)。
    • 关键点: eMYR 的最小单位通常不是 Sen,而是更小的单位(类似比特币的聪),具体取决于采用的协议(1 eMYR = 1,000,000,000 单位,即 nano 级别)。但在与现有系统交互时,最安全的做法是将其视为最小的不可分割单位(整数)进行传输和存储。

原则:永远不要在前端或业务逻辑中使用浮点数计算货币。

PHP 格式化与处理函数

<?php
/**
 * 将整数分(Sen)格式化为显示字符串
 *  1250 -> "RM 12.50"
 */
function formatMYRFromSen(int $sen): string {
    $ringgit = $sen / 100;
    // 使用 number_format 避免浮点精度问题
    return 'RM ' . number_format($ringgit, 2, '.', ',');
}
/**
 * 将浮点金额转换为最小的整数分(用于存储或计算)
 *  "12.50" -> 1250
 */
function convertMYRToCents(float $amount): int {
    // 乘以100并取整,避免浮点误差
    return (int) round($amount * 100);
}
/**
 * eMYR 单位转换(假设 eMYR 最小单位为 1e-9 或按 1:1 处理)
 * 注意:必须知道具体的 eMYR 精度
 * 示例:1 eMYR = 1,000,000,000 最小单位 (nano)
 */
function convertEMYRToSmallestUnit(float $eMYR, int $decimals = 9): string {
    // 使用 bcmath 扩展处理大数
    if (function_exists('bcmul')) {
        return bcmul((string)$eMYR, '1' . str_repeat('0', $decimals), 0);
    }
    // 降级方案 (不推荐用于生产)
    return (string) ($eMYR * pow(10, $decimals));
}
/**
 * 将 eMYR 的最小单位格式化为人类可读形式
 */
function formatEMYRFromUnit(string $amount, int $decimals = 9): string {
    if (function_exists('bcdiv')) {
        $value = bcdiv($amount, '1' . str_repeat('0', $decimals), $decimals);
    } else {
        $value = number_format($amount / pow(10, $decimals), $decimals, '.', '');
    }
    return 'eMYR ' . rtrim(rtrim($value, '0'), '.');
}
// 使用示例
echo formatMYRFromSen(1250); // 输出: RM 12.50
echo "\n";
echo formatEMYRFromUnit('1500000000'); // 输出: eMYR 1.5 (假设小数位9位)
?>

数据库设计建议

如果你的项目同时处理 MYR 和 eMYR,建议分开存储,或使用统一的整数类型:

-- 方案 A: 分开表存储
CREATE TABLE transactions (
    id INT AUTO_INCREMENT PRIMARY KEY,
    type ENUM('MYR', 'eMYR') NOT NULL,
    -- MYR 金额以分为单位(整数)
    myr_amount_cents INT DEFAULT NULL, -- 1250 代表 RM12.50
    -- eMYR 金额以最小单位存储(BIGINT 或 DECIMAL)
    emyr_amount_units DECIMAL(30,0) DEFAULT NULL, -- 1500000000000 代表 1.5 eMYR
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- 方案 B: 统一货币表(假设主货币是 MYR,eMYR 视为1:1等值?这通常不准确,需谨慎)
-- 建议使用方案 A。

与 eMYR 智能合约/API 交互(伪代码)

假设你需要调用某个 eMYR 钱包 API(如 Bank Negara 的试点 API 或第三方托管商)。

<?php
class EMYRService {
    private string $apiEndpoint;
    private string $apiKey;
    public function __construct(string $endpoint, string $key) {
        $this->apiEndpoint = $endpoint;
        $this->apiKey = $key;
    }
    /**
     * 检查 eMYR 余额 (返回最小单位整数)
     */
    public function getBalance(string $walletAddress): string {
        $response = $this->callAPI('/v1/balance', ['address' => $walletAddress]);
        // 假设返回 {"balance": "1500000000"} (即 1.5 eMYR)
        return $response['balance'];
    }
    /**
     * 转账 eMYR
     * @param string $from 私钥或地址
     * @param string $to 目标地址
     * @param string $amount 最小单位整数 (注意类型!)
     */
    public function transfer(string $from, string $to, string $amount): bool {
        // 永远不要在前端传递浮点数金额,强制传递 unit string
        // 验证金额 > 0
        if (bccomp($amount, '0', 0) <= 0) {
            throw new InvalidArgumentException('Amount must be positive');
        }
        // 调用 eMYR 链上/API 接口
        $payload = [
            'from' => $from,
            'to'   => $to,
            'value' => $amount, // 已经是最小单位字符串
        ];
        $response = $this->callAPI('/v1/transfer', $payload);
        return $response['tx_hash'] ?? false;
    }
    private function callAPI(string $path, array $data): array {
        // 使用 cURL 或 Guzzle 发起请求
        // 伪代码省略具体实现
        return []; 
    }
}
// 使用示例
// $emyr = new EMYRService('https://api.emyr.my', 'your_key');
// $balanceStr = $emyr->getBalance('0x123...');
// echo formatEMYRFromUnit($balanceStr); // 显示 eMYR 1.5
?>

关键注意事项与坑

  1. 不要用 float 存钱
    • echo 19.99 * 100; 可能会输出 9999999999998
    • 应使用 整数(Sen)或 bcmath(任意精度数学函数)。
  2. eMYR 的精度确认
    • eMYR 计划采用与马来西亚林吉特相同的 2 位小数(1 eMYR = 100 sen digital),则直接使用 cents 逻辑。
    • 但如果它采用区块链标准(如 18 位小数,类似 ERC-20),你需要使用 stringbcmath 进行计算。
    • 默认保守做法:向 API 传输金额时,始终使用最小单位的整数(字符串),并在显示时格式化。
  3. 合规与标识
    • 如果需要在界面上显示,必须明确标注 eMYRDigital Ringgit,不能仅写 RM,以免与传统 MYR 混淆。
    • 遵循 BNM 的图形标准和标识要求。
  4. 税率与舍入

    eMYR 小额支付可能产生极小的零头,舍入逻辑必须明确(会计上通常四舍五入到 Sen,但数字货币可以保留更小单位)。

对于 PHP 项目:

  1. MYR 使用 整数分 (Sen) 存储,用 number_format($value/100, 2) 显示。
  2. eMYR 视作独立资产不要直接与 MYR 互相换算,除非有明确官方 1:1 锚定且 API 要求如此。
  3. 传输金额时 总是传递最小单位的整数(字符串类型),decimal(30,0)varchar,计算使用 bcmath 扩展。
  4. 为你的 eMYR / MYR 交互编写严格的单元测试,特别是边界值(如 0非常大的金额)。

抱歉,评论功能暂时关闭!