I'm curious, is there any way this could be improved?
Code: Select all
<?php
require_once 'Tilling/Validation/Exception.php';
/**
* Validation to test if a string is intergal
*/
class Tilling_Validation_Test_Intergal
{
/**
* @var int|string
*/
private $_maxInt = PHP_INT_MAX;
/**
* Test whether a value is an integer
*
* @param array $testSubjects strings to test
* @param bool $signed set to false if only unsigned is allowed
* @param int|string $maxInt the maximum integer size, if you do not have BC math installed this cannot be larger than PHP_INT_MAX
* @return bool
*/
public function invoke(array $testSubjects, $signed = false, $maxInt = PHP_INT_MAX)
{
$this->_maxInt = $maxInt;
$call = $signed ? '_signed' : '_unsigned';
foreach ($testSubjects as $testSubject) {
if (!$this->$call((string)$testSubject)) {
return false;
}
}
return true;
}
/**
* Test if a signed integer string is intergal
*
* @uses _unsigned()
* @param string $testSubject
* @return bool
*/
private function _signed($testSubject)
{
if ($this->_unsigned($testSubject)) {
return true;
}
// Multibyte safe: Testing for single byte character
if ($testSubject[0] == '-' && $this->_unsigned(substr($testSubject, 1))) {
return true;
}
return false;
}
/**
* Test if a unsigned integer string is intergal
*
* @throws Tilling_Validation_Exception if bcmath is required but no available
* @param string $testSubject
* @return bool
*/
private function _unsigned($testSubject)
{
if (!ctype_digit($testSubject)) {
// its obviously false if it contains non-digit characters
return false;
}
if (is_int($this->_maxInt) && $this->_maxInt < PHP_INT_MAX) {
// normal comparison is fine
return $testSubject <= $this->_maxInt;
}
if ($this->_maxInt == PHP_INT_MAX) { // different rules for checking overflow
// if its got the value of PHP_INT_MAX as a string then it's fine
if ((string)$this->_maxInt === (string)$testSubject) {
return true;
}
// if when cast to an integer it becomes PHP_INT_MAX this is an
// indication that it was formerly out of range
if ((int)$testSubject === $this->_maxInt) {
return false;
}
return true;
}
// $this->_maxInt is greater than PHP natively handles
// so we have to use bcmath
if (!extension_loaded('bcmath')) {
$errStr = 'Cannot compare number greater than PHP_INT_MAX without bcmath loaded';
throw new Tilling_Validation_Exception($errStr);
}
return bccomp($testSubject, $this->_maxInt, 0) < 1; // 0 or -1 are valid
}
}Code: Select all
<?php
require_once 'Tilling/Validation/Test/Intergal.php';
class Tilling_Validation_Test_Intergal_Test extends Tilling_Test_Case
{
/**
* @var Tilling_Validation_Test_Intergal
*/
public $inst;
public function setUp()
{
$this->inst = new Tilling_Validation_Test_Intergal();
}
public function testDigitsOnly()
{
$this->assertTrue($this->inst->invoke(array('1', '5', '94254334534'), false));
$this->assertFalse($this->inst->invoke(array('1', '5', '9a'), false));
$this->assertTrue($this->inst->invoke(array('1', '5', '94254334534'), true));
$this->assertFalse($this->inst->invoke(array('1', '5', '9a'), true));
}
public function testSignChar()
{
$this->assertFalse($this->inst->invoke(array('-1'), false));
$this->assertFalse($this->inst->invoke(array('1-'), false));
$this->assertTrue($this->inst->invoke(array('-1'), true));
$this->assertFalse($this->inst->invoke(array('1-'), true));
}
public function testWithinStorableRange()
{
$this->assertFalse($this->inst->invoke(array('99999999999999999999999')));
$this->assertFalse($this->inst->invoke(array('-99999999999999999999999'), true));
$this->assertTrue($this->inst->invoke(array(PHP_INT_MAX)));
$this->assertTrue($this->inst->invoke(array(-PHP_INT_MAX), true));
}
public function testCustomMaxLessThanPHP_INT_MAX()
{
$this->assertFalse($this->inst->invoke(array(500), false, 499));
$this->assertFalse($this->inst->invoke(array(-1), false, 499));
$this->assertTrue($this->inst->invoke(array(499), false, 499));
$this->assertFalse($this->inst->invoke(array(-499), false, 499));
$this->assertTrue($this->inst->invoke(array(-499), true, 499));
$this->assertFalse($this->inst->invoke(array(-500), true, 499));
$this->assertFalse($this->inst->invoke(array(500), true, 499));
}
public function testCustomMaxMoreThanPHP_INT_MAX()
{
if (extension_loaded('bcmath')) {
$this->assertTrue($this->inst->invoke(array('9999999999999'), false, $max = '9999999999999'));
$this->assertTrue($this->inst->invoke(array('9999999999998'), false, $max));
$this->assertFalse($this->inst->invoke(array('10000000000000'), false, $max));
} else {
$this->expectException();
$this->inst->invoke(array(1), false, '999999999999999');
}
}
}