Comparing Data Using FFI
Learn how to compare data using FFI.
It’s important to keep in mind that when we create a C-language data structure using the FFI extension, it exists outside of our PHP application. PHP can interact with the C data to a certain extent. However, for comparison purposes, it’s best to use FFI::memcmp()
, as native PHP functions might return inconsistent results.
The two comparison functions available in the FFI extension are summarized here in the following table.
Summary of FFI Class Comparison Methods
FFI Method | Returns | Notes |
|
| Returns |
|
| Operates in much the same manner as the PHP |
FFI::isNull()
can be used to determine whether or not the FFI\CData
instance is NULL
. What is more interesting is FFI::memcmp()
. Although this function operates in the same manner as the spaceship operator (<=>
), it accepts a third argument that represents how many bytes we wish to include in the comparison. The following example illustrates this usage:
<?php// Create native C data types using FFI$a = FFI::new("char[6]"); // Array of 6 characters$b = FFI::new("char[6]");$c = FFI::new("char[6]");$d = FFI::new("char[6]");// Function to populate the given C data array with values$populate = function ($cdata, $start, $offset, $num) {// Populate with alpha charsfor ($x = 0; $x < $num; $x++) {$cdata[$x + $offset] = chr($x + $offset + $start); // Assign character values to the array}return $cdata;};// Populate the arrays with values$a = $populate($a, 65, 0, 6); // 'A' to 'F'$b = $populate($b, 65, 0, 3); // 'A' to 'C'$b = $populate($b, 85, 3, 3); // 'U' to 'W'$c = $populate($c, 71, 0, 6); // 'G' to 'L'$d = $populate($d, 71, 0, 6); // 'G' to 'L'// Display the contents of the arrays$patt = "%2s : %6s\n";printf($patt, '$a', FFI::string($a, 6));printf($patt, '$b', FFI::string($b, 6));printf($patt, '$c', FFI::string($c, 6));printf($patt, '$d', FFI::string($d, 6));/*$a : ABCDEF$b : ABCUVW$c : GHIJKL$d : GHIJKL*/// Note: The following code snippets are commented out because they will throw fatal errors or exceptions due to incompatible types// Attempt to compare arrays using PHP <=>// var_dump($a <=> $b);// PHP Fatal error: Uncaught FFI\Exception: Comparison of incompatible C types// Attempt to compare arrays using PHP strcmp()// var_dump(strcmp($a,$b));// PHP Fatal error: Uncaught TypeError: strcmp(): Argument #1 ($string1) must be of type string// Compare arrays using FFI::memcmp()echo "\nUsing FFI::memcmp()\n";$p = "%20s : %2d\n";printf($p, 'memcmp($a, $b, 6)', FFI::memcmp($a, $b, 6));printf($p, 'memcmp($c, $a, 6)', FFI::memcmp($c, $a, 6));printf($p, 'memcmp($c, $d, 6)', FFI::memcmp($c, $d, 6));// Compare arrays using FFI::memcmp(), but not the full length of the arraysecho "\nUsing FFI::memcmp() but not full length\n";printf($p, 'memcmp($a, $b, 3)', FFI::memcmp($a, $b, 3));?>
Let’s get into the code.
Lines 3–6: We first define a set of four variables representing
FFI\CData
instances that can contain up to six characters and populate the instances with sample data.Lines 9–15: Recall that the C language treats character data as an array, so we can’t just directly assign a string, even if using the
cdata
property. Accordingly, we need to define an anonymous function that populates the instances with ...