0

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

$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;

但同时连接并不是真正的“对象”实例,例如是 Memcached 的实例,结果是:

可捕获的致命错误:黑客类型错误:无效分配

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

4

1 回答 1

1

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

连接是一个对象,可以是 Memcached、MySQLi 等的实例,也可以是 NULL。

正确的做法是定义这两个对象都实现的接口,并使用该接口作为此处的类型。

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

请注意,“什么时候调用什么方法是安全的”是在你的应用程序中隐式编码的——代码通过一些外部方式知道什么时候可以安全地调用 Memcached、MySQLi 等的某些方法,否则你的代码将无法工作!Hack 的类型系统,以及一般的类型系统,只是强迫你明确这一点。

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

于 2015-08-15T15:19:36.730 回答