问题
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