array_diff($a, $b, ...) keeps the elements of $a found in none of the other arrays, and array_intersect() those found in all, both keeping $a's keys. The sixteen variants share one grammar: _key compares keys, _assoc keys and values, and a u supplies your own callback, before the verb for values (array_udiff) or before key/assoc for keys (array_diff_ukey).
<?php
$catalog = ['BK-101' => 'Dune', 'BK-205' => 'Emma', 'BK-300' => 'Ariel', 'BK-410' => 'Odes'];
$cart = ['BK-205' => 'Emma', 'BK-300' => 'Ariel 2e', 'BK-999' => 'Dune'];
echo json_encode(array_diff($catalog, $cart)), "\n"; // values not in $cart
echo json_encode(array_diff_key($catalog, $cart)), "\n"; // keys not in $cart
echo json_encode(array_intersect_assoc($catalog, $cart)), ' ', // same key and value
json_encode(array_uintersect(['Dune', 'EMMA'], ['emma'], strcasecmp(...))), "\n";
echo json_encode(array_diff([1, '1.0', true, null], ['1'])), ' ', // compared as strings
json_encode(array_values(array_unique([...['sf', 'poetry'], ...['poetry', 'classic']])));{"BK-300":"Ariel","BK-410":"Odes"}
{"BK-101":"Dune","BK-410":"Odes"}
{"BK-205":"Emma"} {"1":"EMMA"}
{"1":"1.0","3":null} ["sf","poetry","classic"]BK-300 survives array_diff() because its title differs. Elements are equal when their string forms match, so 1 and true equal '1', but '1.0' and null (as '') do not. A union of lists is array_unique() over a spread. For large sets, store members as keys (array_flip()) and test with isset(): a hash probe instead of the full scan in_array() makes.