Design patterns: apply valuables (written strictly) in PHP

What is the best way to prevent erroneous states in an object? This is the source of my question.

Basically, my curiosity started with the intention of not letting a class exist with incorrect values. Prevent programmers from making errors in implementations and class extensions.

I did not want a class to even bother having to deal with an incorrect value. I just wanted it not to start if an incorrect value of a given state or type was passed.

I work a lot with chain types, due to a demand for legacy code. For this reason I find it interesting to work with "valuable objects". That apparently is the main design idea. I tried to find something with a puny letter (another new term I just discovered).

So below I have the first example. The scenario is: a class needs a type and instead invokes a string & # 39; type_x & # 39; invokes a class and this class resolves the value if it is valid. This class is what we will see next.

/ **
* StringlyTypeSecondOption
* /
StringlyTypeFirstOption class
{
type $ private;

public static function type_1 ()
{
returns new self (& # 39; type_1 & # 39;);
}

public static function type_2 ()
{
returns new self (& # 39; type_2 & # 39;);
}

private function __construct (string $ type)
{
$ this-> type = $ type;
}

public function __toString ()
{
returns $ this-> type;
}
}

echo StringlyTypeFirstOption :: type_2 (); // here is OK

echo StringlyTypeFirstOption :: type_3 (); // Here we have an error because the type_3 does not exist

This is a very good example because we have no exception or verification logic. It's oop on your own. And I think it's good.

And now we have the second example. It will provide a solution for the same problem that I proposed.

StringlyTypeSecondOption class
{
type $ private;

const TYPE1 = & # 39; type_1 & # 39 ;;
const TYPE2 = & # 39; type_2 & # 39 ;;

private const ALLOWED_TYPES = [StringlyTypeSecondOption::TYPE1, StringlyTypeSecondOption::TYPE2];

static public function of factory ($ type)
{
if (! in_array ($ type, StringlyTypeSecondOption :: ALLOWED_TYPES, true)) {
throw a new exception ("Invalid type: {$ type}");
}

return new self ($ type);
}

private function __construct (string $ type)
{
$ this-> type = $ type;
}

public function __toString ()
{
returns $ this-> type;
}
}

echo StringlyTypeSecondOption :: factory (& # 39; type_2 & # 39;); // here is OK

echo StringlyTypeSecondOption :: factory (& # 39; type_3 & # 39;); // Here we have an exception because the type_3 does not exist

It is also a very good example, but I already have some logic and it is not as pure as the first one. But it solves the problem like an amulet too.

Both considerations have strengths and weaknesses (I think).
But if there is a consolidated design that corrects the allowed values ​​for a state of a class, what is its name, how to implement it, and what is the best designed and beautiful strategy to avoid an invalid value in an object?

I think this is more a discussion about an exact solution. If this was not the right place, I ask the moderators to direct me to a better channel.

Thanks in advance!