Mastering PHP 8.2: Disjunctive Normal Form Types
OpenClipart Image by ben
As a web developer, keeping up with the latest technology is essential to stay relevant and competitive in the industry. With the release of PHP 8.2, there are new features and improvements that can help you elevate your web development skills. In this article we cover a new feature of PHP 8.2 called disjunctive normal form types and provide you with short code examples to aid your understanding.
Disjunctive Normal Form (DNF)
Disjunctive Normal Form (DNF) is a canonical normal form of a logical formula consisting of a disjunction of conjunctions, or simply an OR of ANDs. It represents a logical formula as the alternation of one or more conjunctions of one or more literals. In PHP 8.2, you can use DNF to simplify complex boolean expressions, making your code more readable and maintainable. Before showing you an example, you first need to understand two other types, introduced in slightly earlier versions of PHP: union and intersection types.
Union Types
In this example, the first argument $data accepts
either an array or a string as a data type. This is
referred to as a union type because it's a union of
array
and
string
. Note that the OR
symbol ("|
") is used to
represent the union. Please note that you're not limited to just
two types. You can add others if appropriate.
function get_row(array|string $data, bool $td = TRUE)
{
$tag = ($td)
? function
($item) { return '' . $item . ''; }
: function
($item) { return '' . $item . ''; };
$html = '';
if (is_string($data)) {
$data =
str_getcsv($data);
} elseif (!is_array($data)) {
$data = [];
}
foreach ($data as $item) $html .=
$tag($item);
$html .= '' . PHP_EOL;
return $html;
}
Intersection Types
The intersection type was introduced in PHP 8.1 and
is mainly useful in OOP. Whereas union types allows you to pass
either of the types specified, the intersection type means that the
object you pass need to match all of the intersecting
types. In this example, the function add_and_get_avg()
requires an object that implements all of these interfaces:
ArrayAccess,
Countable
and
Traversable.
Note that the
AND symbol ("&
") is used
to represent an intersection of types.
function
add_and_get_avg(ArrayAccess&Countable&Traversable $obj,
float $value) : float
{
// ArrayAccess allows object to act as array
$obj[] = $value;
$sum = 0;
// Traversable allows object to be used in a
foreach loop
foreach ($obj as $val) $sum += $val;
// Countable lets you use the count() function
on the object
return $sum / count($obj);
}
Disjunctive Normal Form
OK, now we're ready to talk about DNF. In the code example shown in the section discussing intersection types, you've no doubt recognized that a simple array can easily handle the logic inside the function. However, prior to PHP 8.2 you would need to remove the type hints entirely in order to allow objects that implement those three interfaces and also allow arrays! As of PHP 8.2, you can use parentheses to subgroup types and gang them together in whatever form is appropriate.
In this example, we can make a couple of simple modifications to the function signature to achieve the desired result:
function add_and_get_avg((ArrayAccess&Countable&Traversable)|array
&$obj, float
$value) : float
We placed paratheses around the intersection type, and placed
the intersection type in union with array
. Note that
we also needed to add an ampersand ("&
") in front of $obj
so that the array can be passed
by reference. This has no effect on objects as they are already
implicitly passed by reference.
In the runner code, this now works:
$arr = [1,2];
echo "Current Avg: " . add_and_get_avg($arr, 3) . "\n";
// 2
echo "Current Avg: " . add_and_get_avg($arr, 4) . "\n";
// 2.5
echo "Current Avg: " . add_and_get_avg($arr, 5) . "\n"; //
3