可靠的整数类型转换

发布于 2024-11-28 18:28:15 字数 1766 浏览 0 评论 0原文

我正在为 PHP 开发一个数据验证器包(主要是作为 5.3 中一些新添加的练习,例如命名空间)。我计划有一个主验证器类,它使用插件类来进行实际验证。

我正在构建的第一个验证插件只是一个简单的整数验证插件。来源如下:

namespace validator\validatorplugins;

class Integer implements ValidatorPlugin
{
    private
        $field  = NULL;

    public function cast ()
    {
        return ($this -> field  = (int) ($this -> field * 1));
    }

    public function isValid ()
    {
        if (!$isValid = is_int ($this -> field * 1))
        {
            $this -> field  = NULL;
        }
        return ($isValid);
    }

    public function __construct ($field)
    {
        $this -> field  = $field;
    }

    public function __toString()
    {
        return ((string) $this -> field);
    }
}

我正在使用上述类的以下测试:

$a  = new Integer (0xDEADBEEF);
var_dump ($a -> isValid ());
var_dump ($a -> cast ());
echo ($a . "\n\n");

$b  = new Integer ('0xDEADBEEF');
var_dump ($b -> isValid ());
var_dump ($b -> cast ());
echo ($b . "\n\n");

$c  = new Integer (0777);
var_dump ($c -> isValid ());
var_dump ($c -> cast ());
echo ($c . "\n\n");

$d  = new Integer ('0777');
var_dump ($d -> isValid ());
var_dump ($d -> cast ());
echo ($d . "\n\n");

从上面的测试用例中我得到以下结果:

布尔(true)int(3735928559)3735928559

布尔(true)int(3735928559)3735928559

布尔(true)int(511)511

布尔(true)int(777)777

如您所见,我遇到了一个问题编码八进制数的字符串。它的计算结果应该是 511(以 10 为基数的 0777),但实际上我得到的是 777。

因为有一天我可能想要使用此类来验证表单,并且由于 PHP 始终将表单视为字符串数组,因此您可以看到使用此插件处理恰好是字符串的八进制数字是有问题的。

我尝试了各种整数验证方法(使用 is_int 对于字符串总是返回 false,乘以 1 并且 is_numeric 不会捕获浮点数,类型转换和 intval 在处理八进制数时会产生不需要的结果)。我是否可以使用其他一些适用于基数 10(十进制)、基数 16(十六进制)和基数 8(八进制)的方法?

I'm working on a data validator package for PHP (mostly as an exercise in some of the new additions in 5.3 such as namespaces). I'm planning to have a main validator class which uses plugin classes to do the actual validation.

The first validation plugin I'm building is just a simple one for integers. The source is below:

namespace validator\validatorplugins;

class Integer implements ValidatorPlugin
{
    private
        $field  = NULL;

    public function cast ()
    {
        return ($this -> field  = (int) ($this -> field * 1));
    }

    public function isValid ()
    {
        if (!$isValid = is_int ($this -> field * 1))
        {
            $this -> field  = NULL;
        }
        return ($isValid);
    }

    public function __construct ($field)
    {
        $this -> field  = $field;
    }

    public function __toString()
    {
        return ((string) $this -> field);
    }
}

I'm using the following tests of the above class:

$a  = new Integer (0xDEADBEEF);
var_dump ($a -> isValid ());
var_dump ($a -> cast ());
echo ($a . "\n\n");

$b  = new Integer ('0xDEADBEEF');
var_dump ($b -> isValid ());
var_dump ($b -> cast ());
echo ($b . "\n\n");

$c  = new Integer (0777);
var_dump ($c -> isValid ());
var_dump ($c -> cast ());
echo ($c . "\n\n");

$d  = new Integer ('0777');
var_dump ($d -> isValid ());
var_dump ($d -> cast ());
echo ($d . "\n\n");

From the above test cases I'm getting the following results:

bool(true) int(3735928559) 3735928559

bool(true) int(3735928559) 3735928559

bool(true) int(511) 511

bool(true) int(777) 777

As you can see, I've run into an issue with a string that encodes an octal number. It should evaluate to 511 (0777 in base 10), but I'm actually getting 777 instead.

As I might one day want to use this class to validate forms, and as forms are always treated as arrays of strings by PHP, you can see that processing octal numbers that happen to be strings with this plugin is problematic.

I've tried various approaches to integer validation (using is_int always returns false for strings, multiplying by 1 and is_numeric will not catch floats, typecasting and intval produce an unwanted result when dealing with octal numbers). Is there some other approach I could use that would work for base 10 (decimal), base 16 (hex) and base 8 (octal)?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

小情绪 2024-12-05 18:28:16

intval 有一个可选参数 $base

intval('0777', 8); // 511
intval('0777', 10); // 777
intval('0777'); // 777
intval(0777); // 511

所以你可以这样做:

$i = '0777';

$base = 10;
if (strtolower(substr($i, 0, 2)) === '0x') $base = 16;
else if (substr($i, 0, 1) === '0') $base = 8;

intval($i, $base);

intval has an optional argument $base:

intval('0777', 8); // 511
intval('0777', 10); // 777
intval('0777'); // 777
intval(0777); // 511

So you could do something like this:

$i = '0777';

$base = 10;
if (strtolower(substr($i, 0, 2)) === '0x') $base = 16;
else if (substr($i, 0, 1) === '0') $base = 8;

intval($i, $base);
超可爱的懒熊 2024-12-05 18:28:16

您首先需要定义如何在字符串中表示八进制数。因为有些人倾向于说像 "0777" 这样的字符串是 777 十进制值。

那么,您的类应该如何知道用户在执行您想要验证的输入时的想法(或更正确地转换为整数值)。

至于您想要模仿 PHP 本身如何“作为 PHP”解析值,您可以使用 eval 进行模拟(演示):

<?php

$value = '0777';

$value = eval("return $value;");

var_dump($value);

然而,这并没有解决根本的设计问题。您的沙箱类阵容应该有一个 DecimalIntegerHexadecimalIntegerOctalInteger

You first need to define how an octal number is represented in a string. Because some folks tend to say that a string like "0777" is the 777 decimal value.

So how should your class know what the user thought when doing the input you would like to validate (or more correctly convert into an integer value).

As far as you're concerned to mimic how PHP itself resolves the value "as PHP", you can simulate with eval (Demo):

<?php

$value = '0777';

$value = eval("return $value;");

var_dump($value);

However this does not solve the underlying design problem. You should have a DecimalInteger or a HexadecimalInteger or OctalInteger for your line-up of your sandbox classes.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文