3v4l.org

run code in 500+ PHP versions simultaneously
<?php class X { } class Y { } function foo(X|Y|null $param, string|bool|null $anotherParam) { } class Z extends Y { } class U { } function isCompatibleWithType(string $type, mixed $value): bool { if (gettype($value) === 'object') { return get_class($value) === $type || is_subclass_of($value, $type); } return gettype($value) === $type; } function canAccept(callable $func, int $paramPosition, mixed $paramValue): bool { $r = new \ReflectionFunction($func); $canAccept = false; foreach ($r->getParameters() as $parameter) { if ($parameter->getPosition() !== $paramPosition) { continue; } $type = $parameter->getType(); if ($type instanceof \ReflectionUnionType) { foreach ($type->getTypes() as $t) { if (isCompatibleWithType($t->getName(), $paramValue) || ($t->allowsNull() && is_null($paramValue))) { return true; } } return false; } if ($type instanceof \ReflectionIntersectionType) { foreach ($type->getTypes() as $t) { if (!isCompatibleWithType($t->getName(), $paramValue)) /* intersection types do not support nullables for now */ { return false; } } return true; } return isCompatibleWithType($type->getName(), $paramValue) || ($t->allowsNull() && is_null($paramValue)); } return false; } var_dump(canAccept('foo', 0, null)); var_dump(canAccept('foo', 1, null));

preferences:
22.31 ms | 475 KiB | 4 Q