For the purposes of this proposal, the existing semantics should be followed, under which isset(), and consequently ??, has no interaction with constant lookup.
Suppressing errors would provide a direct counterpart for tryFrom: State::{$stateName} ?? State::Default. I don't necessarily think that's something you should do but without adjusting interaction with ?? the result is only slightly better than the status quo, if at all:
// PHP 8.2 $fqn = State::class . '::' . $stateName; $result = defined($fqn) ? constant($fqn) : State::Default; // Without ?? $fqn = State::class . '::' . $stateName; $result = defined($fqn) ? State::{$stateName} : State::Default; // WIth ?? $result = State::{$stateName} ?? State::Default;
Number 3 sounds undesirable at first but given that ?? (and isset) only suppress errors in the root chain of which :: is not usually a part of it might be a viable option. (e.g. $foo->bar->{$baz}[$qux] ?? null will suppress undeclared $foo, undeclared ->bar but not undeclared $baz or $qux). :: in the root chain of ?? is uncommon because class constants historically could not contain objects on which you'd use -> (which does interact with ??) and exactly because it doesn't interact with ??, so there was no point in putting it there. One imaginable case is Foo::CONST_THAT_MGIHT_BE_NULL ?? 'foo' where the constant is overridden.
That said, I'm ok with starting with option 1. Relaxing it will always be easier than the opposite.