不同对象的 HackLang 类型

HackLang type for different objects

假设我有允许代理不同适配器实例的静态连接器:

$m = Connector::take('mcrouter');
$db = Connector::take('production_database');

连接器必须在运行时初始化和处理连接:

protected $connection;
abstract protected function openConnection($config);

适配器内部某处:

$this->connection = $this->openConnection($config);

连接是一个对象,可以是 Memcached、MySQLi 等的实例或 NULL。 所以从逻辑上讲我想这样做:

protected ?object $connection;
abstract protected function openConnection($config):?object;

但同时connection并不是"object"的实例,而是Memcached的实例,结果是:

Catchable fatal error: Hack type error: Invalid assignment

在这种情况下唯一可行的解​​决方案是根本不定义类型。 通用对象的定义有什么技巧吗?

Hack 中的通用类型是您省略类型注释时得到的;它与一切兼容。 object 不是类型检查器已知的类型,因此它假定您在某处有一个 class object

The connection is an object and could be an instance of Memcached, MySQLi etc. or NULL.

执行此操作的正确方法是定义一个由这两个对象实现的接口,并将该接口用作此处的类型。

拥有通用对象类型不会向类型检查器提供任何信息;它仍然不知道在该对象上调用哪些方法是有效的。该接口为类型检查器提供了该信息。

请注意,"what methods are safe to call when" 是在您的应用程序中隐式编码的东西——代码通过一些外部方式知道何时可以安全地为 Memcached、MySQLi 等调用某些方法,否则您的代码将无法工作! Hack 的类型系统,以及一般的类型系统,只是强制你明确这一点。

顺便说一句,你真的不应该把你的类型错误当作来自 HHVM 的致命错误;这是不得已的检查。直接尝试 运行 hh_client 检查器,甚至可能在您的 IDE 中显示其结果;它将为您提供更快的迭代周期,以及比 HHVM 提供的更多信息。