Надежное целочисленное приведение типов - PullRequest
1 голос
/ 06 августа 2011

Я работаю над пакетом валидатора данных для 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");

Из приведенных выше тестовых примеров я получаю следующие результаты:

bool (true) int (3735928559) 3735928559

bool (true) int (3735928559) 3735928559

bool (true) int (511) 511

bool (true) int (777) 777

Как видите, я столкнулся с проблемой со строкой, которая кодирует восьмеричное число.Он должен оценить 511 (0777 в базе 10), но вместо этого я получаю 777.

Как я мог бы однажды захотеть использовать этот класс для проверки форм, и так как формы всегда обрабатываются PHP как массивы строк, вы можете видеть, что обработка восьмеричных чисел, которые оказываются строками с этим плагином, проблематична,

Я пробовал различные подходы к проверке целых чисел (использование is_int всегда возвращает false для строк, умножение на 1 и is_numeric не будет перехватывать числа с плавающей запятой, приведение типов и intval приводят к нежелательному результату при работе с восьмеричными числами).Есть ли какой-то другой подход, который я мог бы использовать, который работал бы для основания 10 (десятичное), основания 16 (шестнадцатеричное) и основания 8 (восьмеричное)?

Ответы [ 2 ]

3 голосов
/ 06 августа 2011

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);
0 голосов
/ 06 августа 2011

Сначала необходимо определить, как восьмеричное число представляется в строке.Потому что некоторые люди склонны говорить, что строка типа "0777" равна десятичное значение 777.

Так как ваш класс должен знать, что думает пользователь, когда вы хотите вводить данные, которые вам нужны?для проверки (или, вернее, преобразования в целочисленное значение).

Что касается имитации того, как PHP сам разрешает значение «как PHP», вы можете смоделировать с помощью eval ( Demo *)1010 *):

<?php

$value = '0777';

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

var_dump($value);

Однако это не решает основную проблему проектирования.У вас должно быть DecimalInteger или HexadecimalInteger или OctalInteger для вашего набора классов песочницы.

...