I'm not sure if "the opposite" would be equivalent to adding 128 to each component - that would make black come out mid-grey, and white into a grey one tick darker. I think you mean to subtract each component from 255.
Does the string $hex have the # still attached, or not?
If so, a str_replace will get rid of it for the moment.
$rgb = hexdec($hex);
$rgb ^= 0xffffff;
$hex = substr('000000'.dechex($rgb), -6);
and then put the # back on the beginning again.
OR:
$hex = strtr('0123456789ABCDEF', 'FEDCBA9876543210', strtoupper($hex));
'course, if you do want to add 0x80 and wrap;
$rgb = hexdec($hex);
$red = ((($rgb>>16)&0xff)+0x80)&0xff;
$green = ((($rgb>>8)&0xff)+0x80)&0xff;
$blue = (($rgb&0xff)+0x80)&0xff;
$hex = sprintf('%02X%02X%02X', $red, $green, $blue);
OR
$hex = $hex{0} . strtr('0123456789ABCDEF', 'FEDCBA9876543210', strtoupper($hex{1}))
$hex{2} . strtr('0123456789ABCDEF', 'FEDCBA9876543210', strtoupper($hex{3}))
$hex{4} . strtr('0123456789ABCDEF', 'FEDCBA9876543210', strtoupper($hex{5}));
There are of course other ways to do either task.