Reliable integer typecasting

与世无争的帅哥 提交于 2020-01-16 01:06:13

问题


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)?


回答1:


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);



回答2:


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.



来源:https://stackoverflow.com/questions/6967186/reliable-integer-typecasting

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!