Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
"issues": "https://github.com/pleonasm/bloom-filter/issues"
},
"require": {
"php": ">=7.1"
"php": ">=8.0"
},
"require-dev": {
"phpunit/phpunit": "^6.5 || ^7.5 || ^8.5 || ^9.4",
Expand Down
51 changes: 25 additions & 26 deletions src/BitArray.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,24 +17,24 @@
*/
class BitArray implements ArrayAccess, Countable, JsonSerializable
{
const BITS_IN_BYTE = 8;
public const BITS_IN_BYTE = 8;

/**
* @var int
*/
private $length;
private int $length;

/**
* @var string
*/
private $data;
private string $data;

/**
* @param array $decodedJson Should be passed the return from
* $this->jsonSerialize() to re-create the object.
* @return BitArray
*/
public static function initFromJson(array $decodedJson)
public static function initFromJson(array $decodedJson): static
{
return new static(base64_decode($decodedJson['arr']), $decodedJson['len']);
}
Expand All @@ -43,7 +43,7 @@ public static function initFromJson(array $decodedJson)
* @param int $length The length in bits of the bit array
* @return BitArray
*/
public static function init($length)
public static function init(int $length): BitArray
{
static::checkPositiveInt($length);
$lengthInBytes = (int) ceil($length / static::BITS_IN_BYTE);
Expand All @@ -54,7 +54,7 @@ public static function init($length)
/**
* @param mixed $val
*/
private static function checkPositiveInt($val)
private static function checkPositiveInt(mixed $val): void
{
if (!is_int($val)) {
throw new UnexpectedValueException('Value must be an integer.');
Expand All @@ -69,7 +69,7 @@ private static function checkPositiveInt($val)
* @param string $data The raw bytes of the bit array
* @param int $bitLength
*/
public function __construct($data, $bitLength)
public function __construct(string $data, int $bitLength)
{
// need to check string here
// need to check or truncate to $bitlength
Expand All @@ -78,10 +78,10 @@ public function __construct($data, $bitLength)
}

/**
* @param int $offset
* @param mixed $offset
* @return bool
*/
public function offsetExists($offset)
public function offsetExists(mixed $offset): bool
{
if (!is_int($offset)) {
return false;
Expand All @@ -99,20 +99,19 @@ public function offsetExists($offset)
}

/**
* @param int $offset
* @throws UnexpectedValueException
* @throws RangeException
* @param mixed $offset
* @return bool
*/
public function offsetGet($offset)
* @throws RangeException
* @throws UnexpectedValueException
*/
public function offsetGet(mixed $offset): bool
{
$this->isValidOffset($offset);

$byte = $this->offsetToByte($offset);
$byte = ord($this->data[$byte]);
$bit = (bool) ($this->finalBitPos($offset) & $byte);

return $bit;
return (bool) ($this->finalBitPos($offset) & $byte);
}

/**
Expand All @@ -122,7 +121,7 @@ public function offsetGet($offset)
* @throws RangeException
* @return void
*/
public function offsetSet($offset, $value)
public function offsetSet(mixed $offset, mixed $value): void
{
$this->isValidOffset($offset);
$value = (bool) $value;
Expand All @@ -146,7 +145,7 @@ public function offsetSet($offset, $value)
* @throws RangeException
* @return void
*/
public function offsetUnset($offset)
public function offsetUnset(mixed $offset): void
{
$this->offsetSet($offset, false);
}
Expand All @@ -156,15 +155,15 @@ public function offsetUnset($offset)
*
* @return int Returns the total length in bits of the array
*/
public function count()
public function count(): int
{
return $this->length;
}

/**
* @return int Returns the total byte length of the bit array
*/
public function byteLength()
public function byteLength(): int
{
return strlen($this->data);
}
Expand All @@ -175,7 +174,7 @@ public function byteLength()
* @throws UnexpectedValueException
* @return void
*/
private function isValidOffset($val)
private function isValidOffset(mixed $val): void
{
static::checkPositiveInt($val);

Expand All @@ -188,7 +187,7 @@ private function isValidOffset($val)
* @param int $offset
* @return int
*/
private function offsetToByte($offset)
private function offsetToByte(int $offset): int
{
return (int) floor($offset / self::BITS_IN_BYTE);
}
Expand All @@ -197,15 +196,15 @@ private function offsetToByte($offset)
* @param int $offset
* @return int
*/
private function finalBitPos($offset)
private function finalBitPos(int $offset): int
{
return (int) pow(2, $offset % self::BITS_IN_BYTE);
return 2 ** ($offset % self::BITS_IN_BYTE);
}

/**
* @return array
* @return array{len: int, arr: string}
*/
public function jsonSerialize()
public function jsonSerialize(): array
{
return [
'len' => $this->length,
Expand Down
28 changes: 14 additions & 14 deletions src/BloomFilter.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,33 +13,33 @@
*/
class BloomFilter implements JsonSerializable
{
const HASH_ALGO = 'sha1';
public const HASH_ALGO = 'sha1';

/**
* @var BitArray
*/
private $ba;
private BitArray $ba;

/**
* @var HasherList
*/
private $hashers;
private HasherList $hashers;

/**
* @param array $data
* @return BloomFilter
* @return static
*/
public static function initFromJson(array $data)
public static function initFromJson(array $data): static
{
return new static(BitArray::initFromJson($data['bit_array']), HasherList::initFromJson($data['hashers']));
}

/**
* @param int $approxSize
* @param float $falsePosProb
* @return BloomFilter
* @return static
*/
public static function init($approxSize, $falsePosProb)
public static function init(int $approxSize, float $falsePosProb): static
{
$baSize = self::optimalBitArraySize($approxSize, $falsePosProb);
$ba = BitArray::init($baSize);
Expand All @@ -55,17 +55,17 @@ public static function init($approxSize, $falsePosProb)
* @param float $falsePositiveProbability
* @return int
*/
private static function optimalBitArraySize($approxSetSize, $falsePositiveProbability)
private static function optimalBitArraySize(int $approxSetSize, float $falsePositiveProbability): int
{
return (int) round((($approxSetSize * log($falsePositiveProbability)) / pow(log(2), 2)) * -1);
return (int) round((($approxSetSize * log($falsePositiveProbability)) / (log(2) ** 2)) * -1);
}

/**
* @param int $approxSetSize
* @param int $bitArraySize
* @return int
*/
private static function optimalHasherCount($approxSetSize, $bitArraySize)
private static function optimalHasherCount(int $approxSetSize, int $bitArraySize): int
{
return (int) round(($bitArraySize / $approxSetSize) * log(2));
}
Expand All @@ -86,7 +86,7 @@ public function __construct(BitArray $ba, HasherList $hashers)
* @param string $item
* @return void
*/
public function add($item)
public function add(string $item): void
{
$vals = $this->hashers->hash($item);
foreach ($vals as $bitLoc) {
Expand All @@ -98,7 +98,7 @@ public function add($item)
* @param string $item
* @return bool
*/
public function exists($item)
public function exists(string $item): bool
{
$exists = true;
$vals = $this->hashers->hash($item);
Expand All @@ -112,9 +112,9 @@ public function exists($item)
}

/**
* @return array
* @return array{bit_array: BitArray, hashers: HasherList}
*/
public function jsonSerialize()
public function jsonSerialize(): array
{
return [
'bit_array' => $this->ba,
Expand Down
20 changes: 10 additions & 10 deletions src/HasherList.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,22 +12,22 @@

class HasherList implements JsonSerializable
{
private $algo;
private $count;
private $maxResult;
private string $algo;
private int $count;
private int $maxResult;

/**
* @param array $data The result of json_decode()ing a json_encode()ed
* instance of this class. Note to always decode with the second
* argument as true.
* @return HasherList
* @return static
*/
public static function initFromJson(array $data)
public static function initFromJson(array $data): static
{
return new static($data['algo'], $data['count'], $data['max']);
}

private static function hashValidation($algo, $maxResult)
private static function hashValidation($algo, $maxResult): void
{
$testHash = @hash_hmac($algo, 'test', 'key', true);

Expand All @@ -41,7 +41,7 @@ private static function hashValidation($algo, $maxResult)
* @param int $count
* @param int $maxResult
*/
public function __construct($algo, $count, $maxResult)
public function __construct(string $algo, int $count, int $maxResult)
{
if ($maxResult <= 0) {
throw new RangeException("Your maxResult value must be an integer greater than 0");
Expand All @@ -61,7 +61,7 @@ public function __construct($algo, $count, $maxResult)
* @param string $value
* @return int[] An array of $this->count ints that are between 0 and $this->maxResult
*/
public function hash($value)
public function hash(string $value): array
{
$returns = [];
for ($i = 0; $i < $this->count; $i++) {
Expand All @@ -87,9 +87,9 @@ public function hash($value)
}

/**
* @return array
* @return array{algo: string, count: int, max: int}
*/
public function jsonSerialize()
public function jsonSerialize(): array
{
return [
'algo' => $this->algo,
Expand Down
3 changes: 2 additions & 1 deletion tests/src/BitArrayTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
use PHPUnit\Framework\TestCase;
use RangeException;
use UnexpectedValueException;
use TypeError;

class BitArrayTest extends TestCase
{
Expand Down Expand Up @@ -42,7 +43,7 @@ public function testThrowErrorIfBitArrayInitializedWithNegativeLength()
*/
public function testThrowErrorIfBitArrayConstrutectedWithNonIntegerLength()
{
$this->expectException(UnexpectedValueException::class);
$this->expectException(TypeError::class);
BitArray::init('big');
}

Expand Down
4 changes: 2 additions & 2 deletions tests/src/HasherListTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

use PHPUnit\Framework\TestCase;
use RangeException;
use RuntimeException;
use ValueError;

class HasherListTest extends TestCase
{
Expand Down Expand Up @@ -38,7 +38,7 @@ public function testHasherListFailsWhenNegativeCount()
*/
public function testInvalidHashAlgo()
{
$this->expectException(RuntimeException::class);
$this->expectException(ValueError::class);
new HasherList('this-is-not-valid', 3, 200);
}

Expand Down