How to declare relation between properties (enum and nullable field) #10471
-
Say i have an enum and a nullable property. How can i tell phpstan to expect the nullable property to be not null depending on the value of the enum? <?php declare(strict_types = 1);
enum Type
{
case FOO_IS_NULL;
case FOO_IS_STRING;
}
final readonly class FooHolder
{
private function __construct(
public Type $type,
public ?string $foo
) {
if ($this->type === Type::FOO_IS_STRING && $this->foo === null) {
throw new \InvalidArgumentException('The foo must be set if the type is string.', 1695118377);
}
}
public static function createEmpty(): self
{
return new self(Type::FOO_IS_NULL, null);
}
public static function createFromString(string $value): self
{
return new self(Type::FOO_IS_STRING, $value);
}
}
$foo1 = FooHolder::createFromString('hi');
assert($foo1->type === Type::FOO_IS_STRING);
assert(is_string($foo1->foo));
$foo2 = FooHolder::createEmpty();
function fooMe(FooHolder $afoo): void
{
if ($afoo->type === Type::FOO_IS_NULL) {
// how to teach phpstan this relation? Foo should be null. And this should not raise an Error.
// assert($afoo->foo === null);
someFunctionThatOnlyAcceptsNull($afoo->foo);
}
if ($afoo->type === Type::FOO_IS_STRING) {
// how to teach phpstan this relation? Foo should be string. And this should not raise an Error.
// assert(is_string($afoo->foo));
someFunctionThatOnlyAcceptsString($afoo->foo);
}
}
function someFunctionThatOnlyAcceptsNull(null $variable): void {}
function someFunctionThatOnlyAcceptsString(string $variable): void {}
fooMe($foo1);
fooMe($foo2); I know that for methods one can leverage A real world usecase can be found here: The NodeName must be set if the Node's classification is tethered. What do you say? :D |
Beta Was this translation helpful? Give feedback.
Replies: 1 comment 5 replies
-
Please reproduce this on phpstan.org/try and tell us what the expected output is as opposed to the actual PHPStan output. |
Beta Was this translation helpful? Give feedback.
No you can't express this with the current type system.
If I were you I'd choose a different object design. Usage of nullable or optional parameters is usually a code smell. You should have separate
EmptyHolder
andStringHolder
classes.