Skip to content
This repository was archived by the owner on Nov 14, 2025. It is now read-only.

Commit 772bd34

Browse files
committed
Make FFI injection optional
By automagically finding and processing header files, or using preload scope, when an FFI hasn’t been supplied.
1 parent 91d289c commit 772bd34

File tree

8 files changed

+145
-85
lines changed

8 files changed

+145
-85
lines changed

README.md

Lines changed: 66 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -39,14 +39,69 @@ Use [Composer](https://getcomposer.org) to install this library (note the [Requi
3939
composer require awesomized/crc-fast
4040
```
4141

42+
## Configuration
43+
[FFI ini](https://www.php.net/manual/en/ffi.configuration.php) settings must be configured properly for your environment.
44+
45+
Optionally, opcache [preloading](https://www.php.net/manual/en/ffi.examples-complete.php) can also be used as an optimization.
4246

4347
## Usage
4448

4549
Examples are for `CRC-64/NVME`, but `CRC-32/ISO-HDLC` is nearly identical, just in a different namespace (`Awesomized\Checksums\Crc32\IsoHdlc`).
4650

47-
### Creating the CRC-64/NVME FFI object
51+
Make sure you have the correct header file(s) for your CPU architecture and OS in [/include](include) for your project (e.g., [include/crc64nvme-aarch64-linux.h](include/crc64nvme-aarch64-linux.h)) which points to the correct shared library for your environment.
52+
53+
### Calculate CRC-64/NVME checksums:
54+
55+
```php
56+
use Awesomized\Checksums\Crc64\Nvme;
57+
58+
// calculate the checksum of a string
59+
$checksum = Nvme\Computer::calculate(
60+
string: 'hello, world!'
61+
// optionally inject a different FFI here
62+
); // f8046e40c403f1d0
63+
64+
// calculate the checksum of a file, which will chunk through the file optimally,
65+
// limiting RAM usage and maximizing throughput
66+
$checksum = Nvme\Computer::calculateFile(
67+
filename: 'path/to/hello-world'
68+
// optionally inject a different FFI here
69+
); // f8046e40c403f1d0
70+
```
71+
72+
### Calculate CRC-64/NVME checksums with a Digest for intermittent / streaming / etc workloads:
73+
74+
```php
75+
use Awesomized\Checksums\Crc64\Nvme;
4876

49-
A [helper FFI Class](src/Ffi.php) is provided, which supplies many ways to easily create an FFI object for the [crc64fast-nvme](https://github.com/awesomized/crc64fast-nvme) shared library:
77+
$crc64Digest = new Nvme\Computer(
78+
// optionally inject a different FFI here
79+
);
80+
81+
// write some data to the digest
82+
$crc64Digest->write('hello,');
83+
84+
// write some more data to the digest
85+
$crc64Digest->write(' world!');
86+
87+
// calculate the entire digest
88+
$checksum = $crc64Digest->sum(); // f8046e40c403f1d0
89+
```
90+
91+
### Creating an CRC-64/NVME FFI object
92+
93+
Alternatively, you can create an FFI object directly, and inject it into the `Computer` classes:
94+
95+
#### - Via automagic loading via preloading and/or header files (recommended for most use cases):
96+
97+
```php
98+
use Awesomized\Checksums\Crc64\Nvme;
99+
100+
// uses the opcache preloaded shared library, if possible, otherwise uses the header file
101+
$crc64Fast = Nvme\Ffi::fromAuto();
102+
```
103+
104+
Alternatively, a [helper FFI Class](src/Ffi.php) is provided, which supplies many ways to easily create an FFI object for the [crc64fast-nvme](https://github.com/awesomized/crc64fast-nvme) shared library:
50105

51106
#### - Via [preloaded](https://www.php.net/manual/en/ffi.examples-complete.php) shared library (recommended for any long-running workloads, such as web requests):
52107

@@ -67,7 +122,7 @@ use Awesomized\Checksums\Crc64\Nvme;
67122

68123
// uses the FFI_LIB and FFI_SCOPE definitions in the header file
69124
$crc64Fast = Nvme\Ffi::fromHeaderFile(
70-
headerFile: 'path/to/crc64fast_nvme.h', // optional, can likely be inferred from the OS
125+
headerFile: 'path/to/crc64nvme-ARCH-OS.h', // optional, can likely be inferred from the OS
71126
);
72127
```
73128

@@ -86,49 +141,7 @@ $crc64Fast = Nvme\Ffi::fromCode(
86141
library: 'libcrc64fast_nvme.so',
87142
);
88143
```
89-
### Using the CRC-64/NVME FFI object
90-
91-
#### Calculate CRC-64/NVME checksums:
92-
93-
```php
94-
use Awesomized\Checksums\Crc64\Nvme;
95-
96-
/** @var \FFI $crc64Fast */
97-
98-
// calculate the checksum of a string
99-
$checksum = Nvme\Computer::calculate(
100-
ffi: $crc64Fast,
101-
string: 'hello, world!'
102-
); // f8046e40c403f1d0
103-
104-
// calculate the checksum of a file, which will chunk through the file optimally,
105-
// limiting RAM usage and maximizing throughput
106-
$checksum = Nvme\Computer::calculateFile(
107-
ffi: $crc64Fast,
108-
filename: 'path/to/hello-world'
109-
); // f8046e40c403f1d0
110-
```
111-
112-
#### Calculate CRC-64/NVME checksums with a Digest for intermittent / streaming / etc workloads:
113-
114-
```php
115-
use Awesomized\Checksums\Crc64\Nvme;
116-
117-
/** @var \FFI $crc64FastNvme */
118-
119-
$crc64Digest = new Nvme\Computer(
120-
crc64Nvme: $crc64FastNvme,
121-
);
122-
123-
// write some data to the digest
124-
$crc64Digest->write('hello,');
125-
126-
// write some more data to the digest
127-
$crc64Digest->write(' world!');
128144

129-
// calculate the entire digest
130-
$checksum = $crc64Digest->sum(); // f8046e40c403f1d0
131-
```
132145

133146
## Examples
134147

@@ -140,16 +153,17 @@ This project uses [SemVer](https://semver.org), and has extensive coding standar
140153

141154
Examples:
142155

143-
#### Building the shared `crc64fast-nvme` Rust library for local development and testing
156+
#### Build, validate, and test everything:
144157
```bash
145-
make build
146-
```
147-
#### Validating PHP code
158+
make
159+
```
160+
161+
#### Building the shared Rust libraries for local development and testing
148162
```bash
149-
make validate
150-
```
163+
make build
164+
```
151165

152-
#### Repairing PHP code quality issues
166+
#### Repairing PHP coding standards issues
153167
```bash
154168
make repair
155169
```

src/ChecksumTrait.php

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,13 @@
1212
trait ChecksumTrait
1313
{
1414
public static function calculate(
15-
FFI $ffi,
1615
string $string,
16+
?FFI $ffi = null,
1717
): string {
18+
if (null === $ffi) {
19+
$ffi = self::getFfi();
20+
}
21+
1822
return (new self($ffi))
1923
->write(
2024
string: $string,
@@ -23,10 +27,14 @@ public static function calculate(
2327
}
2428

2529
public static function calculateFile(
26-
FFI $ffi,
2730
string $filename,
2831
int $readChunkSize = self::READ_CHUNK_SIZE_DEFAULT,
32+
?FFI $ffi = null,
2933
): string {
34+
if (null === $ffi) {
35+
$ffi = self::getFfi();
36+
}
37+
3038
$handle = fopen(
3139
filename: $filename,
3240
mode: 'rb',
@@ -62,4 +70,6 @@ public static function calculateFile(
6270

6371
return $computer->sum();
6472
}
73+
74+
abstract protected static function getFfi(): FFI;
6575
}

src/Crc32/IsoHdlc/Computer.php

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,24 +16,30 @@ final class Computer implements Checksums\CrcInterface
1616
{
1717
use Checksums\ChecksumTrait;
1818

19-
private FFI\CData $hasherHandle;
19+
private readonly FFI $crc32IsoHdlc;
20+
21+
private readonly FFI\CData $hasherHandle;
22+
23+
private static ?FFI $ffiAuto = null;
2024

2125
/**
22-
* @param FFI $crc32IsoHdlc The FFI instance for the CRC-32 IEEE library.
26+
* @param FFI|null $crc32IsoHdlc The FFI instance for the CRC-32 IEEE library.
2327
*
2428
* @throws \InvalidArgumentException
2529
*/
2630
public function __construct(
27-
private readonly FFI $crc32IsoHdlc,
31+
?FFI $crc32IsoHdlc = null,
2832
) {
33+
$this->crc32IsoHdlc = $crc32IsoHdlc ?? self::getFfi();
34+
2935
try {
3036
/**
31-
* @var FFI\CData $digestHandle
37+
* @var FFI\CData $hasherHandle
3238
*
3339
* @psalm-suppress UndefinedMethod - from FFI, we'll catch the Exception if the method is missing
3440
*/
3541
// @phpstan-ignore-next-line
36-
$digestHandle = $this->crc32IsoHdlc->hasher_new();
42+
$hasherHandle = $this->crc32IsoHdlc->hasher_new();
3743
} catch (FFI\Exception $e) {
3844
throw new \InvalidArgumentException(
3945
message: 'Could not create a new Hasher handle.'
@@ -42,7 +48,7 @@ public function __construct(
4248
);
4349
}
4450

45-
$this->hasherHandle = $digestHandle;
51+
$this->hasherHandle = $hasherHandle;
4652
}
4753

4854
public function write(
@@ -92,4 +98,16 @@ public function sum(): string
9298
$crc32,
9399
);
94100
}
101+
102+
/**
103+
* @throws \InvalidArgumentException
104+
*/
105+
protected static function getFfi(): FFI
106+
{
107+
if (null !== self::$ffiAuto) {
108+
return self::$ffiAuto;
109+
}
110+
111+
return self::$ffiAuto = Checksums\Crc32\IsoHdlc\Ffi::fromAuto();
112+
}
95113
}

src/Crc64/Nvme/Computer.php

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,16 +18,22 @@ final class Computer implements Checksums\CrcInterface
1818
{
1919
use Checksums\ChecksumTrait;
2020

21-
private FFI\CData $digestHandle;
21+
private readonly FFI $crc64Nvme;
22+
23+
private readonly FFI\CData $digestHandle;
24+
25+
private static ?FFI $ffiAuto = null;
2226

2327
/**
2428
* @param FFI $crc64Nvme The FFI instance for the CRC-64 NVMe library.
2529
*
2630
* @throws \InvalidArgumentException
2731
*/
2832
public function __construct(
29-
private readonly FFI $crc64Nvme,
33+
?FFI $crc64Nvme = null,
3034
) {
35+
$this->crc64Nvme = $crc64Nvme ?? self::getFfi();
36+
3137
try {
3238
/**
3339
* @var FFI\CData $digestHandle
@@ -94,4 +100,16 @@ public function sum(): string
94100
$crc64,
95101
);
96102
}
103+
104+
/**
105+
* @throws \InvalidArgumentException
106+
*/
107+
protected static function getFfi(): FFI
108+
{
109+
if (null !== self::$ffiAuto) {
110+
return self::$ffiAuto;
111+
}
112+
113+
return self::$ffiAuto = Checksums\Crc64\Nvme\Ffi::fromAuto();
114+
}
97115
}

src/CrcInterface.php

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,8 @@ interface CrcInterface
2626
/**
2727
* Calculates the CRC checksum for a string.
2828
*
29-
* @param FFI $ffi The FFI instance for the CRC library.
30-
* @param string $string The string to calculate the CRC checksum for.
29+
* @param string $string The string to calculate the CRC checksum for.
30+
* @param FFI|null $ffi The FFI instance for the CRC library.
3131
*
3232
* @return string The calculated CRC checksum as a hexadecimal string (due to signed large int issues in PHP for
3333
* 64-bit results).
@@ -36,17 +36,17 @@ interface CrcInterface
3636
* @throws \RuntimeException
3737
*/
3838
public static function calculate(
39-
FFI $ffi,
4039
string $string,
40+
?FFI $ffi = null,
4141
): string;
4242

4343
/**
4444
* Calculates the CRC checksum for a file.
4545
*
46-
* @param FFI $ffi The FFI instance for the CRC library.
4746
* @param string $filename The file or URL.
4847
* @param int<1, max> $readChunkSize The size of the chunks to read from the file. Adjust as necessary for your
4948
* environment.
49+
* @param FFI|null $ffi The FFI instance for the CRC library.
5050
*
5151
* @return string The calculated CRC checksum as a hexadecimal string (due to signed large int issues in PHP for
5252
* 64-bit results).
@@ -55,9 +55,9 @@ public static function calculate(
5555
* @throws \RuntimeException
5656
*/
5757
public static function calculateFile(
58-
FFI $ffi,
5958
string $filename,
6059
int $readChunkSize = self::READ_CHUNK_SIZE_DEFAULT,
60+
?FFI $ffi = null,
6161
): string;
6262

6363
/**

src/FfiTrait.php

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,20 @@ trait FfiTrait
1717
*/
1818
private static array $ffis = [];
1919

20+
/**
21+
* @throws \InvalidArgumentException
22+
*/
23+
public static function fromAuto(): \FFI
24+
{
25+
try {
26+
return self::fromPreloadScope();
27+
} catch (\Throwable $e) {
28+
// ignore
29+
}
30+
31+
return self::fromHeaderFile();
32+
}
33+
2034
public static function fromCode(
2135
string $code,
2236
?string $library = null,

0 commit comments

Comments
 (0)