I took it myself :)
Link to the tester (there you can download the class and see the truth tables), listing the main operators for future generations:
define('TRUE3', 1); define('NULL3', 0); define('FALSE3', -1); function l3validate(&$arg) { if ($arg !== FALSE3 and $arg !== NULL3 and $arg !== TRUE3) { $arg = NULL3; return FALSE3; } return TRUE3; } function l3not($a) { // НЕ, инверсия l3validate($a); if ($a === TRUE3) return FALSE3; if ($a === FALSE3) return TRUE3; return NULL3; } function l3and($a, $b) { // И, конъюнкция l3validate($a); l3validate($b); if ($a === TRUE3 and $b === TRUE3) return TRUE3; if ($a === FALSE3 or $b === FALSE3) return FALSE3; return NULL3; } function l3andm() { // И, несколько аргументов $result = TRUE3; foreach (func_get_args() as $arg) { l3validate($arg); if ($arg === NULL3) $result = NULL3; if ($arg === FALSE3) return FALSE3; } return $result; } function l3or($a, $b) { // ИЛИ, дизъюнкция l3validate($a); l3validate($b); if ($a === $b and $a === FALSE3) return FALSE3; if ($a === TRUE3 or $b === TRUE3) return TRUE3; return NULL3; } function l3orm() { // ИЛИ, несколько аргументов $result = FALSE3; foreach (func_get_args() as $arg) { l3validate($arg); if ($arg === NULL3) $result = NULL3; if ($arg === TRUE3) return TRUE3; } return $result; } function l3xor($a, $b) { // ЛИБО ... ЛИБО ..., строгая дизъюнкция l3validate($a); l3validate($b); if ($a === $b and $a !== NULL3) return FALSE3; if (($a === TRUE3 and $b === FALSE3) or ($a === FALSE3 and $b === TRUE3)) return TRUE3; return NULL3; } function l3imp($a, $b) { // ->, импликация l3validate($a); l3validate($b); if ($a === FALSE3 or $b === TRUE3) return TRUE3; if ($a === TRUE3 and $b === FALSE3) return FALSE3; return NULL3; } function l3bimp($a, $b) { // <-, обратная импликация l3validate($a); l3validate($b); if ($a === TRUE3 or $b === FALSE3) return TRUE3; if ($a === FALSE3 and $b === TRUE3) return FALSE3; return NULL3; } function l3eq($a, $b) { // =, эквивалентность l3validate($a); l3validate($b); if ($a === NULL3 or $b === NULL3) return NULL3; if ($a === $b) return TRUE3; return FALSE3; }
PS: Especially for @Dex: the discussion of terms , yet yours took) But still look at the discussion, it turned out to be difficult and purely aesthetic. Even the variant "trivalent" would be true lexical%)
UPDATE: Corrected "ideologically", any "unidentified" turns into NULL3. If you want to be more tolerant, the class has a cast method that rounds to the nearest logical one.