Reputation: 4020
I want to make a type-inferring linter for a subset of PHP, but am unsure about how much type information you can get out of it without having to enforce phpdoc annotations or similar. Consider this example:
function a() {
b(10); // This is wrong, but we don't know the type of b()
}
function b($c) {
print($c . " hallo"); // Only allow concatenations with strings
}
Without the in OCaml present and
for mutual recursion, things have to be defined in order of use. The way to get around it is to make a two-stage type-checker, where the first stage checks interfaces, but type-inferring needs to go through the body of the functions.
One way to get around this is to enforce phpdoc docblocks:
function a() {
b(10); // Type error: b() expects a string
}
/**
* @param string $c
*/
function b($c) {
print($c . " hallo");
}
Enforcing docblocks to be used in type-checking feels... wrong. Is there any way around this? Of course the scalar type-hints v5, using declare(strict_types=1)
, would allow scalar type-hints in function signatures, but that's too far into the future.
Edit: I'm stupid, b()
could of course be inferred from it's usage in a()
, so we would have:
function a() {
b(10); // b() inferred to int -> void
}
function b($c) {
print($c . " hallo"); // Wrong, $c used as a string
}
Upvotes: 3
Views: 775
Reputation: 2586
You could create classes that represent the scalar values you want to type hint.
class String {
protected $string;
public function __construct($value) {
if (!is_string($value)) {
throw new Exception('Not a string');
}
$this->string = $value;
}
public function __toString() {
return $this->string;
}
}
Then in your function declaration:
function b(String $c) {
...
}
b(new String('Some String'));
Upvotes: 3