<?hh
namespace Hack\UserDocumentation\Types\Inference\Examples\LocalVariables;
function foo(): int {
$a = str_shuffle("ABCDEF"); // $a is a string
if (strpos($a, "A") === false) {
$a = 4; // $a is an int
} else {
$a = 2; // $a is an int
}
// Based on the flow of the program, $a is guaranteed to be an int at this
// point, so it is safe to return as an int.
return $a;
}
function run(): void {
var_dump(foo());
}
run();
<?hh
namespace Hack\UserDocumentation\Types\Inference\Examples\Unresolved;
function foo(): arraykey {
$a = str_shuffle("ABCDEF"); // $a is a string
if (strpos($a, "A") === false) {
$a = 4; // $a is an int
} else {
$a = "Hello"; // $a is string
}
// Based on the flow of the program, at this point $a is either an int or
// string. You have an unresolved type; or, to look at it another way, you
// the union of an int and string. So you can only perform operations that
// can be performed on both of those types.
var_dump($a + 20); // Nope. This isn't good for a string
$arr = array();
$arr[$a] = 4; // Fine. Since an array key can be an int or string
// arraykey is fine since it is either an int or string
return $a;
}
var_dump(foo());
<?hh
namespace Hack\UserDocumentation\Types\Inference\Examples\Props;
class A {
protected ?int $x;
public function __construct() {
$this->x = 3;
}
public function setPropToNull(): void {
$this->x = null;
}
public function checkPropBad(): void {
// Typechecker knows $x isn't null after this validates
if ($this->x !== null) {
// We know that this doesn't call A::setPropToNull(), but the typechecker
// does not since inferences is local to the function.
// Commenting out so typechecker passes on all examples
does_not_set_to_null();
// We know that $x is still not null, but the typechecker doesn't
take_an_int($this->x);
}
}
public function checkPropGood(): void {
// Typechecker knows $x isn't null after this validates
if ($this->x !== null) {
// We know that this doesn't call A::setPropToNull(), but the typechecker
// does not since inferences is local to the function.
does_not_set_to_null();
// Use this invariant to tell the typechecker what's happening.
invariant($this->x !== null, "We know it is not null");
// We know that $x is still not null, and now the typechecker does too
// Could also have used a local variable here saying:
// $local = $this->x;
// takes_an_int($local);
take_an_int($this->x);
}
}
}
function does_not_set_to_null(): void {
echo "I don't set A::x to null" . PHP_EOL;
}
function take_an_int(int $x): void {
var_dump($x);
}
function run(): void {
$a = new A();
$a->checkPropBad();
$a->checkPropGood();
}
run();
Output
I don't set A::x to null
int(3)
I don't set A::x to null
int(3)
更多建議: